浏览代码

Replace (Fascist)Firewall* with a new ReachableAddresses option that understands address policies.

svn:r4751
Nick Mathewson 19 年之前
父节点
当前提交
249b72f53e
共有 12 个文件被更改,包括 154 次插入95 次删除
  1. 2 0
      doc/TODO
  2. 16 10
      doc/tor.1.in
  3. 3 2
      src/or/circuitbuild.c
  4. 96 62
      src/or/config.c
  5. 1 1
      src/or/connection_edge.c
  6. 3 3
      src/or/directory.c
  7. 11 5
      src/or/or.h
  8. 2 2
      src/or/relay.c
  9. 1 1
      src/or/router.c
  10. 3 4
      src/or/routerlist.c
  11. 15 4
      src/or/routerparse.c
  12. 1 1
      src/or/test.c

+ 2 - 0
doc/TODO

@@ -108,6 +108,8 @@ N . helper nodes (Choose N nodes randomly; if a node dies (goes down for a
     - On sighup, if usehelpernodes changed to 1, use new circs.
     - On sighup, if usehelpernodes changed to 1, use new circs.
   o Make a FirewallIPs to correspond to firewallPorts so I can use Tor at
   o Make a FirewallIPs to correspond to firewallPorts so I can use Tor at
     MIT when my directory is out of date.
     MIT when my directory is out of date.
+    o Document, rename, deprecate fascistfirewall, and make it use
+      addr_policy_t logic.
   - switch accountingmax to count total in+out, not either in or
   - switch accountingmax to count total in+out, not either in or
     out. it's easy to move in this direction (not risky), but hard to
     out. it's easy to move in this direction (not risky), but hard to
     back, out if we decide we prefer it the way it already is. hm.
     back, out if we decide we prefer it the way it already is. hm.

+ 16 - 10
doc/tor.1.in

@@ -233,19 +233,25 @@ If 1, Tor will only create outgoing connections to ORs running on ports that
 your firewall allows (defaults to 80 and 443; see \fBFirewallPorts\fR).  This will
 your firewall allows (defaults to 80 and 443; see \fBFirewallPorts\fR).  This will
 allow you to run Tor as a client behind a firewall with restrictive policies,
 allow you to run Tor as a client behind a firewall with restrictive policies,
 but will not allow you to run as a server behind such a firewall.
 but will not allow you to run as a server behind such a firewall.
+This option is deprecated; use
+ReachableAddresses instead.
 .LP
 .LP
 .TP
 .TP
 \fBFirewallPorts \fR\fIPORTS\fP
 \fBFirewallPorts \fR\fIPORTS\fP
-A list of ports that your firewall allows you to connect to.  Only used when
+A list of ports that your firewall allows you to connect to.  Only
-\fBFascistFirewall\fR is set. (Default: 80, 443)
+used when \fBFascistFirewall\fR is set. This option is deprecated; use
-.LP
+ReachableAddresses instead. (Default: 80, 443)
-.TP
+.LP
-\fBFirewallIPs \fR\fIADDR\fP[\fB/\fP\fIMASK\fP\fB][:\fP\fIPORT\fP]...\fP
+.TP
-A comma-separated list of IPs that your firewall allows you to connect to.
+\fBReachableAddresses \fR\fIADDR\fP[\fB/\fP\fIMASK\fP\fB][:\fP\fIPORT\fP]...\fP
-Only used when \fBFascistFirewall\fR is set.  The format is as for the
+A comma-separated list of IPs that your firewall allows you to connect
-addresses in ExitPolicy.  For example, 'FirewallIPs 99.0.0.0/8, *:80' means
+to.  Only used when \fBFascistFirewall\fR is set.  The format is as
-that your firewall allows connections to everything inside net 99, and to
+for the addresses in ExitPolicy, except that "accept" is understood
-port 80 outside.
+unless "reject" is explicitly provided.  For example, 'FirewallIPs
+99.0.0.0/8, reject 18.0.0.0/8:80, accept *:80' means that your
+firewall allows connections to everything inside net 99, rejects port
+80 connections to net 18, and accepts connections to port 80 otherwise.
+(Default: 'accept *:*'.)
 .LP
 .LP
 .TP
 .TP
 \fBLongLivedPorts \fR\fIPORTS\fP
 \fBLongLivedPorts \fR\fIPORTS\fP

+ 3 - 2
src/or/circuitbuild.c

@@ -1416,7 +1416,7 @@ choose_good_entry_server(cpath_build_state_t *state)
     smartlist_add(excluded, r);
     smartlist_add(excluded, r);
     routerlist_add_family(excluded, r);
     routerlist_add_family(excluded, r);
   }
   }
