diff options
Diffstat (limited to 'src/or/routerlist.c')
-rw-r--r-- | src/or/routerlist.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/or/routerlist.c b/src/or/routerlist.c index c4411fdcdc..f9c39eca55 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1021,6 +1021,90 @@ int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port, return 1; /* all will reject. */ } +/** + * If <b>policy</b> implicitly allows connections to any port in the + * IP set <b>addr</b>/<b>mask</b>, then set *<b>policy_out</b> to the + * part of the policy that allows it, and return 1. Else return 0. + * + * A policy allows an IP:Port combination <em>implicitly</em> if + * it is included in a *: pattern, or in a fallback pattern. + */ +static int +policy_includes_addr_mask_implicitly(addr_policy_t *policy, + uint32_t addr, uint32_t mask, + addr_policy_t **policy_out) +{ + uint32_t addr2; + tor_assert(policy_out); + addr &= mask; + addr2 = addr | ~mask; + for (; policy; policy=policy->next) { + /* Does this policy cover all of the address range we're looking at? */ + /* Boolean logic time: range X is contained in range Y if, for + * each bit B, all possible values of B in X are values of B in Y. + * In "addr", we have every fixed bit set to its value, and every + * free bit set to 0. In "addr2", we have every fixed bit set to + * its value, and every free bit set to 1. So if addr and addr2 are + * both in the policy, the range is covered by the policy. + */ + if ((policy->addr & policy->msk) == (addr & policy->msk) && + (policy->addr & policy->msk) == (addr2 & policy->msk) && + (policy->prt_min <= 1 && policy->prt_max == 65535)) { + return 0; + } + /* Does this policy cover some of the address range we're looking at? */ + /* Boolean logic time: range X and range Y intersect if there is + * some z such that z & Xmask == Xaddr and z & Ymask == Yaddr. + * This is FALSE iff there is some bit b where Xmask == yMask == 1 + * and Xaddr != Yaddr. So if X intersects with Y iff at every + * place where Xmask&Ymask==1, Xaddr == Yaddr, or equivalently, + * Xaddr&Xmask&Ymask == Yaddr&Xmask&Ymask. + */ + if ((policy->addr & policy->msk & mask) == (addr & policy->msk) && + policy->policy_type == ADDR_POLICY_ACCEPT) { + *policy_out = policy; + return 1; + } + } + *policy_out = NULL; + return 1; +} + +/** If <b>policy</b> implicitly allows connections to any port on + * 127.*, 192.168.*, etc, then warn (if <b>warn</b> is set) and return + * true. Else return false. + **/ +int +exit_policy_implicitly_allows_local_networks(addr_policy_t *policy, + int warn) +{ + addr_policy_t *p; + int r=0,i; + static struct { + uint32_t addr; uint32_t mask; const char *network; + } private_networks[] = { + { 0x7f000000, 0xff000000, "localhost (127.x)" }, + { 0x0a000000, 0xff000000, "addresses in private network 10.x" }, + { 0xa9fe0000, 0xffff0000, "addresses in private network 169.254.x" }, + { 0xac100000, 0xfff00000, "addresses in private network 172.16.x" }, + { 0xc0a80000, 0xffff0000, "addresses in private network 192.168.x" }, + { 0,0,NULL}, + }; + for (i=0; private_networks[i].addr; ++i) { + p = NULL; + if (policy_includes_addr_mask_implicitly( + policy, private_networks[i].addr, private_networks[i].mask, &p)) { + if (warn) + log_fn(LOG_WARN, "Exit policy %s implicitly accepts %s", + policy?policy->string:"(default)", + private_networks[i].network); + r = 1; + } + } + + return r; +} + /** Return true iff <b>router</b> does not permit exit streams. */ int router_exit_policy_rejects_all(routerinfo_t *router) { |