diff options
-rw-r--r-- | src/or/microdesc.c | 9 | ||||
-rw-r--r-- | src/or/nodelist.c | 15 | ||||
-rw-r--r-- | src/or/or.h | 19 | ||||
-rw-r--r-- | src/or/policies.c | 166 | ||||
-rw-r--r-- | src/or/policies.h | 7 | ||||
-rw-r--r-- | src/or/routerparse.c | 2 | ||||
-rw-r--r-- | src/test/test.c | 5 |
7 files changed, 204 insertions, 19 deletions
diff --git a/src/or/microdesc.c b/src/or/microdesc.c index c3511cf324..0a4c8ea4c7 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -4,12 +4,13 @@ #include "or.h" #include "config.h" #include "directory.h" +#include "dirserv.h" #include "microdesc.h" -#include "nodelist.h" -#include "routerparse.h" #include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" #include "routerlist.h" -#include "dirserv.h" +#include "routerparse.h" /** A data structure to hold a bunch of cached microdescriptors. There are * two active files in the cache: a "cache file" that we mmap, and a "journal @@ -458,7 +459,7 @@ microdesc_free(microdesc_t *md) SMARTLIST_FOREACH(md->family, char *, cp, tor_free(cp)); smartlist_free(md->family); } - tor_free(md->exitsummary); + short_policy_free(md->exit_policy); tor_free(md); } diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 9518114479..d303fc67b4 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -10,6 +10,7 @@ #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" +#include "policies.h" #include "router.h" #include "routerlist.h" @@ -597,14 +598,18 @@ node_allows_single_hop_exits(const node_t *node) return 0; } -/** Return true iff it seems that <b>node</b> has an exit policy that - * doesn't actually permit anything to exit. */ +/** Return true iff it seems that <b>node</b> has an exit policy that doesn't + * actually permit anything to exit, or we don't know its exit policy */ int node_exit_policy_rejects_all(const node_t *node) { - (void)node; - UNIMPLEMENTED_NODELIST(); - return 0; + if (node->ri) + return node->ri->policy_is_reject_star; + else if (node->md) + return node->md->exit_policy == NULL || + short_policy_is_reject_star(node->md->exit_policy); + else + return 1; } /** Copy the address for <b>node</b> into *<b>addr_out</b>. */ diff --git a/src/or/or.h b/src/or/or.h index ac9634748e..c8616beba3 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1648,6 +1648,18 @@ typedef struct routerstatus_t { } routerstatus_t; +/** DOCDOC */ +typedef struct short_policy_entry_t { + uint16_t min_port, max_port; +} short_policy_entry_t; + +/** DOCDOC */ +typedef struct short_policy_t { + unsigned int is_accept : 1; + unsigned int n_entries : 31; + short_policy_entry_t entries[1]; +} short_policy_t; + /** A microdescriptor is the smallest amount of information needed to build a * circuit through a router. They are generated by the directory authorities, * using information from the uploaded routerinfo documents. They are not @@ -1689,9 +1701,8 @@ typedef struct microdesc_t { crypto_pk_env_t *onion_pkey; /** As routerinfo_t.family */ smartlist_t *family; - /** Encoded exit policy summary */ - char *exitsummary; /**< exit policy summary - - * XXX this probably should not stay a string. */ + /** Exit policy summary */ + short_policy_t *exit_policy; } microdesc_t; /** A node_t represents a Tor router. @@ -3444,7 +3455,7 @@ typedef enum { ADDR_POLICY_PROBABLY_ACCEPTED=1, /** Part of the address was unknown, but as far as we can tell, it was * rejected. */ - ADDR_POLICY_PROBABLY_REJECTED=2 + ADDR_POLICY_PROBABLY_REJECTED=2, } addr_policy_result_t; /********************************* rephist.c ***************************/ diff --git a/src/or/policies.c b/src/or/policies.c index 1404e20e50..a5b71c9e2f 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -1315,6 +1315,157 @@ policy_summarize(smartlist_t *policy) return result; } +/** DOCDOC */ +short_policy_t * +parse_short_policy(const char *summary) +{ + const char *orig_summary = summary; + short_policy_t *result; + int is_accept; + int n_entries; + short_policy_entry_t entries[MAX_EXITPOLICY_SUMMARY_LEN]; /* overkill */ + const char *next; + + if (!strcmpstart(summary, "accept ")) { + is_accept = 1; + summary += strlen("accept "); + } else if (!strcmpstart(summary, "reject ")) { + is_accept = 0; + summary += strlen("reject "); + } else { + log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Unrecognized policy summary keyword"); + return NULL; + } + + n_entries = 0; + for ( ; *summary; summary = next) { + const char *comma = strchr(summary, ','); + unsigned low, high; + char dummy; + char ent_buf[32]; + + next = comma ? comma+1 : strchr(summary, '\0'); + + if (n_entries == MAX_EXITPOLICY_SUMMARY_LEN) { + log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Impossibly long policy summary %s", + escaped(orig_summary)); + return NULL; + } + + if (! TOR_ISDIGIT(*summary) || next-summary > (int)(sizeof(ent_buf)-1)) { + /* unrecognized entry format. skip it. */ + continue; + } + if (next-summary < 2) { + /* empty; skip it. */ + continue; + } + + memcpy(ent_buf, summary, next-summary-1); + ent_buf[next-summary-1] = '\0'; + + if (tor_sscanf(ent_buf, "%u-%u%c", &low, &high, &dummy) == 2) { + if (low<1 || low>65535 || high<1 || high>65535) { + log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s", + escaped(orig_summary)); + return NULL; + } + } else if (tor_sscanf(ent_buf, "%u%c", &low, &dummy) == 1) { + if (low<1 || low>65535) { + log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s", + escaped(orig_summary)); + return NULL; + } + high = low; + } else { + log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s", + escaped(orig_summary)); + return NULL; + } + + entries[n_entries].min_port = low; + entries[n_entries].max_port = high; + n_entries++; + } + + if (n_entries == 0) { + log_fn(LOG_PROTOCOL_WARN, LD_DIR, + "Found no port-range entries in summary %s", escaped(orig_summary)); + return NULL; + } + + { + size_t size = sizeof(short_policy_t) + + sizeof(short_policy_entry_t)*(n_entries-1); + result = tor_malloc_zero(size); + + tor_assert( (char*)&result->entries[n_entries-1] < ((char*)result)+size); + } + + result->is_accept = is_accept; + result->n_entries = n_entries; + memcpy(result->entries, entries, sizeof(short_policy_entry_t)*n_entries); + return result; +} + +/** DOCDOC */ +void +short_policy_free(short_policy_t *policy) +{ + tor_free(policy); +} + +/** DOCDOC */ +addr_policy_result_t +compare_tor_addr_to_short_policy(const tor_addr_t *addr, uint16_t port, + const short_policy_t *policy) +{ + int i; + int found_match = 0; + int accept; + (void)addr; + + tor_assert(port != 0); + + if (addr && (tor_addr_is_internal(addr, 0) || + tor_addr_is_null(addr) || + tor_addr_is_loopback(addr))) + return ADDR_POLICY_REJECTED; + + for (i=0; i < policy->n_entries; ++i) { + const short_policy_entry_t *e = &policy->entries[i]; + if (e->min_port <= port && port <= e->max_port) { + found_match = 1; + break; + } + } + + if (found_match) + accept = policy->is_accept; + else + accept = ! policy->is_accept; + + /* ???? are these right? */ + if (accept) + return ADDR_POLICY_PROBABLY_ACCEPTED; + else + return ADDR_POLICY_REJECTED; +} + +/* DOCDOC */ +int +short_policy_is_reject_star(const short_policy_t *policy) +{ + /* This doesn't need to be as much on the lookout as policy_is_reject_star, + * since policy summaries are from the consensus or from consensus microdescs. + */ + tor_assert(policy); + /* Check for an exact match of "reject 1-65535". */ + return (policy->is_accept == 0 && policy->n_entries == 1 && + policy->entries[0].min_port == 1 && + policy->entries[0].max_port == 65535); +} + /** Decides whether addr:port is probably or definitely accepted or rejcted by * <b>node</b>. See compare_tor_addr_to_addr_policy for details on addr/port * interpretation. */ @@ -1333,11 +1484,16 @@ addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port, const node_t *node) { - (void)addr; - (void)port; - (void)node; - UNIMPLEMENTED_NODELIST(); - return 0; + if (node->ri) + return compare_tor_addr_to_addr_policy(addr, port, node->ri->exit_policy); + else if (node->md && node->md) { + if (node->md->exit_policy == NULL) + return ADDR_POLICY_REJECTED; + else + return compare_tor_addr_to_short_policy(addr, port, + node->md->exit_policy); + } else + return ADDR_POLICY_PROBABLY_REJECTED; } /** Implementation for GETINFO control command: knows the answer for questions diff --git a/src/or/policies.h b/src/or/policies.h index acc254da3c..5c1113e75a 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -63,5 +63,12 @@ void policies_free_all(void); char *policy_summarize(smartlist_t *policy); +short_policy_t *parse_short_policy(const char *summary); +void short_policy_free(short_policy_t *policy); +int short_policy_is_reject_star(const short_policy_t *policy); +addr_policy_result_t compare_tor_addr_to_short_policy( + const tor_addr_t *addr, uint16_t port, + const short_policy_t *policy); + #endif diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 665a718132..2b82e9828f 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -4302,7 +4302,7 @@ microdescs_parse_from_string(const char *s, const char *eos, } if ((tok = find_opt_by_keyword(tokens, K_P))) { - md->exitsummary = tor_strdup(tok->args[0]); + md->exit_policy = parse_short_policy(tok->args[0]); } crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256); diff --git a/src/test/test.c b/src/test/test.c index 8d8c46fca2..a57b6b0444 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -560,6 +560,7 @@ test_policy_summary_helper(const char *policy_str, smartlist_t *policy = smartlist_create(); char *summary = NULL; int r; + short_policy_t *short_policy = NULL; line.key = (char*)"foo"; line.value = (char *)policy_str; @@ -572,10 +573,14 @@ test_policy_summary_helper(const char *policy_str, test_assert(summary != NULL); test_streq(summary, expected_summary); + short_policy = parse_short_policy(summary); + tt_assert(short_policy); + done: tor_free(summary); if (policy) addr_policy_list_free(policy); + short_policy_free(short_policy); } /** Run unit tests for generating summary lines of exit policies */ |