[tor-commits] [tor/master] Make option OutboundBindAddress accept IPv6 addresses too.

nickm at torproject.org nickm at torproject.org
Fri Sep 28 16:03:45 UTC 2012


commit 1cbf45bed1451997e0815bedca8e816d87e081ce
Author: Linus Nordberg <linus at torproject.org>
Date:   Thu Sep 20 17:09:25 2012 +0200

    Make option OutboundBindAddress accept IPv6 addresses too.
    
    Implements ticket 6786.
---
 doc/tor.1.txt       |    6 +++-
 src/or/config.c     |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/or/connection.c |   45 +++++++++++++++++++++-------------
 src/or/or.h         |    6 ++++-
 4 files changed, 103 insertions(+), 21 deletions(-)

diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 97fdb48..8245ff4 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -472,8 +472,10 @@ GENERAL OPTIONS
 **OutboundBindAddress** __IP__::
     Make all outbound connections originate from the IP address specified. This
     is only useful when you have multiple network interfaces, and you want all
-    of Tor's outgoing connections to use a single one.  This setting will be
-    ignored for connections to the loopback addresses (127.0.0.0/8 and ::1).
+    of Tor's outgoing connections to use a single one. This option may
+    be used twice, once with an IPv4 address and once with an IPv6 address.
+    This setting will be ignored for connections to the loopback addresses
+    (127.0.0.0/8 and ::1).
 
 **PidFile** __FILE__::
     On startup, write our PID to FILE. On clean shutdown, remove
diff --git a/src/or/config.c b/src/or/config.c
index affe238..05c7028 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -302,7 +302,7 @@ static config_var_t _option_vars[] = {
   V(NumEntryGuards,              UINT,     "3"),
   V(ORListenAddress,             LINELIST, NULL),
   VPORT(ORPort,                      LINELIST, NULL),
-  V(OutboundBindAddress,         STRING,   NULL),
+  V(OutboundBindAddress,         LINELIST,   NULL),
 
   V(PathBiasCircThreshold,       INT,      "-1"),
   V(PathBiasNoticeRate,          DOUBLE,   "-1"),
@@ -474,6 +474,8 @@ static int options_init_logs(or_options_t *options, int validate_only);
 
 static void init_libevent(const or_options_t *options);
 static int opt_streq(const char *s1, const char *s2);
+static int parse_outbound_addresses(or_options_t *options, int validate_only,
+                                    char **msg);
 
 /** Magic value for or_options_t. */
 #define OR_OPTIONS_MAGIC 9090909
@@ -1390,6 +1392,12 @@ options_act(const or_options_t *old_options)
     tor_free(http_authenticator);
   }
 