-  if (options->FascistFirewall) {
+  if (firewall_is_fascist()) {
     /* exclude all ORs that listen on the wrong port */
     /* exclude all ORs that listen on the wrong port */
     routerlist_t *rl;
     routerlist_t *rl;
     int i;
     int i;
@@ -1427,7 +1427,7 @@ choose_good_entry_server(cpath_build_state_t *state)
 
 
     for (i=0; i < smartlist_len(rl->routers); i++) {
     for (i=0; i < smartlist_len(rl->routers); i++) {
       r = smartlist_get(rl->routers, i);
       r = smartlist_get(rl->routers, i);
-      if (!fascist_firewall_allows_address(options,r->addr,r->or_port))
+      if (!fascist_firewall_allows_address(r->addr,r->or_port))
         smartlist_add(excluded, r);
         smartlist_add(excluded, r);
     }
     }
   }
   }
@@ -1986,3 +1986,4 @@ helper_nodes_getinfo_helper(const char *question, char **answer)
   }
   }
   return 0;
   return 0;
 }
 }
+

+ 96 - 62
src/or/config.c

@@ -123,7 +123,6 @@ static config_var_t _option_vars[] = {
   VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
   VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
   VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
   VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
   VAR("FirewallPorts",       CSV,      FirewallPorts,        ""),
   VAR("FirewallPorts",       CSV,      FirewallPorts,        ""),
-  VAR("FirewallIPs",         CSV,      FirewallIPs,          NULL),
   VAR("Group",               STRING,   Group,                NULL),
   VAR("Group",               STRING,   Group,                NULL),
   VAR("HardwareAccel",       BOOL,     HardwareAccel,        "1"),
   VAR("HardwareAccel",       BOOL,     HardwareAccel,        "1"),
   VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
   VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
@@ -160,6 +159,7 @@ static config_var_t _option_vars[] = {
   VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
   VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
   VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
   VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
   VAR("PidFile",             STRING,   PidFile,              NULL),
   VAR("PidFile",             STRING,   PidFile,              NULL),
+  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
   VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
   VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
   VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
   VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
   VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
   VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
@@ -285,6 +285,7 @@ static int or_state_validate(or_state_t *options);
 static uint64_t config_parse_memunit(const char *s, int *ok);
 static uint64_t config_parse_memunit(const char *s, int *ok);
 static int config_parse_interval(const char *s, int *ok);
 static int config_parse_interval(const char *s, int *ok);
 static void print_cvs_version(void);
 static void print_cvs_version(void);
+static void parse_reachable_addresses(void);
 static int init_libevent(void);
 static int init_libevent(void);
 #if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
 #if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
 static void check_libevent_version(const char *m, const char *v, int server);
 static void check_libevent_version(const char *m, const char *v, int server);
@@ -324,6 +325,8 @@ static or_options_t *global_options = NULL;
 static char *config_fname = NULL;
 static char *config_fname = NULL;
 /** Persistant serialized state. */
 /** Persistant serialized state. */
 static or_state_t *global_state = NULL;
 static or_state_t *global_state = NULL;
+/** DOCDOC */
+static addr_policy_t *reachable_addr_policy = NULL;
 
 
 static void *
 static void *
 config_alloc(config_format_t *fmt)
 config_alloc(config_format_t *fmt)
@@ -358,6 +361,8 @@ config_free_all(void)
 {
 {
   config_free(&options_format, global_options);
   config_free(&options_format, global_options);
   tor_free(config_fname);
   tor_free(config_fname);
+  addr_policy_free(reachable_addr_policy);
+  reachable_addr_policy = NULL;
 }
 }
 
 
 /** If options->SafeLogging is on, return a not very useful string,
 /** If options->SafeLogging is on, return a not very useful string,
@@ -483,6 +488,7 @@ options_act(void)
   /* Update address policies. */
   /* Update address policies. */
   parse_socks_policy();
   parse_socks_policy();
   parse_dir_policy();
   parse_dir_policy();
+  parse_reachable_addresses();
 
 
   init_cookie_authentication(options->CookieAuthentication);
   init_cookie_authentication(options->CookieAuthentication);
 
 
@@ -1376,7 +1382,6 @@ config_dump(config_format_t *fmt, void *options, int minimal)
     if (minimal && option_is_same(fmt, options, defaults, fmt->vars[i].name))
     if (minimal && option_is_same(fmt, options, defaults, fmt->vars[i].name))
       continue;
       continue;
 
 
-
     desc = config_find_description(fmt, fmt->vars[i].name);
     desc = config_find_description(fmt, fmt->vars[i].name);
     if (desc) {
     if (desc) {
       size_t len = strlen(desc)+8;
       size_t len = strlen(desc)+8;
@@ -1439,56 +1444,51 @@ validate_ports_csv(smartlist_t *sl, const char *name)
   return result;
   return result;
 }
 }
 
 
-/* Return 0 if every element of sl is a string holding an IP with
+/** DOCDOC */
- * optional mask and port, or if sl is NULL. Otherwise return -1. */
+static void
-static int
+parse_reachable_addresses(void)
-validate_addr_port_ranges_csv(smartlist_t *sl, const char *name)
 {
 {
-  uint32_t addr, mask;
+  or_options_t *options = get_options();
-  uint16_t port_min, port_max;
-  int result = 0;
-  tor_assert(name);
 
 
-  if (!sl)
+  addr_policy_free(reachable_addr_policy);
-    return 0;
+  reachable_addr_policy = NULL;
 
 
-  SMARTLIST_FOREACH(sl, const char *, cp,
+  if (config_parse_addr_policy(options->ReachableAddresses,
-  {
+                               &reachable_addr_policy,
-    if (parse_addr_and_port_range(cp, &addr, &mask, &port_min, &port_max)<0) {
+                               ADDR_POLICY_ACCEPT)) {
-      log(LOG_WARN, "IP/port range '%s' invalid in %s", cp, name);
+    log_fn(LOG_WARN, "Error in ReachableAddresses entry; ignoring.");
-      result=-1;
+    return;
-    }
+  }
-  });
-  return result;
 }
 }
 
 
-/** Return true iff we are configured to think that the local fascist
+/** Return true iff the firewall options might block any address:port
- * firewall (if any) will allow a connection to <b>addr</b>:<b>port</b> */
+ * combination
+ */
 int
 int
-fascist_firewall_allows_address(or_options_t *options, uint32_t addr,
+firewall_is_fascist(void)
-                                uint16_t port)
 {
 {
-  uint32_t ipaddr, ipmask;
+  return reachable_addr_policy ? 1 : 0;
-  uint16_t portmin, portmax;
+}
-  if (!options->FascistFirewall)
-    return 1;
-
-  if (smartlist_string_num_isin(options->FirewallPorts, port))
-    return 1;
-
-  if (!options->FirewallIPs)
-    return 0;
-
-  SMARTLIST_FOREACH(options->FirewallIPs, const char *, cp,
-    {
-      if (parse_addr_and_port_range(cp, &ipaddr, &ipmask, &portmin, &portmax)<0)
-        continue;
-      if ((addr&ipmask) == (ipaddr&ipmask) &&
-          (portmin <= port) && (port <= portmax))
-        return 1;
-    });
 
 
-  return 0;
+/** Return true iff we are configured to think that the local fascist
+ * firewall (if any) will allow a connection to <b>addr</b>:<b>port</b> */
+int
+fascist_firewall_allows_address(uint32_t addr, uint16_t port)
+{
+  addr_policy_result_t p = router_compare_addr_to_addr_policy(
+               addr, port, reachable_addr_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_fn(LOG_WARN, "Unexpected result: %d", (int)p);
+      return 0;
+  }
 }
 }
 
 
 /** Return 0 if every setting in <b>options</b> is reasonable.  Else
 /** Return 0 if every setting in <b>options</b> is reasonable.  Else
@@ -1632,20 +1632,48 @@ options_validate(or_options_t *options)
                          "FirewallPorts") < 0)
                          "FirewallPorts") < 0)
     result = -1;
     result = -1;
 
 
-  if (validate_addr_port_ranges_csv(options->FirewallIPs,
+  if (validate_ports_csv(options->LongLivedPorts,
-                                    "FirewallIPs") < 0)
+                         "LongLivedPorts") < 0)
     result = -1;
     result = -1;
 
 
-  if (options->FascistFirewall &&
+  if (options->FascistFirewall) {
-      !smartlist_len(options->FirewallIPs) &&
+    smartlist_t *instead = smartlist_create();
-      !smartlist_len(options->FirewallPorts)) {
+    config_line_t *new_line = tor_malloc_zero(sizeof(config_line_t));
-    smartlist_add(options->FirewallPorts, tor_strdup("80"));
+    new_line->key = tor_strdup("ReachableAddresses");
-    smartlist_add(options->FirewallPorts, tor_strdup("443"));
+    /* If we're configured with the old format, we need to prepend some
+     * open ports. */
+    if (!smartlist_len(options->FirewallPorts)) {
+      smartlist_add(options->FirewallPorts, tor_strdup("80"));
+      smartlist_add(options->FirewallPorts, tor_strdup("443"));
+    }
+    SMARTLIST_FOREACH(options->FirewallPorts, const char *, portno,
+      {
+        int p = atoi(portno);
+        char *s;
+        if (p<0) continue;
+        s = tor_malloc(16);
+        tor_snprintf(s, 16, "*:%d", p);
+        smartlist_add(instead, s);
+      });
+    new_line->value = smartlist_join_strings(instead,",",0,NULL);
+    /* These have been deprecated since 0.1.1.5-alpha-cvs */
+    log_fn(LOG_WARN, "FascistFirewall and FirewallPorts are deprecated.  Instead, use \"ReachableAddresses %s\"", new_line->value);
+    new_line->next = options->ReachableAddresses;
+    options->ReachableAddresses = new_line;
+    SMARTLIST_FOREACH(instead, char *, cp, tor_free(cp));
+    smartlist_free(instead);
   }
   }
 
 
-  if (validate_ports_csv(options->LongLivedPorts,
+  if (options->FascistFirewall || options->ReachableAddresses) {
-                         "LongLivedPorts") < 0)
+    /* We need to end with a reject *:*, not an implicit accept *:* */
-    result = -1;
+    config_line_t **linep = &options->ReachableAddresses;
+    while (*linep) {
+      linep = &((*linep)->next);
+    }
+    *linep = tor_malloc_zero(sizeof(config_line_t));
+    (*linep)->key = tor_strdup("ReachableAddresses");
+    (*linep)->value = tor_strdup("reject *:*");
+  }
 
 
   options->_AllowUnverified = 0;
   options->_AllowUnverified = 0;
   if (options->AllowUnverifiedNodes) {
   if (options->AllowUnverifiedNodes) {
@@ -1844,7 +1872,7 @@ options_validate(or_options_t *options)
       result = -1;
       result = -1;
   }
   }
 
 
-  if (config_parse_addr_policy(options->ExitPolicy, &addr_policy)) {
+  if (config_parse_addr_policy(options->ExitPolicy, &addr_policy, -1)) {
     log_fn(LOG_WARN, "Error in Exit Policy entry.");
     log_fn(LOG_WARN, "Error in Exit Policy entry.");
     result = -1;
     result = -1;
   }
   }
@@ -1854,14 +1882,19 @@ options_validate(or_options_t *options)
   }
   }
   /* The rest of these calls *append* to addr_policy. So don't actually
   /* The rest of these calls *append* to addr_policy. So don't actually
    * use the results for anything other than checking if they parse! */
    * use the results for anything other than checking if they parse! */
-  if (config_parse_addr_policy(options->DirPolicy, &addr_policy)) {
+  if (config_parse_addr_policy(options->DirPolicy, &addr_policy, -1)) {
     log_fn(LOG_WARN, "Error in DirPolicy entry.");
     log_fn(LOG_WARN, "Error in DirPolicy entry.");
     result = -1;
     result = -1;
   }
   }
-  if (config_parse_addr_policy(options->SocksPolicy, &addr_policy)) {
+  if (config_parse_addr_policy(options->SocksPolicy, &addr_policy, -1)) {
     log_fn(LOG_WARN, "Error in SocksPolicy entry.");
     log_fn(LOG_WARN, "Error in SocksPolicy entry.");
     result = -1;
     result = -1;
   }
   }
+  if (config_parse_addr_policy(options->ReachableAddresses, &addr_policy,
+                               ADDR_POLICY_ACCEPT)) {
+    log_fn(LOG_WARN, "Error in ReachableAddresses entry.");
+    result = -1;
+  }
   addr_policy_free(addr_policy);
   addr_policy_free(addr_policy);
 
 
   for (cl = options->RedirectExit; cl; cl = cl->next) {
   for (cl = options->RedirectExit; cl; cl = cl->next) {
@@ -2461,7 +2494,7 @@ options_append_default_exit_policy(addr_policy_t **policy)
   tmp.key = NULL;
   tmp.key = NULL;
   tmp.value = (char*)DEFAULT_EXIT_POLICY;
   tmp.value = (char*)DEFAULT_EXIT_POLICY;
   tmp.next = NULL;
   tmp.next = NULL;
-  config_parse_addr_policy(&tmp, policy);
+  config_parse_addr_policy(&tmp, policy, -1);
 
 
   /* Remove redundant parts, if any. */
   /* Remove redundant parts, if any. */
   for (ap=*policy; ap; ap=ap->next) {
   for (ap=*policy; ap; ap=ap->next) {
@@ -2482,7 +2515,8 @@ options_append_default_exit_policy(addr_policy_t **policy)
  */
  */
 int
 int
 config_parse_addr_policy(config_line_t *cfg,
 config_parse_addr_policy(config_line_t *cfg,
-                         addr_policy_t **dest)
+                         addr_policy_t **dest,
+                         int assume_action)
 {
 {
   addr_policy_t **nextp;
   addr_policy_t **nextp;
   smartlist_t *entries;
   smartlist_t *entries;
@@ -2502,7 +2536,7 @@ config_parse_addr_policy(config_line_t *cfg,
     SMARTLIST_FOREACH(entries, const char *, ent,
     SMARTLIST_FOREACH(entries, const char *, ent,
     {
     {
       log_fn(LOG_DEBUG,"Adding new entry '%s'",ent);
       log_fn(LOG_DEBUG,"Adding new entry '%s'",ent);
-      *nextp = router_parse_addr_policy_from_string(ent);
+      *nextp = router_parse_addr_policy_from_string(ent, assume_action);
       if (*nextp) {
       if (*nextp) {
         nextp = &((*nextp)->next);
         nextp = &((*nextp)->next);
       } else {
       } else {
@@ -3140,9 +3174,9 @@ config_getinfo_helper(const char *question, char **answer)
       size_t len;
       size_t len;
       desc = config_find_description(&options_format, var->name);
       desc = config_find_description(&options_format, var->name);
       switch (var->type) {
       switch (var->type) {
-        case CONFIG_TYPE_STRING: type = "String"; break; 
+        case CONFIG_TYPE_STRING: type = "String"; break;
         case CONFIG_TYPE_UINT: type = "Integer"; break;
         case CONFIG_TYPE_UINT: type = "Integer"; break;
-        case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break; 
+        case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break;
         case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;
         case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;
         case CONFIG_TYPE_DOUBLE: type = "Float"; break;
         case CONFIG_TYPE_DOUBLE: type = "Float"; break;
         case CONFIG_TYPE_BOOL: type = "Boolean"; break;
         case CONFIG_TYPE_BOOL: type = "Boolean"; break;

+ 1 - 1
src/or/connection_edge.c

@@ -1696,7 +1696,7 @@ parse_socks_policy(void)
     addr_policy_free(socks_policy);
     addr_policy_free(socks_policy);
     socks_policy = NULL;
     socks_policy = NULL;
   }
   }
-  config_parse_addr_policy(get_options()->SocksPolicy, &socks_policy);
+  config_parse_addr_policy(get_options()->SocksPolicy, &socks_policy, -1);
   /* ports aren't used. */
   /* ports aren't used. */
   for (n=socks_policy; n; n = n->next) {
   for (n=socks_policy; n; n = n->next) {
     n->prt_min = 1;
     n->prt_min = 1;

+ 3 - 3
src/or/directory.c

@@ -69,7 +69,7 @@ parse_dir_policy(void)
     addr_policy_free(dir_policy);
     addr_policy_free(dir_policy);
     dir_policy = NULL;
     dir_policy = NULL;
   }
   }
-  config_parse_addr_policy(get_options()->DirPolicy, &dir_policy);
+  config_parse_addr_policy(get_options()->DirPolicy, &dir_policy, -1);
   /* ports aren't used. */
   /* ports aren't used. */
   for (n=dir_policy; n; n = n->next) {
   for (n=dir_policy; n; n = n->next) {
     n->prt_min = 1;
     n->prt_min = 1;
@@ -138,7 +138,7 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
        * router descriptor, but not when uploading a service
        * router descriptor, but not when uploading a service
        * descriptor -- those use Tor. */
        * descriptor -- those use Tor. */
       if (purpose == DIR_PURPOSE_UPLOAD_DIR && !get_options()->HttpProxy) {
       if (purpose == DIR_PURPOSE_UPLOAD_DIR && !get_options()->HttpProxy) {
-        if (!fascist_firewall_allows_address(get_options(),ds->addr,ds->dir_port))
+        if (!fascist_firewall_allows_address(ds->addr,ds->dir_port))
           continue;
           continue;
       }
       }
       directory_initiate_command_trusted_dir(ds, purpose, purpose_is_private(purpose),
       directory_initiate_command_trusted_dir(ds, purpose, purpose_is_private(purpose),
@@ -159,7 +159,7 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
 {
 {
   routerinfo_t *r = NULL;
   routerinfo_t *r = NULL;
   trusted_dir_server_t *ds = NULL;
   trusted_dir_server_t *ds = NULL;
-  int fascistfirewall = get_options()->FascistFirewall;
+  int fascistfirewall = firewall_is_fascist();
   int directconn = purpose == DIR_PURPOSE_FETCH_DIR ||
   int directconn = purpose == DIR_PURPOSE_FETCH_DIR ||
                    purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
                    purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
   int fetch_fresh_first = advertised_server_mode();
   int fetch_fresh_first = advertised_server_mode();

+ 11 - 5
src/or/or.h

@@ -1094,7 +1094,9 @@ typedef struct {
   int RunAsDaemon; /**< If true, run in the background. (Unix only) */
   int RunAsDaemon; /**< If true, run in the background. (Unix only) */
   int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */
   int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */
   smartlist_t *FirewallPorts; /**< Which ports our firewall allows (strings). */
   smartlist_t *FirewallPorts; /**< Which ports our firewall allows (strings). */
-  smartlist_t *FirewallIPs; /**< Which IPs our firewall allows (strings). */
+  config_line_t *ReachableAddresses; /**< Which IP:ports our firewall allows
+                                      * (exit policy.) */
+
   /** Application ports that require all nodes in circ to have sufficient uptime. */
   /** Application ports that require all nodes in circ to have sufficient uptime. */
   smartlist_t *LongLivedPorts;
   smartlist_t *LongLivedPorts;
   /** Should we try to reuse the same exit node for a given host */
   /** Should we try to reuse the same exit node for a given host */
@@ -1175,6 +1177,8 @@ typedef struct {
                        * of fixed nodes? */
                        * of fixed nodes? */
   int NumHelperNodes; /**< How many helper nodes do we try to establish? */
   int NumHelperNodes; /**< How many helper nodes do we try to establish? */
   int RephistTrackTime; /**< How many seconds do we keep rephist info? */
   int RephistTrackTime; /**< How many seconds do we keep rephist info? */
+
+  addr_policy_t *reachable_addr_policy; /**< Parsed from ReachableAddresses */
 } or_options_t;
 } or_options_t;
 
 
 /** Persistent state for an onion router, as saved to disk. */
 /** Persistent state for an onion router, as saved to disk. */
@@ -1360,7 +1364,8 @@ void options_init(or_options_t *options);
 int options_init_from_torrc(int argc, char **argv);
 int options_init_from_torrc(int argc, char **argv);
 int options_init_logs(or_options_t *options, int validate_only);
 int options_init_logs(or_options_t *options, int validate_only);
 int config_parse_addr_policy(config_line_t *cfg,
 int config_parse_addr_policy(config_line_t *cfg,
-                             addr_policy_t **dest);
+                             addr_policy_t **dest,
+                             int assume_action);
 void options_append_default_exit_policy(addr_policy_t **policy);
 void options_append_default_exit_policy(addr_policy_t **policy);
 void addr_policy_free(addr_policy_t *p);
 void addr_policy_free(addr_policy_t *p);
 int option_is_recognized(const char *key);
 int option_is_recognized(const char *key);
@@ -1376,8 +1381,8 @@ int or_state_save(void);
 
 
 int config_getinfo_helper(const char *question, char **answer);
 int config_getinfo_helper(const char *question, char **answer);
 
 
-int fascist_firewall_allows_address(or_options_t *options, uint32_t addr,
+int firewall_is_fascist(void);
-                                    uint16_t port);
+int fascist_firewall_allows_address(uint32_t addr, uint16_t port);
 
 
 /********************************* connection.c ***************************/
 /********************************* connection.c ***************************/
 
 
@@ -2022,7 +2027,8 @@ running_routers_t *router_parse_runningrouters(const char *str,
                                                int write_to_cache);
                                                int write_to_cache);
 routerinfo_t *router_parse_entry_from_string(const char *s, const char *end);
 routerinfo_t *router_parse_entry_from_string(const char *s, const char *end);
 int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
 int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
-addr_policy_t *router_parse_addr_policy_from_string(const char *s);
+addr_policy_t *router_parse_addr_policy_from_string(const char *s,
+                                                    int assume_action);
 int check_software_version_against_directory(const char *directory);
 int check_software_version_against_directory(const char *directory);
 int tor_version_parse(const char *s, tor_version_t *out);
 int tor_version_parse(const char *s, tor_version_t *out);
 int tor_version_as_new_as(const char *platform, const char *cutoff);
 int tor_version_as_new_as(const char *platform, const char *cutoff);

+ 2 - 2
src/or/relay.c

@@ -656,7 +656,7 @@ connection_edge_process_end_not_open(
           log_fn(LOG_NOTICE,"Exitrouter '%s' seems to be more restrictive than its exit policy. Not using this router as exit for now.", exitrouter->nickname);
           log_fn(LOG_NOTICE,"Exitrouter '%s' seems to be more restrictive than its exit policy. Not using this router as exit for now.", exitrouter->nickname);
           addr_policy_free(exitrouter->exit_policy);
           addr_policy_free(exitrouter->exit_policy);
           exitrouter->exit_policy =
           exitrouter->exit_policy =
-            router_parse_addr_policy_from_string("reject *:*");
+            router_parse_addr_policy_from_string("reject *:*", -1);
         }
         }
         if (connection_ap_detach_retriable(conn, circ) >= 0)
         if (connection_ap_detach_retriable(conn, circ) >= 0)
           return 0;
           return 0;
@@ -683,7 +683,7 @@ connection_edge_process_end_not_open(
         if (exitrouter) {
         if (exitrouter) {
           addr_policy_free(exitrouter->exit_policy);
           addr_policy_free(exitrouter->exit_policy);
           exitrouter->exit_policy =
           exitrouter->exit_policy =
-            router_parse_addr_policy_from_string("reject *:*");
+            router_parse_addr_policy_from_string("reject *:*", -1);
         }
         }
         if (connection_ap_detach_retriable(conn, circ) >= 0)
         if (connection_ap_detach_retriable(conn, circ) >= 0)
           return 0;
           return 0;

+ 1 - 1
src/or/router.c

@@ -749,7 +749,7 @@ router_rebuild_descriptor(int force)
   if (options->BandwidthRate > options->MaxAdvertisedBandwidth)
   if (options->BandwidthRate > options->MaxAdvertisedBandwidth)
     ri->bandwidthrate = (int)options->MaxAdvertisedBandwidth;
     ri->bandwidthrate = (int)options->MaxAdvertisedBandwidth;
 
 
-  config_parse_addr_policy(get_options()->ExitPolicy, &ri->exit_policy);
+  config_parse_addr_policy(get_options()->ExitPolicy, &ri->exit_policy, -1);
   options_append_default_exit_policy(&ri->exit_policy);
   options_append_default_exit_policy(&ri->exit_policy);
 
 
   if (desc_routerinfo) /* inherit values */
   if (desc_routerinfo) /* inherit values */

+ 3 - 4
src/or/routerlist.c

@@ -123,7 +123,7 @@ router_pick_directory_server(int requireother,
     return choice;
     return choice;
 
 
   log_fn(LOG_INFO,"Still no %s router entries. Reloading and trying again.",
   log_fn(LOG_INFO,"Still no %s router entries. Reloading and trying again.",
-         get_options()->FascistFirewall ? "reachable" : "known");
+         firewall_is_fascist() ? "reachable" : "known");
   has_fetched_directory=0; /* reset it */
   has_fetched_directory=0; /* reset it */
   if (router_reload_router_list()) {
   if (router_reload_router_list()) {
     return NULL;
     return NULL;
@@ -187,8 +187,7 @@ router_pick_directory_server_impl(int requireother, int fascistfirewall,
     if (requireother && router_is_me(router))
     if (requireother && router_is_me(router))
       continue;
       continue;
     if (fascistfirewall) {
     if (fascistfirewall) {
-      if (!fascist_firewall_allows_address(get_options(),router->addr,
+      if (!fascist_firewall_allows_address(router->addr, router->dir_port))
-                                           router->dir_port))
         continue;
         continue;
     }
     }
     /* before 0.0.9rc5-cvs, only trusted dirservers served status info. */
     /* before 0.0.9rc5-cvs, only trusted dirservers served status info. */
@@ -231,7 +230,7 @@ router_pick_trusteddirserver_impl(int requireother, int fascistfirewall)
           !memcmp(me->identity_digest, d->digest, DIGEST_LEN))
           !memcmp(me->identity_digest, d->digest, DIGEST_LEN))
         continue;
         continue;
       if (fascistfirewall) {
       if (fascistfirewall) {
-        if (!fascist_firewall_allows_address(get_options(),d->addr,d->dir_port))
+        if (!fascist_firewall_allows_address(d->addr, d->dir_port))
           continue;
           continue;
       }
       }
       smartlist_add(sl, d);
       smartlist_add(sl, d);

+ 15 - 4
src/or/routerparse.c

@@ -1028,10 +1028,12 @@ router_parse_entry_from_string(const char *s, const char *end)
   return router;
   return router;
 }
 }
 
 
-/** Parse the exit policy in the string <b>s</b> and return it.
+/** Parse the exit policy in the string <b>s</b> and return it.  If
+ * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
+ * ADDR_POLICY_REJECT) for items that specify no action.
  */
  */
 addr_policy_t *
 addr_policy_t *
-router_parse_addr_policy_from_string(const char *s)
+router_parse_addr_policy_from_string(const char *s, int assume_action)
 {
 {
   directory_token_t *tok = NULL;
   directory_token_t *tok = NULL;
   const char *cp;
   const char *cp;
@@ -1047,6 +1049,15 @@ router_parse_addr_policy_from_string(const char *s)
   }
   }
   tmp[len]='\n';
   tmp[len]='\n';
   tmp[len+1]='\0';
   tmp[len+1]='\0';
+  while (TOR_ISSPACE(*cp))
+    ++cp;
+  if ((*cp == '*' || TOR_ISDIGIT(*cp)) && assume_action >= 0) {
+    char *new_str = tor_malloc(len+10);
+    tor_snprintf(new_str, len+10, "%s %s\n",
+                 assume_action == ADDR_POLICY_ACCEPT?"accept":"reject", cp);
+    tor_free(tmp);
+    cp = tmp = new_str;
+  }
   tok = get_next_token(&cp, RTR_ONLY);
   tok = get_next_token(&cp, RTR_ONLY);
   if (tok->tp == _ERR) {
   if (tok->tp == _ERR) {
     log_fn(LOG_WARN, "Error reading exit policy: %s", tok->error);
     log_fn(LOG_WARN, "Error reading exit policy: %s", tok->error);
@@ -1073,7 +1084,7 @@ int
 router_add_exit_policy_from_string(routerinfo_t *router, const char *s)
 router_add_exit_policy_from_string(routerinfo_t *router, const char *s)
 {
 {
   addr_policy_t *newe, *tmpe;
   addr_policy_t *newe, *tmpe;
-  newe = router_parse_addr_policy_from_string(s);
+  newe = router_parse_addr_policy_from_string(s, -1);
   if (!newe)
   if (!newe)
     return -1;
     return -1;
   for (tmpe = router->exit_policy; tmpe; tmpe=tmpe->next)
   for (tmpe = router->exit_policy; tmpe; tmpe=tmpe->next)
@@ -1156,7 +1167,7 @@ assert_addr_policy_ok(addr_policy_t *t)
     tor_assert(t->policy_type == ADDR_POLICY_REJECT ||
     tor_assert(t->policy_type == ADDR_POLICY_REJECT ||
                t->policy_type == ADDR_POLICY_ACCEPT);
                t->policy_type == ADDR_POLICY_ACCEPT);
     tor_assert(t->prt_min <= t->prt_max);
     tor_assert(t->prt_min <= t->prt_max);
-    t2 = router_parse_addr_policy_from_string(t->string);
+    t2 = router_parse_addr_policy_from_string(t->string, -1);
     tor_assert(t2);
     tor_assert(t2);
     tor_assert(t2->policy_type == t->policy_type);
     tor_assert(t2->policy_type == t->policy_type);
     tor_assert(t2->addr == t->addr);
     tor_assert(t2->addr == t->addr);

+ 1 - 1
src/or/test.c

@@ -1385,7 +1385,7 @@ test_exit_policies(void)
 {
 {
   addr_policy_t *policy;
   addr_policy_t *policy;
 
 
-  policy = router_parse_addr_policy_from_string("reject 192.168.0.0/16:*");
+  policy = router_parse_addr_policy_from_string("reject 192.168.0.0/16:*",-1);
   test_eq(NULL, policy->next);
   test_eq(NULL, policy->next);
   test_eq(ADDR_POLICY_REJECT, policy->policy_type);
   test_eq(ADDR_POLICY_REJECT, policy->policy_type);
   test_eq(0xc0a80000u, policy->addr);
   test_eq(0xc0a80000u, policy->addr);