From 80365b989749efbeca6202156197321706462e4d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 20 May 2004 02:42:50 +0000 Subject: [PATCH] Allow multiple exit policy lines; mostly add support for AP policies svn:r1905 --- doc/TODO | 4 +-- src/or/config.c | 76 ++++++++++++++++++++++++++++++++++------ src/or/connection.c | 74 ++++++++++++++++++++++---------------- src/or/connection_edge.c | 36 +++++++++++++++++++ src/or/or.h | 21 ++++++----- src/or/router.c | 57 ++++++++---------------------- src/or/routerlist.c | 9 +---- src/or/routerparse.c | 63 +++++++++++++++++++++------------ 8 files changed, 215 insertions(+), 125 deletions(-) diff --git a/doc/TODO b/doc/TODO index cc6ed1d353..f8223da8c3 100644 --- a/doc/TODO +++ b/doc/TODO @@ -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. diff --git a/src/or/config.c b/src/or/config.c index 7658550ce2..046a716ffd 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -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 options 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 diff --git a/src/or/connection.c b/src/or/connection.c index 64b0632d0e..49576eba33 100644 --- a/src/or/connection.c +++ b/src/or/connection.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 bindaddress 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 type in the connection - * array, mark it for close. +/** If there exist any listeners of type type 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;itype == 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; } diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index c20b0cc2ec..8de0d6d9ba 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -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. */ diff --git a/src/or/or.h b/src/or/or.h index 3422f8adbb..db1f58173f 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -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 diff --git a/src/or/router.c b/src/or/router.c index a7957864f8..aa9134b33b 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -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 s to the - * exit policy in router. */ -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 router 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 diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 7c0fbaf337..17ba4a1fcc 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -232,8 +232,6 @@ void router_get_routerlist(routerlist_t **prouterlist) { /** Free all storage held by router. */ 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); } diff --git a/src/or/routerparse.c b/src/or/routerparse.c index ef6c601ec4..6b227fcddf 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -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 s and add it to router. +/** Parse the exit policy in the string s 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 router */ -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; } /*