+  if (parse_outbound_addresses(options, 0, &msg) < 0) {
+    log_warn(LD_BUG, "Failed parsing oubound bind addresses: %s", msg);
+    tor_free(msg);
+    return -1;
+  }
+
   /* Check for transitions that need action. */
   if (old_options) {
     int revise_trackexithosts = 0;
@@ -2164,6 +2172,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
   if (parse_ports(options, 1, msg, &n_ports) < 0)
     return -1;
 
+  if (parse_outbound_addresses(options, 1, msg) < 0)
+    return -1;
+
   if (validate_data_directory(options)<0)
     REJECT("Invalid DataDirectory");
 
@@ -5482,3 +5493,57 @@ getinfo_helper_config(control_connection_t *conn,
   return 0;
 }
 
+/** Parse outbound bind address option lines. If <b>validate_only</b>
+ * is not 0 update _OutboundBindAddressIPv4 and
+ * _OutboundBindAddressIPv6 in <b>options</b>. On failure, set
+ * <b>msg</b> (if provided) to a newly allocated string containing a
+ * description of the problem and return -1. */
+static int
+parse_outbound_addresses(or_options_t *options, int validate_only, char **msg)
+{
+  const config_line_t *lines = options->OutboundBindAddress;
+  int found_v4 = 0, found_v6 = 0;
+
+  if (!validate_only) {
+    memset(&options->_OutboundBindAddressIPv4, 0,
+           sizeof(options->_OutboundBindAddressIPv4));
+    memset(&options->_OutboundBindAddressIPv6, 0,
+           sizeof(options->_OutboundBindAddressIPv6));
+  }
+  while (lines) {
+    tor_addr_t addr, *dst_addr = NULL;
+    int af = tor_addr_parse(&addr, lines->value);
+    switch (af) {
+    case AF_INET:
+      if (found_v4) {
+        if (msg)
+          tor_asprintf(msg, "Multiple IPv4 outbound bind addresses "
+                       "configured: %s", lines->value);
+        return -1;
+      }
+      found_v4 = 1;
+      dst_addr = &options->_OutboundBindAddressIPv4;
+      break;
+    case AF_INET6:
+      if (found_v6) {
+        if (msg)
+          tor_asprintf(msg, "Multiple IPv6 outbound bind addresses "
+                       "configured: %s", lines->value);
+        return -1;
+      }
+      found_v6 = 1;
+      dst_addr = &options->_OutboundBindAddressIPv6;
+      break;
+    default:
+      if (msg)
+        tor_asprintf(msg, "Outbound bind address '%s' didn't parse.",
+                     lines->value);
+      return -1;
+    }
+    if (!validate_only)
+      tor_addr_copy(dst_addr, &addr);
+    lines = lines->next;
+  }
+  return 0;
+}
+
diff --git a/src/or/connection.c b/src/or/connection.c
index d8f5d87..d64c676 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1377,23 +1377,34 @@ connection_connect(connection_t *conn, const char *address,
 
   make_socket_reuseable(s);
 
-  if (options->OutboundBindAddress && !tor_addr_is_loopback(addr)) {
-    struct sockaddr_in ext_addr;
-
-    memset(&ext_addr, 0, sizeof(ext_addr));
-    ext_addr.sin_family = AF_INET;
-    ext_addr.sin_port = 0;
-    if (!tor_inet_aton(options->OutboundBindAddress, &ext_addr.sin_addr)) {
-      log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
-               options->OutboundBindAddress);
-    } else {
-      if (bind(s, (struct sockaddr*)&ext_addr,
-               (socklen_t)sizeof(ext_addr)) < 0) {
-        *socket_error = tor_socket_errno(s);
-        log_warn(LD_NET,"Error binding network socket: %s",
-                 tor_socket_strerror(*socket_error));
-        tor_close_socket(s);
-        return -1;
+  if (!tor_addr_is_loopback(addr)) {
+    const tor_addr_t *ext_addr = NULL;
+    if (protocol_family == AF_INET &&
+        !tor_addr_is_null(&options->_OutboundBindAddressIPv4))
+      ext_addr = &options->_OutboundBindAddressIPv4;
+    else if (protocol_family == AF_INET6 &&
+             !tor_addr_is_null(&options->_OutboundBindAddressIPv6))
+      ext_addr = &options->_OutboundBindAddressIPv6;
+    if (ext_addr) {
+      struct sockaddr_storage ext_addr_sa;
+      socklen_t ext_addr_len = 0;
+      memset(&ext_addr_sa, 0, sizeof(ext_addr_sa));
+      ext_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
+                                          (struct sockaddr *) &ext_addr_sa,
+                                          sizeof(ext_addr_sa));
+      if (ext_addr_len == 0) {
+        log_warn(LD_NET,
+                 "Error converting OutboundBindAddress %s into sockaddr. "
+                 "Ignoring.", fmt_addr(ext_addr));
+      } else {
+        if (bind(s, (struct sockaddr *) &ext_addr_sa, ext_addr_len) < 0) {
+          *socket_error = tor_socket_errno(s);
+          log_warn(LD_NET,"Error binding network socket to %s: %s",
+                   fmt_addr(ext_addr),
+                   tor_socket_strerror(*socket_error));
+          tor_close_socket(s);
+          return -1;
+        }
       }
     }
   }
diff --git a/src/or/or.h b/src/or/or.h
index f7914b8..577cf6d 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3028,7 +3028,11 @@ typedef struct {
   /** Addresses to bind for listening for control connections. */
   config_line_t *ControlListenAddress;
   /** Local address to bind outbound sockets */
-  char *OutboundBindAddress;
+  config_line_t *OutboundBindAddress;
+  /** IPv4 address derived from OutboundBindAddress. */
+  tor_addr_t _OutboundBindAddressIPv4;
+  /** IPv6 address derived from OutboundBindAddress. */
+  tor_addr_t _OutboundBindAddressIPv6;
   /** Directory server only: which versions of
    * Tor should we tell users to run? */
   config_line_t *RecommendedVersions;





More information about the tor-commits mailing list