[or-cvs] [tor/master 09/15] Implement policies for nodes (and for microdescriptors too)

nickm at torproject.org nickm at torproject.org
Wed Oct 13 19:59:50 UTC 2010


Author: Nick Mathewson <nickm at torproject.org>
Date: Fri, 1 Oct 2010 18:12:30 -0400
Subject: Implement policies for nodes (and for microdescriptors too)
Commit: 1bb9734e3a745e2a16b58512f47a6db1229a2b75

---
 src/or/microdesc.c   |    9 ++-
 src/or/nodelist.c    |   15 +++--
 src/or/or.h          |   19 +++++-
 src/or/policies.c    |  166 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/or/policies.h    |    7 ++
 src/or/routerparse.c |    2 +-
 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 c3511cf..0a4c8ea 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 9518114..d303fc6 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 ac96347..c8616be 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 1404e20..a5b71c9 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 acc254d..5c1113e 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 665a718..2b82e98 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 8d8c46f..a57b6b0 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 */
-- 
1.7.1




More information about the tor-commits mailing list