Commit 80365b98 authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Allow multiple exit policy lines; mostly add support for AP policies


svn:r1905
parent 80be19d9
......@@ -16,9 +16,9 @@ For 0.0.7:
o the keep-trying-to-build-intropoints-always bug.
- *bindaddress
o include the port
- allow multiple of them
o allow multiple of them
- have an allow/deny series for them
- break exitpolicy into multiple config lines
o break exitpolicy into multiple config lines
- have the OP forget routers it hasn't heard about in 24 hours
- rename/rearrange functions for what file they're in
- try to break apart the main clump of functions better.
......
......@@ -195,7 +195,7 @@ static int config_assign(or_options_t *options, struct config_line_t *list) {
config_compare(list, "DebugLogFile", CONFIG_TYPE_STRING, &options->DebugLogFile) ||
config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) ||
config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) ||
config_compare(list, "DirBindAddress", CONFIG_TYPE_STRING, &options->DirBindAddress) ||
config_compare(list, "DirBindAddress", CONFIG_TYPE_LINELIST, &options->DirBindAddress) ||
config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_INT, &options->DirFetchPostPeriod) ||
config_compare(list, "ExitNodes", CONFIG_TYPE_STRING, &options->ExitNodes) ||
......@@ -221,7 +221,7 @@ static int config_assign(or_options_t *options, struct config_line_t *list) {
config_compare(list, "NumCpus", CONFIG_TYPE_INT, &options->NumCpus) ||
config_compare(list, "ORPort", CONFIG_TYPE_INT, &options->ORPort) ||
config_compare(list, "ORBindAddress", CONFIG_TYPE_STRING, &options->ORBindAddress) ||
config_compare(list, "ORBindAddress", CONFIG_TYPE_LINELIST, &options->ORBindAddress) ||
config_compare(list, "PidFile", CONFIG_TYPE_STRING, &options->PidFile) ||
config_compare(list, "PathlenCoinWeight",CONFIG_TYPE_DOUBLE, &options->PathlenCoinWeight) ||
......@@ -233,7 +233,8 @@ static int config_assign(or_options_t *options, struct config_line_t *list) {
config_compare(list, "RendExcludeNodes",CONFIG_TYPE_STRING, &options->RendExcludeNodes) ||
config_compare(list, "SocksPort", CONFIG_TYPE_INT, &options->SocksPort) ||
config_compare(list, "SocksBindAddress",CONFIG_TYPE_STRING,&options->SocksBindAddress) ||
config_compare(list, "SocksBindAddress",CONFIG_TYPE_LINELIST,&options->SocksBindAddress) ||
config_compare(list, "SocksPolicy", CONFIG_TYPE_LINELIST,&options->SocksPolicy) ||
config_compare(list, "TrafficShaping", CONFIG_TYPE_BOOL, &options->TrafficShaping) ||
......@@ -477,14 +478,15 @@ static void free_options(or_options_t *options) {
tor_free(options->ExcludeNodes);
tor_free(options->RendNodes);
tor_free(options->RendExcludeNodes);
tor_free(options->ExitPolicy);
tor_free(options->SocksBindAddress);
tor_free(options->ORBindAddress);
tor_free(options->DirBindAddress);
tor_free(options->RecommendedVersions);
tor_free(options->User);
tor_free(options->Group);
config_free_lines(options->RendConfigLines);
config_free_lines(options->SocksBindAddress);
config_free_lines(options->ORBindAddress);
config_free_lines(options->DirBindAddress);
config_free_lines(options->ExitPolicy);
config_free_lines(options->SocksPolicy);
}
/** Set <b>options</b> to hold reasonable defaults for most options. */
......@@ -497,10 +499,11 @@ static void init_options(or_options_t *options) {
options->ExcludeNodes = tor_strdup("");
options->RendNodes = tor_strdup("");
options->RendExcludeNodes = tor_strdup("");
options->ExitPolicy = tor_strdup("");
options->SocksBindAddress = tor_strdup("127.0.0.1");
options->ORBindAddress = tor_strdup("0.0.0.0");
options->DirBindAddress = tor_strdup("0.0.0.0");
options->ExitPolicy = NULL;
options->SocksPolicy = NULL;
options->SocksBindAddress = NULL;
options->ORBindAddress = NULL;
options->DirBindAddress = NULL;
options->RecommendedVersions = NULL;
options->PidFile = NULL; // tor_strdup("tor.pid");
options->DataDirectory = NULL;
......@@ -808,6 +811,57 @@ void config_init_logs(or_options_t *options)
}
}
void
config_parse_exit_policy(struct config_line_t *cfg,
struct exit_policy_t **dest)
{
struct exit_policy_t **nextp;
char *e, *s;
int last=0;
char line[1024];
if (!cfg)
return;
nextp = dest;
while (*nextp)
nextp = &((*nextp)->next);
for (; cfg; cfg = cfg->next) {
s = cfg->value;
for (;;) {
e = strchr(s,',');
if(!e) {
last = 1;
strncpy(line,s,1023);
} else {
memcpy(line,s, ((e-s)<1023)?(e-s):1023);
line[e-s] = 0;
}
line[1023]=0;
log_fn(LOG_DEBUG,"Adding new entry '%s'",line);
*nextp = router_parse_exit_policy_from_string(line);
if(*nextp) {
nextp = &((*nextp)->next);
} else {
log_fn(LOG_WARN,"Malformed exit policy %s; skipping.", line);
}
if (last)
break;
s = e+1;
}
}
}
void exit_policy_free(struct exit_policy_t *p) {
struct exit_policy_t *e;
while (p) {
e = p;
p = p->next;
tor_free(e->string);
tor_free(e);
}
}
/*
Local Variables:
mode:c
......
......@@ -74,6 +74,8 @@ char *conn_state_to_string[][_CONN_TYPE_MAX+1] = {
/********* END VARIABLES ************/
static int connection_create_listener(const char *bindaddress,
uint16_t bindport, int type);
static int connection_init_accepted_conn(connection_t *conn);
static int connection_handle_listener_read(connection_t *conn, int new_type);
static int connection_receiver_bucket_should_increase(connection_t *conn);
......@@ -307,7 +309,7 @@ void connection_expire_held_open(void)
* If <b>bindaddress</b> includes a port, we bind on that port; otherwise, we
* use bindport.
*/
int connection_create_listener(char *bindaddress, uint16_t bindport, int type) {
static int connection_create_listener(const char *bindaddress, uint16_t bindport, int type) {
struct sockaddr_in bindaddr; /* where to bind */
connection_t *conn;
char *hostname, *cp;
......@@ -488,54 +490,64 @@ int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_
return 1;
}
/** If there exists a listener of type <b>type</b> in the connection
* array, mark it for close.
/** If there exist any listeners of type <b>type</b> in the connection
* array, mark them for close.
*/
static void listener_close_if_present(int type) {
connection_t *conn;
connection_t **carray;
int i,n;
tor_assert(type == CONN_TYPE_OR_LISTENER ||
type == CONN_TYPE_AP_LISTENER ||
type == CONN_TYPE_DIR_LISTENER);
conn = connection_get_by_type(type);
if (conn) {
connection_close_immediate(conn);
connection_mark_for_close(conn);
get_connection_array(&carray,&n);
for(i=0;i<n;i++) {
conn = carray[i];
if (conn->type == type && !conn->marked_for_close) {
connection_close_immediate(conn);
connection_mark_for_close(conn);
}
}
}
static int retry_listeners(int type, struct config_line_t *cfg,
int port_option, const char *default_addr)
{
listener_close_if_present(type);
if (port_option) {
if (!cfg) {
if (connection_create_listener(default_addr, (uint16_t) port_option,
type)<0)
return -1;
} else {
for ( ; cfg; cfg = cfg->next) {
if (connection_create_listener(cfg->value, (uint16_t) port_option,
type)<0)
return -1;
}
}
}
return 0;
}
/** Start all connections that should be up but aren't.
* - Connect to all ORs if you're an OR.
* - Relaunch listeners for each port you have open.
*/
int retry_all_connections(void) {
if(options.ORPort) {
router_retry_connections();
}
if(options.ORPort) {
listener_close_if_present(CONN_TYPE_OR_LISTENER);
if(connection_create_listener(options.ORBindAddress,
(uint16_t) options.ORPort,
CONN_TYPE_OR_LISTENER) < 0)
return -1;
}
if(options.DirPort) {
listener_close_if_present(CONN_TYPE_DIR_LISTENER);
if(connection_create_listener(options.DirBindAddress,
(uint16_t) options.DirPort,
CONN_TYPE_DIR_LISTENER) < 0)
return -1;
}
if(options.SocksPort) {
listener_close_if_present(CONN_TYPE_AP_LISTENER);
if(connection_create_listener(options.SocksBindAddress,
(uint16_t) options.SocksPort,
CONN_TYPE_AP_LISTENER) < 0)
return -1;
}
if (retry_listeners(CONN_TYPE_OR_LISTENER, options.ORBindAddress,
options.ORPort, "0.0.0.0")<0)
return -1;
if (retry_listeners(CONN_TYPE_DIR_LISTENER, options.DirBindAddress,
options.DirPort, "0.0.0.0")<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_LISTENER, options.SocksBindAddress,
options.SocksPort, "127.0.0.1")<0)
return -1;
return 0;
}
......
......@@ -13,7 +13,11 @@
extern or_options_t options; /* command-line and config-file options */
extern char *conn_state_to_string[][_CONN_TYPE_MAX+1]; /* from connection.c */
static struct exit_policy_t *socks_policy = NULL;
static int connection_ap_handshake_process_socks(connection_t *conn);
static void parse_socks_policy(void);
static int socks_policy_permits_address(uint32_t addr);
/** Handle new bytes on conn->inbuf, or notification of eof.
*
......@@ -781,6 +785,38 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
conn->socks_request->port, exit->exit_policy);
}
static void parse_socks_policy(void)
{
struct exit_policy_t *n;
if (socks_policy) {
exit_policy_free(socks_policy);
socks_policy = NULL;
}
config_parse_exit_policy(options.SocksPolicy, &socks_policy);
/* ports aren't used. */
for (n=socks_policy; n; n = n->next) {
n->prt_min = 1;
n->prt_max = 65535;
}
}
int socks_policy_permits_address(uint32_t addr)
{
int a;
if (options.SocksPolicy && !socks_policy)
parse_socks_policy();
a = router_compare_addr_to_exit_policy(addr, 1, socks_policy);
if (a==-1)
return 0;
else if (a==0)
return 1;
else if (a==1) {
log_fn(LOG_WARN, "Got unexpected 'maybe' answer from socks policy");
return 1;
}
}
/* ***** Client DNS code ***** */
/* XXX Perhaps this should get merged with the dns.c code somehow. */
......
......@@ -777,13 +777,14 @@ typedef struct {
char *RendExcludeNodes; /**< Comma-separated list of nicknames not to use
* as introduction points. */
char *ExitPolicy; /**< Comma-separated list of exit policy components. */
char *SocksBindAddress; /**< Address to bind for listening for SOCKS
* connections. */
char *ORBindAddress; /**< Address to bind for listening for OR
* connections. */
char *DirBindAddress; /**< Address to bind for listening for directory
* connections. */
struct config_line_t *ExitPolicy; /**< Lists of exit policy components. */
struct config_line_t *SocksPolicy; /**< Lists of socks policy components */
struct config_line_t *SocksBindAddress;
/**< Addresses to bind for listening for SOCKS connections. */
struct config_line_t *ORBindAddress;
/**< Addresses to bind for listening for OR connections. */
struct config_line_t *DirBindAddress;
/**< Addresses to bind for listening for directory connections. */
char *RecommendedVersions; /**< Directory server only: which versions of
* Tor should we tell users to run? */
char *User; /**< Name of user to run Tor as. */
......@@ -953,6 +954,9 @@ struct config_line_t {
int config_assign_default_dirservers(void);
int getconfig(int argc, char **argv, or_options_t *options);
void config_init_logs(or_options_t *options);
void config_parse_exit_policy(struct config_line_t *cfg,
struct exit_policy_t **dest);
void exit_policy_free(struct exit_policy_t *p);
/********************************* connection.c ***************************/
......@@ -982,8 +986,6 @@ int _connection_mark_for_close(connection_t *conn);
void connection_expire_held_open(void);
int connection_create_listener(char *bindaddress, uint16_t bindport, int type);
int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_t port);
int retry_all_connections(void);
......@@ -1318,6 +1320,7 @@ int router_parse_routerlist_from_directory(const char *s,
crypto_pk_env_t *pkey);
routerinfo_t *router_parse_entry_from_string(const char *s, const char *end);
int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
struct exit_policy_t *router_parse_exit_policy_from_string(const char *s);
#endif
......
......@@ -324,41 +324,6 @@ void router_upload_dir_desc_to_dirservers(void) {
directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_DIR, s, strlen(s));
}
/** Append the comma-separated sequence of exit policies in <b>s</b> to the
* exit policy in <b>router</b>. */
static void router_add_exit_policy_from_config_helper(const char *s, routerinfo_t *router) {
char *e;
int last=0;
char line[1024];
if(!s) {
log_fn(LOG_INFO,"No exit policy configured. Ok.");
return; /* nothing to see here */
}
if(!*s) {
log_fn(LOG_INFO,"Exit policy is empty. Ok.");
return; /* nothing to see here */
}
for(;;) {
e = strchr(s,',');
if(!e) {
last = 1;
strncpy(line,s,1023);
} else {
memcpy(line,s, ((e-s)<1023)?(e-s):1023);
line[e-s] = 0;
}
line[1023]=0;
log_fn(LOG_DEBUG,"Adding new entry '%s'",line);
if(router_add_exit_policy_from_string(router,line) < 0)
log_fn(LOG_WARN,"Malformed exit policy %s; skipping.", line);
if(last)
return;
s = e+1;
}
}
#define DEFAULT_EXIT_POLICY "reject 0.0.0.0/8,reject 169.254.0.0/16,reject 127.0.0.0/8,reject 192.168.0.0/16,reject 10.0.0.0/8,reject 172.16.0.0/12,accept *:20-22,accept *:53,accept *:79-81,accept *:110,accept *:143,accept *:443,accept *:873,accept *:993,accept *:995,accept *:1024-65535,reject *:*"
/** Set the exit policy on <b>router</b> to match the exit policy in the
......@@ -366,14 +331,22 @@ static void router_add_exit_policy_from_config_helper(const char *s, routerinfo_
* rule, then append the default exit policy as well.
*/
static void router_add_exit_policy_from_config(routerinfo_t *router) {
router_add_exit_policy_from_config_helper(options.ExitPolicy, router);
/* XXXX This is wrong; you can spell *:* many ways. -NM
* So? If they spell it sneakily, then their exit policy is bulkier. -RD */
if(strstr(options.ExitPolicy," *:*") == NULL) {
/* if exitpolicy includes a *:* line, then we're done. Else, append
* the default exitpolicy. */
router_add_exit_policy_from_config_helper(DEFAULT_EXIT_POLICY, router);
struct exit_policy_t *ep;
struct config_line_t default_policy;
config_parse_exit_policy(options.ExitPolicy, &router->exit_policy);
for (ep = router->exit_policy; ep; ep = ep->next) {
if (ep->msk == 0 && ep->prt_min <= 1 && ep->prt_max >= 65535) {
/* if exitpolicy includes a *:* line, then we're done. */
return;
}
}
/* Else, append the default exitpolicy. */
default_policy.key = NULL;
default_policy.value = DEFAULT_EXIT_POLICY;
default_policy.next = NULL;
config_parse_exit_policy(&default_policy, &router->exit_policy);
}
/** OR only: Return false if my exit policy says to allow connection to
......
......@@ -232,8 +232,6 @@ void router_get_routerlist(routerlist_t **prouterlist) {
/** Free all storage held by <b>router</b>. */
void routerinfo_free(routerinfo_t *router)
{
struct exit_policy_t *e;
if (!router)
return;
......@@ -244,12 +242,7 @@ void routerinfo_free(routerinfo_t *router)
crypto_free_pk_env(router->onion_pkey);
if (router->identity_pkey)
crypto_free_pk_env(router->identity_pkey);
while (router->exit_policy) {
e = router->exit_policy;
router->exit_policy = e->next;
tor_free(e->string);
free(e);
}
exit_policy_free(router->exit_policy);
free(router);
}
......
......@@ -115,6 +115,7 @@ static struct {
/* static function prototypes */
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
static struct exit_policy_t *router_parse_exit_policy(directory_token_t *tok);
static int router_get_hash_impl(const char *s, char *digest,
const char *start_str, const char *end_str);
static void token_free(directory_token_t *tok);
......@@ -590,15 +591,15 @@ routerinfo_t *router_parse_entry_from_string(const char *s,
return router;
}
/** Parse the exit policy in the string <b>s</b> and add it to <b>router</b>.
/** Parse the exit policy in the string <b>s</b> and return it.
*/
int
router_add_exit_policy_from_string(routerinfo_t *router, const char *s)
struct exit_policy_t *
router_parse_exit_policy_from_string(const char *s)
{
directory_token_t *tok = NULL;
const char *cp;
char *tmp;
int r;
struct exit_policy_t *r;
int len, idx;
/* *s might not end with \n, so we need to extend it with one. */
......@@ -620,22 +621,49 @@ router_add_exit_policy_from_string(routerinfo_t *router, const char *s)
}
/* Now that we've gotten an exit policy, add it to the router. */
r = router_add_exit_policy(router, tok);
r = router_parse_exit_policy(tok);
goto done;
err:
r = -1;
r = NULL;
done:
free(tmp);
token_free(tok);
return r;
}
int router_add_exit_policy_from_string(routerinfo_t *router, const char *s)
{
struct exit_policy_t *newe, *tmpe;
newe = router_parse_exit_policy_from_string(s);
if (!newe)
return -1;
for (tmpe = router->exit_policy; tmpe; tmpe=tmpe->next)
;
tmpe->next = newe;
return 0;
}
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok)
{
struct exit_policy_t *newe, **tmpe;
newe = router_parse_exit_policy(tok);
if (!newe)
return -1;
for (tmpe = &router->exit_policy; *tmpe; tmpe=&((*tmpe)->next))
;
*tmpe = newe;
return 0;
}
/** Given a K_ACCEPT or K_REJECT token and a router, create a new exit_policy_t
* corresponding to the token, and add it to <b>router</b> */
static int
router_add_exit_policy(routerinfo_t *router, directory_token_t *tok) {
static struct exit_policy_t *
router_parse_exit_policy(directory_token_t *tok) {
struct exit_policy_t *tmpe, *newe;
struct exit_policy_t*newe;
struct in_addr in;
char *arg, *address, *mask, *port, *endptr;
int bits;
......@@ -643,7 +671,7 @@ router_add_exit_policy(routerinfo_t *router, directory_token_t *tok) {
tor_assert(tok->tp == K_REJECT || tok->tp == K_ACCEPT);
if (tok->n_args != 1)
return -1;
return NULL;
arg = tok->args[0];
newe = tor_malloc_zero(sizeof(struct exit_policy_t));
......@@ -728,24 +756,15 @@ router_add_exit_policy(routerinfo_t *router, directory_token_t *tok) {
address, inet_ntoa(in), newe->prt_min, newe->prt_max);
tor_free(address);
/* now link newe onto the end of exit_policy */
if(!router->exit_policy) {
router->exit_policy = newe;
return 0;
}
for(tmpe=router->exit_policy; tmpe->next; tmpe=tmpe->next) ;
tmpe->next = newe;
return 0;
newe->next = NULL;
return newe;
policy_read_failed:
tor_assert(newe->string);
log_fn(LOG_WARN,"Couldn't parse line '%s'. Dropping", newe->string);
tor_free(newe->string);
free(newe);
return -1;
return NULL;
}
/*
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment