[tor-commits] [tor/master] relay: Automatically Enable an IPv6 ORPort

nickm at torproject.org nickm at torproject.org
Wed Jul 22 13:56:13 UTC 2020


commit c3a0f757964de0e8a24911d72abff5df20bb323c
Author: David Goulet <dgoulet at torproject.org>
Date:   Tue Jul 21 09:28:52 2020 -0400

    relay: Automatically Enable an IPv6 ORPort
    
    This commit makes it that if the ORPort is set with a single port, it will
    bind to both global listen IPv4 and IPv6 addresses.
    
    To pin an "ORPort <PORT>" to be IPv4 or IPv6, the IPv4Only/IPv6Only flags are
    honored thus this will _only_ bind on IPv6 for that port value:
    
      ORPort 9050 IPv6Only
        Results in: [::]:9050
    
      ORPort 9051 IPv4Only
        Results in: [0.0.0.0]:9051
    
    Attempting to configure an explicit IPv4 address with IPv6Only flag is an
    error and vice versa.
    
    Closes #33246
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 changes/ticket33246              |  3 +++
 src/app/config/config.c          | 51 ++++++++++++++++++++++++++++++----------
 src/core/or/port_cfg_st.h        |  2 ++
 src/feature/relay/relay_config.c |  8 +++++++
 src/test/test_config.c           | 38 ++++++++++++++++++++++++++++++
 5 files changed, 90 insertions(+), 12 deletions(-)

diff --git a/changes/ticket33246 b/changes/ticket33246
new file mode 100644
index 0000000000..c44c2992b0
--- /dev/null
+++ b/changes/ticket33246
@@ -0,0 +1,3 @@
+  o Major feature (relay, IPv6):
+    - Relays now automatically bind on IPv6 for their ORPort unless specified
+      otherwise with the IPv4Only flag. Closes ticket 33246.
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 1671f295e3..a70c1d651e 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -5831,6 +5831,15 @@ port_parse_config(smartlist_t *out,
   int got_zero_port=0, got_nonzero_port=0;
   char *unix_socket_path = NULL;
   port_cfg_t *cfg = NULL;
+  bool addr_is_explicit = false;
+  int family = -1;
+
+  /* Parse default address. This can fail for Unix socket for instance so
+   * family can be -1 and the default_addr will be made UNSPEC. */
+  tor_addr_t default_addr = TOR_ADDR_NULL;
+  if (defaultaddr) {
+    family = tor_addr_parse(&default_addr, defaultaddr);
+  }
 
   /* If there's no FooPort, then maybe make a default one. */
   if (! ports) {
@@ -5907,8 +5916,8 @@ port_parse_config(smartlist_t *out,
         port = 1;
     } else if (!strcasecmp(addrport, "auto")) {
       port = CFG_AUTO_PORT;
-      int af = tor_addr_parse(&addr, defaultaddr);
-      tor_assert(af >= 0);
+      tor_assert(family >= 0);
+      tor_addr_copy(&addr, &default_addr);
     } else if (!strcasecmpend(addrport, ":auto")) {
       char *addrtmp = tor_strndup(addrport, strlen(addrport)-5);
       port = CFG_AUTO_PORT;
@@ -5924,14 +5933,20 @@ port_parse_config(smartlist_t *out,
          "9050" might be a valid address. */
       port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL);
       if (ok) {
-        int af = tor_addr_parse(&addr, defaultaddr);
-        tor_assert(af >= 0);
+        tor_assert(family >= 0);
+        tor_addr_copy(&addr, &default_addr);
       } else if (tor_addr_port_lookup(addrport, &addr, &ptmp) == 0) {
         if (ptmp == 0) {
           log_warn(LD_CONFIG, "%sPort line has address but no port", portname);
           goto err;
         }
+        if (family != -1 && tor_addr_family(&addr) != family) {
+          /* This means we are parsing another ORPort family but we are
+           * attempting to find the default address' family ORPort. */
+          goto ignore;
+        }
         port = ptmp;
+        addr_is_explicit = true;
       } else {
         log_warn(LD_CONFIG, "Couldn't parse address %s for %sPort",
                  escaped(addrport), portname);
@@ -5942,6 +5957,7 @@ port_parse_config(smartlist_t *out,
     /* Default port_cfg_t object initialization */
     cfg = port_cfg_new(unix_socket_path ? strlen(unix_socket_path) : 0);
 
+    cfg->explicit_addr = addr_is_explicit;
     if (unix_socket_path && default_to_group_writable)
       cfg->is_group_writable = 1;
 
@@ -5984,15 +6000,25 @@ port_parse_config(smartlist_t *out,
       }
       if (cfg->server_cfg.bind_ipv4_only &&
           tor_addr_family(&addr) != AF_INET) {
-        log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
-                 portname);
-        goto err;
+        if (cfg->explicit_addr) {
+          log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
+                   portname);
+          goto err;
+        }
+        /* This ORPort is IPv4Only but the default address is IPv6, ignore it
+         * since this will be configured with an IPv4 default address. */
+        goto ignore;
       }
       if (cfg->server_cfg.bind_ipv6_only &&
           tor_addr_family(&addr) != AF_INET6) {
-        log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
-                 portname);
-        goto err;
+        if (cfg->explicit_addr) {
+          log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
+                   portname);
+          goto err;
+        }
+        /* This ORPort is IPv6Only but the default address is IPv4, ignore it
+         * since this will be configured with an IPv6 default address. */
+        goto ignore;
       }
     } else {
       /* This is a client port; parse isolation options */
@@ -6205,9 +6231,10 @@ port_parse_config(smartlist_t *out,
       smartlist_add(out, cfg);
       /* out owns cfg now, don't re-use or free it */
       cfg = NULL;
-    } else {
-      tor_free(cfg);
     }
+
+ ignore:
+    tor_free(cfg);
     SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
     smartlist_clear(elts);
     tor_free(addrport);
diff --git a/src/core/or/port_cfg_st.h b/src/core/or/port_cfg_st.h
index 064e679d78..f8ff6f8cc8 100644
--- a/src/core/or/port_cfg_st.h
+++ b/src/core/or/port_cfg_st.h
@@ -26,6 +26,8 @@ struct port_cfg_t {
   unsigned is_group_writable : 1;
   unsigned is_world_writable : 1;
   unsigned relax_dirmode_check : 1;
+  unsigned explicit_addr : 1; /** Indicate if address was explicitly set or
+                               * we are using the default address. */
 
   entry_port_cfg_t entry_cfg;
 
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index 7cb7f2ccfd..cddb031f8f 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -270,6 +270,14 @@ port_parse_ports_relay(or_options_t *options,
     *msg = tor_strdup("Invalid ORPort configuration");
     goto err;
   }
+  if (port_parse_config(ports,
+                        options->ORPort_lines,
+                        "OR", CONN_TYPE_OR_LISTENER,
+                        "[::]", 0,
+                        CL_PORT_SERVER_OPTIONS) < 0) {
+    *msg = tor_strdup("Invalid ORPort configuration");
+    goto err;
+  }
   if (port_parse_config(ports,
                         options->ExtORPort_lines,
                         "ExtOR", CONN_TYPE_EXT_OR_LISTENER,
diff --git a/src/test/test_config.c b/src/test/test_config.c
index e61a62818d..121b51e925 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -5162,6 +5162,44 @@ test_config_parse_port_config__ports__server_options(void *data)
                           0, CL_PORT_SERVER_OPTIONS);
   tt_int_op(ret, OP_EQ, -1);
 
+  /* Default address is IPv4 but pass IPv6Only flag. Should be ignored. */
+  config_free_lines(config_port_invalid); config_port_invalid = NULL;
+  SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+  smartlist_clear(slout);
+  config_port_invalid = mock_config_line("ORPort", "9050 IPv6Only");
+  ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+                          "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS);
+  tt_int_op(ret, OP_EQ, 0);
+
+  /* Default address is IPv6 but pass IPv4Only flag. Should be ignored. */
+  config_free_lines(config_port_invalid); config_port_invalid = NULL;
+  SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+  smartlist_clear(slout);
+  config_port_invalid = mock_config_line("ORPort", "9050 IPv4Only");
+  ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+                          "[::]", 0, CL_PORT_SERVER_OPTIONS);
+  tt_int_op(ret, OP_EQ, 0);
+
+  /* Explicit address is IPv6 but pass IPv4Only flag. Should error. */
+  config_free_lines(config_port_invalid); config_port_invalid = NULL;
+  SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+  smartlist_clear(slout);
+  config_port_invalid = mock_config_line("ORPort",
+                                         "[4242::4242]:9050 IPv4Only");
+  ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+                          "[::]", 0, CL_PORT_SERVER_OPTIONS);
+  tt_int_op(ret, OP_EQ, -1);
+
+  /* Explicit address is IPv4 but pass IPv6Only flag. Should error. */
+  config_free_lines(config_port_invalid); config_port_invalid = NULL;
+  SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+  smartlist_clear(slout);
+  config_port_invalid = mock_config_line("ORPort",
+                                         "1.2.3.4:9050 IPv6Only");
+  ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+                          "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS);
+  tt_int_op(ret, OP_EQ, -1);
+
  done:
   if (slout)
     SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));





More information about the tor-commits mailing list