Commit 1bb9734e authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

Implement policies for nodes (and for microdescriptors too)

parent 42acef68
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -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);
}
+10 −5
Original line number Diff line number Diff line
@@ -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>. */
+15 −4
Original line number Diff line number Diff line
@@ -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 ***************************/
+161 −5
Original line number Diff line number Diff line
@@ -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
+7 −0
Original line number Diff line number Diff line
@@ -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
Loading