diff options
author | Roger Dingledine <arma@torproject.org> | 2006-03-27 02:25:34 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2006-03-27 02:25:34 +0000 |
commit | 6f08d121d96be29c2ce2d9ef9df4416141651951 (patch) | |
tree | 91c4acf09b72156d35b9bf259c2e5b48b968a14a /src/or/config.c | |
parent | 74d35c8027937fe8dac031bf76e31a017d4fa81f (diff) | |
download | tor-6f08d121d96be29c2ce2d9ef9df4416141651951.tar.gz tor-6f08d121d96be29c2ce2d9ef9df4416141651951.zip |
Refactor and consolidate addr/exit policies into a new policies.c.
Fix some minor bugs and memory leaks along the way.
svn:r6246
Diffstat (limited to 'src/or/config.c')
-rw-r--r-- | src/or/config.c | 467 |
1 files changed, 5 insertions, 462 deletions
diff --git a/src/or/config.c b/src/or/config.c index 2040c8f668..da7a435f62 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -367,9 +367,6 @@ static int check_nickname_list(const char *lst, const char *name, char **msg); static void config_register_addressmaps(or_options_t *options); static int parse_dir_server_line(const char *line, int validate_only); -static int config_cmp_single_addr_policy(addr_policy_t *a, addr_policy_t *b); -static int config_addr_policy_covers(addr_policy_t *a, addr_policy_t *b); -static int config_addr_policy_intersects(addr_policy_t *a, addr_policy_t *b); static int parse_redirect_line(smartlist_t *result, config_line_t *line, char **msg); static int parse_log_severity_range(const char *range, int *min_out, @@ -392,7 +389,6 @@ static int or_state_validate(or_state_t *old_options, or_state_t *options, static uint64_t config_parse_memunit(const char *s, int *ok); static int config_parse_interval(const char *s, int *ok); static void print_cvs_version(void); -static void parse_reachable_addresses(void); static void init_libevent(void); static int opt_streq(const char *s1, const char *s2); #if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD) @@ -441,12 +437,6 @@ static or_options_t *global_options = NULL; static char *torrc_fname = NULL; /** Persistent serialized state. */ static or_state_t *global_state = NULL; -/** Parsed addr_policy_t describing which addresses we believe we can start - * circuits at. */ -static addr_policy_t *reachable_or_addr_policy = NULL; -/** Parsed addr_policy_t describing which addresses we believe we can connect - * to directories at. */ -static addr_policy_t *reachable_dir_addr_policy = NULL; /** Allocate an empty configuration object of a given format type. */ static void * @@ -507,14 +497,6 @@ config_free_all(void) global_state = NULL; } tor_free(torrc_fname); - if (reachable_or_addr_policy) { - addr_policy_free(reachable_or_addr_policy); - reachable_or_addr_policy = NULL; - } - if (reachable_dir_addr_policy) { - addr_policy_free(reachable_dir_addr_policy); - reachable_dir_addr_policy = NULL; - } } /** If options->SafeLogging is on, return a not very useful string, @@ -763,10 +745,7 @@ options_act(or_options_t *old_options) config_register_addressmaps(options); /* Update address policies. */ - parse_socks_policy(); - parse_dir_policy(); - parse_authdir_policy(); - parse_reachable_addresses(); + policies_parse_from_options(options); init_cookie_authentication(options->CookieAuthentication); @@ -1976,98 +1955,6 @@ validate_ports_csv(smartlist_t *sl, const char *name, char **msg) return 0; } -/** Helper: parse the Reachable(Dir|OR)?Addresses fields into - * reachable_(or|dir)_addr_policy. */ -static void -parse_reachable_addresses(void) -{ - or_options_t *options = get_options(); - - if (options->ReachableDirAddresses && - options->ReachableORAddresses && - options->ReachableAddresses) { - log_warn(LD_CONFIG, - "Both ReachableDirAddresses and ReachableORAddresses are set. " - "ReachableAddresses setting will be ignored."); - } - addr_policy_free(reachable_or_addr_policy); - reachable_or_addr_policy = NULL; - if (!options->ReachableORAddresses && options->ReachableAddresses) - log_info(LD_CONFIG, - "Using ReachableAddresses as ReachableORAddresses."); - if (config_parse_addr_policy(options->ReachableORAddresses ? - options->ReachableORAddresses : - options->ReachableAddresses, - &reachable_or_addr_policy, - ADDR_POLICY_ACCEPT)) { - log_warn(LD_CONFIG, - "Error parsing Reachable%sAddresses entry; ignoring.", - options->ReachableORAddresses ? "OR" : ""); - } - - addr_policy_free(reachable_dir_addr_policy); - reachable_dir_addr_policy = NULL; - if (!options->ReachableDirAddresses && options->ReachableAddresses) - log_info(LD_CONFIG, - "Using ReachableAddresses as ReachableDirAddresses"); - if (config_parse_addr_policy(options->ReachableDirAddresses ? - options->ReachableDirAddresses : - options->ReachableAddresses, - &reachable_dir_addr_policy, - ADDR_POLICY_ACCEPT)) { - if (options->ReachableDirAddresses) - log_warn(LD_CONFIG, - "Error parsing ReachableDirAddresses entry; ignoring."); - } -} - -/** Return true iff the firewall options might block any address:port - * combination. - */ -int -firewall_is_fascist_or(void) -{ - return !!reachable_or_addr_policy; -} - -/** Return true iff <b>policy</b> (possibly NULL) will allow a - * connection to <b>addr</b>:<b>port</b>. - */ -static int -_fascist_firewall_allows_address(uint32_t addr, uint16_t port, - addr_policy_t *policy) -{ - addr_policy_result_t p; - - p = router_compare_addr_to_addr_policy(addr, port, policy); - - switch (p) { - case ADDR_POLICY_PROBABLY_ACCEPTED: - case ADDR_POLICY_ACCEPTED: - return 1; - case ADDR_POLICY_PROBABLY_REJECTED: - case ADDR_POLICY_REJECTED: - return 0; - default: - log_warn(LD_BUG, "Unexpected result: %d", (int)p); - return 0; - } -} - -int -fascist_firewall_allows_address_or(uint32_t addr, uint16_t port) -{ - return _fascist_firewall_allows_address(addr, port, - reachable_or_addr_policy); -} - -int -fascist_firewall_allows_address_dir(uint32_t addr, uint16_t port) -{ - return _fascist_firewall_allows_address(addr, port, - reachable_dir_addr_policy); -} - /** Lowest allowable value for DirFetchPeriod; if this is too low, clients can * overload the directory system. */ #define MIN_DIR_FETCH_PERIOD (10*60) @@ -2104,7 +1991,6 @@ options_validate(or_options_t *old_options, or_options_t *options, { int i, r; config_line_t *cl; - addr_policy_t *addr_policy=NULL; const char *uname; char buf[1024]; #define REJECT(arg) \ @@ -2539,33 +2425,8 @@ options_validate(or_options_t *old_options, or_options_t *options, return -1; } - if (config_parse_exit_policy(options->ExitPolicy, &addr_policy, - options->ExitPolicyRejectPrivate)) - REJECT("Error in ExitPolicy entry."); - - /* The rest of these calls *append* to addr_policy. So don't actually - * use the results for anything other than checking if they parse! */ - if (config_parse_addr_policy(options->DirPolicy, &addr_policy, -1)) - REJECT("Error in DirPolicy entry."); - if (config_parse_addr_policy(options->SocksPolicy, &addr_policy, -1)) - REJECT("Error in SocksPolicy entry."); - if (config_parse_addr_policy(options->ReachableAddresses, &addr_policy, - ADDR_POLICY_ACCEPT)) - REJECT("Error in ReachableAddresses entry."); - if (config_parse_addr_policy(options->ReachableORAddresses, &addr_policy, - ADDR_POLICY_ACCEPT)) - REJECT("Error in ReachableORAddresses entry."); - if (config_parse_addr_policy(options->ReachableDirAddresses, &addr_policy, - ADDR_POLICY_ACCEPT)) - REJECT("Error in ReachableDirAddresses entry."); - if (config_parse_addr_policy(options->AuthDirReject, &addr_policy, - ADDR_POLICY_REJECT)) - REJECT("Error in AuthDirReject entry."); - if (config_parse_addr_policy(options->AuthDirInvalid, &addr_policy, - ADDR_POLICY_REJECT)) - REJECT("Error in AuthDirInvalid entry."); - - addr_policy_free(addr_policy); + if (validate_addr_policies(options, msg) < 0) + return -1; for (cl = options->RedirectExit; cl; cl = cl->next) { if (parse_redirect_line(NULL, cl, msg)<0) @@ -3261,326 +3122,6 @@ normalize_log_options(or_options_t *options) return 0; } -/** Add the exit policy described by <b>more</b> to <b>policy</b>. - */ -static void -options_append_exit_policy_string(addr_policy_t **policy, const char *more) -{ - config_line_t tmp; - - tmp.key = NULL; - tmp.value = (char*) more; - tmp.next = NULL; - config_parse_addr_policy(&tmp, policy, -1); -} - -static int -config_expand_exit_policy_aliases(smartlist_t *entries, int assume_action) -{ - static const char *prefixes[] = { - "0.0.0.0/8", "169.254.0.0/16", - "127.0.0.0/8", "192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12",NULL }; - int i; - char *pre=NULL, *post=NULL; - int expanded_any = 0; - pre = smartlist_join_strings(entries,",",0,NULL); - for (i = 0; i < smartlist_len(entries); ++i) { - char *v = smartlist_get(entries, i); - const char *cp, *ports; - const char *action; - int prefix_idx; - if (!strcasecmpstart(v, "accept")) { - action = "accept "; - cp = v+strlen("accept"); - } else if (!strcasecmpstart(v, "reject")) { - action = "reject "; - cp = v+strlen("reject"); - } else if (assume_action >= 0) { - action = ""; - cp = v; - } else { - log_warn(LD_CONFIG,"Policy '%s' didn't start with accept or reject.", v); - tor_free(pre); - return -1; - } - cp = eat_whitespace(cp); - if (strcmpstart(cp, "private")) - continue; /* No need to expand. */ - cp += strlen("private"); - cp = eat_whitespace(cp); - if (*cp && *cp != ':') - continue; /* It wasn't "private" after all. */ - ports = cp; - /* Okay. We're going to replace entries[i] with a bunch of new entries, - * in order. */ - smartlist_del_keeporder(entries, i); - for (prefix_idx = 0; prefixes[prefix_idx]; ++prefix_idx) { - size_t replacement_len = 16+strlen(prefixes[prefix_idx])+strlen(ports); - char *replacement = tor_malloc(replacement_len); - tor_snprintf(replacement, replacement_len, "%s%s%s", - action, prefixes[prefix_idx], ports); - smartlist_insert(entries, i++, replacement); - } - tor_free(v); - expanded_any = 1; - --i; - } - post = smartlist_join_strings(entries,",",0,NULL); - if (expanded_any) - log_info(LD_CONFIG, "Expanded '%s' to '%s'", pre, post); - tor_free(pre); - tor_free(post); - return expanded_any; -} - -/** Detect and excise "dead code" from the policy *<b>dest</b>. */ -static void -config_exit_policy_remove_redundancies(addr_policy_t **dest) -{ - addr_policy_t *ap, *tmp, *victim, *previous; - - /* Step one: find a *:* entry and cut off everything after it. */ - for (ap=*dest; ap; ap=ap->next) { - if (ap->msk == 0 && ap->prt_min <= 1 && ap->prt_max >= 65535) { - /* This is a catch-all line -- later lines are unreachable. */ - if (ap->next) { - addr_policy_free(ap->next); - ap->next = NULL; - } - } - } - - /* Step two: for every entry, see if there's a redundant entry - * later on, and remove it. */ - for (ap=*dest; ap; ap=ap->next) { - tmp=ap; - while (tmp) { - if (tmp->next && config_addr_policy_covers(ap, tmp->next)) { - log(LOG_INFO, LD_CONFIG, "Removing exit policy %s. It is made " - "redundant by %s.", tmp->next->string, ap->string); - victim = tmp->next; - tmp->next = victim->next; - victim->next = NULL; - addr_policy_free(victim); - } else { - tmp=tmp->next; - } - } - } - - /* Step three: for every entry A, see if there's an entry B making this one - * redundant later on. This is the case if A and B are of the same type - * (accept/reject), A is a subset of B, and there is no other entry of - * different type in between those two that intersects with A. - * - * Anybody want to doublecheck the logic here? XXX - */ - ap = *dest; - previous = NULL; - while (ap) { - for (tmp=ap->next; tmp; tmp=tmp->next) { - if (ap->policy_type != tmp->policy_type && - config_addr_policy_intersects(ap, tmp)) { - tmp = NULL; /* so that we advance previous and ap */ - break; - } - if (ap->policy_type == tmp->policy_type && - config_addr_policy_covers(tmp, ap)) { - log(LOG_INFO, LD_CONFIG, "Removing exit policy %s. It is made " - "redundant by %s.", ap->string, tmp->string); - victim = ap; - ap = ap->next; - - if (previous) { - assert(previous->next == victim); - previous->next = victim->next; - } else { - assert(*dest == victim); - *dest = victim->next; - } - - victim->next = NULL; - addr_policy_free(victim); - break; - } - } - if (!tmp) { - previous = ap; - ap = ap->next; - } - } -} - -#define DEFAULT_EXIT_POLICY \ - "reject *:25,reject *:119,reject *:135-139,reject *:445," \ - "reject *:465,reject *:587,reject *:1214,reject *:4661-4666," \ - "reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*" - -/** Parse the exit policy <b>cfg</b> into the linked list *<b>dest</b>. If - * cfg doesn't end in an absolute accept or reject, add the default exit - * policy afterwards. If <b>rejectprivate</b> is true, prepend - * "reject private:*" to the policy. Return -1 if we can't parse cfg, - * else return 0. - * - */ -int -config_parse_exit_policy(config_line_t *cfg, addr_policy_t **dest, - int rejectprivate) -{ - if (rejectprivate) - options_append_exit_policy_string(dest, "reject private:*"); - if (config_parse_addr_policy(cfg, dest, -1)) - return -1; - options_append_exit_policy_string(dest, DEFAULT_EXIT_POLICY); - - config_exit_policy_remove_redundancies(dest); - return 0; -} - -/** - * Given a linked list of config lines containing "allow" and "deny" tokens, - * parse them and append the result to <b>dest</b>. Return -1 if any tokens - * are malformed, else return 0. - */ -int -config_parse_addr_policy(config_line_t *cfg, - addr_policy_t **dest, - int assume_action) -{ - addr_policy_t **nextp; - smartlist_t *entries; - int r = 0; - - if (!cfg) - return 0; - - nextp = dest; - - while (*nextp) - nextp = &((*nextp)->next); - - entries = smartlist_create(); - for (; cfg; cfg = cfg->next) { - smartlist_split_string(entries, cfg->value, ",", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (config_expand_exit_policy_aliases(entries,assume_action)<0) { - r = -1; - continue; - } - SMARTLIST_FOREACH(entries, const char *, ent, - { - log_debug(LD_CONFIG,"Adding new entry '%s'",ent); - *nextp = router_parse_addr_policy_from_string(ent, assume_action); - if (*nextp) { - if (addr_mask_get_bits((*nextp)->msk)<0) { - log_warn(LD_CONFIG, "Address policy element '%s' can't be expressed " - "as a bit prefix.", ent); - } - /* Advance nextp to the end of the policy. */ - while (*nextp) - nextp = &((*nextp)->next); - } else { - log_warn(LD_CONFIG,"Malformed policy '%s'.", ent); - r = -1; - } - }); - SMARTLIST_FOREACH(entries, char *, ent, tor_free(ent)); - smartlist_clear(entries); - } - smartlist_free(entries); - return r; -} - -/** Compare two provided address policy items, and return -1, 0, or 1 - * if the first is less than, equal to, or greater than the second. */ -static int -config_cmp_single_addr_policy(addr_policy_t *a, addr_policy_t *b) -{ - int r; - if ((r=((int)a->policy_type - (int)b->policy_type))) - return r; - if ((r=((int)a->addr - (int)b->addr))) - return r; - if ((r=((int)a->msk - (int)b->msk))) - return r; - if ((r=((int)a->prt_min - (int)b->prt_min))) - return r; - if ((r=((int)a->prt_max - (int)b->prt_max))) - return r; - return 0; -} - -/** Return true iff the address policy <b>a</b> covers every case that would be - * covered by <b>b</b>, so that a,b is redundant. */ -static int -config_addr_policy_covers(addr_policy_t *a, addr_policy_t *b) -{ - - /* We can ignore accept/reject, since "accept *:80, reject *:80" reduces to - * "accept *:80". */ - if (a->msk & ~b->msk) { - /* There's a wildcard bit in b->msk that's not a wildcard in a. */ - return 0; - } - if ((a->addr & a->msk) != (b->addr & a->msk)) { - /* There's a fixed bit in a that's set differently in b. */ - return 0; - } - return (a->prt_min <= b->prt_min && a->prt_max >= b->prt_max); -} - -/** Return true iff the address policies <b>a</b> and <b>b</b> intersect, that - * is, there exists an address/port that is covered by <b>a</b> that is also - * covered by <b>b</b>. - */ -static int -config_addr_policy_intersects(addr_policy_t *a, addr_policy_t *b) -{ - /* All the bits we care about are those that are set in both - * netmasks. If they are equal in a and b's networkaddresses - * then the networks intersect. If there is a difference, - * then they do not. */ - if (((a->addr ^ b->addr) & a->msk & b->msk) != 0) - return 0; - if (a->prt_max < b->prt_min || b->prt_max < a->prt_min) - return 0; - return 1; -} - -/** Like config_cmp_single_addr_policy() above, but looks at the - * whole set of policies in each case. */ -int -config_cmp_addr_policies(addr_policy_t *a, addr_policy_t *b) -{ - int r; - while (a && b) { - if ((r=config_cmp_single_addr_policy(a,b))) - return r; - a = a->next; - b = b->next; - } - if (!a && !b) - return 0; - if (a) - return -1; - else - return 1; -} - -/** Release all storage held by <b>p</b> */ -void -addr_policy_free(addr_policy_t *p) -{ - addr_policy_t *e; - - while (p) { - e = p; - p = p->next; - tor_free(e->string); - tor_free(e); - } -} - /** Parse a single RedirectExit line's contents from <b>line</b>. If * they are valid, and <b>result</b> is not NULL, add an element to * <b>result</b> and return 0. Else if they are valid, return 0. @@ -4333,6 +3874,7 @@ print_cvs_version(void) extern const char hibernate_c_id[]; extern const char main_c_id[]; extern const char onion_c_id[]; + extern const char policies_c_id[]; extern const char relay_c_id[]; extern const char rendclient_c_id[]; extern const char rendcommon_c_id[]; @@ -4381,6 +3923,7 @@ print_cvs_version(void) puts(hibernate_c_id); puts(main_c_id); puts(onion_c_id); + puts(policies_c_id); puts(relay_c_id); puts(rendclient_c_id); puts(rendcommon_c_id); |