Browse Source

Merge remote-tracking branch 'andrea/ticket12585_v3'

Nick Mathewson 9 years ago
parent
commit
d8b7dcca8d
8 changed files with 268 additions and 42 deletions
  1. 9 0
      changes/bug12585
  2. 10 1
      doc/tor.1.txt
  3. 18 0
      src/common/address.c
  4. 100 10
      src/or/config.c
  5. 117 29
      src/or/connection.c
  6. 4 0
      src/or/main.c
  7. 8 0
      src/or/or.h
  8. 2 2
      src/or/relay.c

+ 9 - 0
changes/bug12585

@@ -0,0 +1,9 @@
+  o Major features (security)
+    - Implementation of SocksSocket option - SocksSocket implements a SOCKS
+      proxy reachable by Unix Domain Socket. This allows client applications to
+      communicate with Tor without having the ability to create AF_INET or
+      AF_INET6 family sockets. If an application has permission to create a socket
+      with AF_UNIX, it may directly communicate with Tor as if it were an other
+      SOCKS proxy. This should allow high risk applications to be entirely prevented
+      from connecting directly with TCP/IP, they will be able to only connect to the
+      internet through AF_UNIX and only through Tor.

+ 10 - 1
doc/tor.1.txt

@@ -294,7 +294,7 @@ GENERAL OPTIONS
 
 [[ControlSocket]] **ControlSocket** __Path__::
     Like ControlPort, but listens on a Unix domain socket, rather than a TCP
-    socket. (Unix and Unix-like systems only.)
+    socket. '0' disables ControlSocket (Unix and Unix-like systems only.)
 
 [[ControlSocketsGroupWritable]] **ControlSocketsGroupWritable** **0**|**1**::
     If this option is set to 0, don't allow the filesystem group to read and
@@ -483,6 +483,15 @@ GENERAL OPTIONS
     in accordance to RFC 1929. Both username and password must be between 1 and
     255 characters.
 
+[[SocksSocket]] **SocksSocket** __Path__::
+    Like SocksPort, but listens on a Unix domain socket, rather than a TCP
+    socket.  '0' disables SocksSocket (Unix and Unix-like systems only.)
+
+[[SocksSocketsGroupWritable]] **SocksSocketsGroupWritable** **0**|**1**::
+    If this option is set to 0, don't allow the filesystem group to read and
+    write unix sockets (e.g. SocksSocket). If the option is set to 1, make
+    the SocksSocket socket readable and writable by the default GID. (Default: 0)
+
 [[KeepalivePeriod]] **KeepalivePeriod** __NUM__::
     To keep firewalls from expiring connections, send a padding keepalive cell
     every NUM seconds on open connections that are in use. If the connection

+ 18 - 0
src/common/address.c

@@ -121,6 +121,15 @@ tor_addr_to_sockaddr(const tor_addr_t *a,
   }
 }
 
+/** Set address <b>a</b> to zero.  This address belongs to
+ * the AF_UNIX family. */
+static void
+tor_addr_make_af_unix(tor_addr_t *a)
+{
+  memset(a, 0, sizeof(*a));
+  a->family = AF_UNIX;
+}
+
 /** Set the tor_addr_t in <b>a</b> to contain the socket address contained in
  * <b>sa</b>. */
 int
@@ -142,6 +151,9 @@ tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
     tor_addr_from_in6(a, &sin6->sin6_addr);
     if (port_out)
       *port_out = ntohs(sin6->sin6_port);
+  } else if (sa->sa_family == AF_UNIX) {
+    tor_addr_make_af_unix(a);
+    return 0;
   } else {
     tor_addr_make_unspec(a);
     return -1;
@@ -421,6 +433,10 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate)
         ptr = dest;
       }
       break;
+    case AF_UNIX:
+      tor_snprintf(dest, len, "AF_UNIX");
+      ptr = dest;
+      break;
     default:
       return NULL;
   }
@@ -816,6 +832,8 @@ tor_addr_is_null(const tor_addr_t *addr)
     }
     case AF_INET:
       return (tor_addr_to_ipv4n(addr) == 0);
+    case AF_UNIX:
+      return 1;
     case AF_UNSPEC:
       return 1;
     default:

+ 100 - 10
src/or/config.c

@@ -200,6 +200,8 @@ static config_var_t option_vars_[] = {
   V(ControlPortWriteToFile,      FILENAME, NULL),
   V(ControlSocket,               LINELIST, NULL),
   V(ControlSocketsGroupWritable, BOOL,     "0"),
+  V(SocksSocket,                 LINELIST, NULL),
+  V(SocksSocketsGroupWritable,   BOOL,     "0"),
   V(CookieAuthentication,        BOOL,     "0"),
   V(CookieAuthFileGroupReadable, BOOL,     "0"),
   V(CookieAuthFile,              STRING,   NULL),
@@ -1047,6 +1049,20 @@ options_act_reversible(const or_options_t *old_options, char **msg)
   }
 #endif
 
+#ifndef HAVE_SYS_UN_H
+  if (options->SocksSocket || options->SocksSocketsGroupWritable) {
+    *msg = tor_strdup("Unix domain sockets (SocksSocket) not supported "
+                      "on this OS/with this build.");
+    goto rollback;
+  }
+#else
+  if (options->SocksSocketsGroupWritable && !options->SocksSocket) {
+    *msg = tor_strdup("Setting SocksSocketGroupWritable without setting"
+                      "a SocksSocket makes no sense.");
+    goto rollback;
+  }
+#endif
+
   if (running_tor) {
     int n_ports=0;
     /* We need to set the connection limit before we can open the listeners. */
@@ -6034,22 +6050,87 @@ parse_port_config(smartlist_t *out,
 
 /** Parse a list of config_line_t for an AF_UNIX unix socket listener option
  * from <b>cfg</b> and add them to <b>out</b>.  No fancy options are
- * supported: the line contains nothing but the path to the AF_UNIX socket. */
+ * supported: the line contains nothing but the path to the AF_UNIX socket.
+ * We support a *Socket 0 syntax to explicitly disable if we enable by
+ * default.  To use this, pass a non-NULL list containing the default
+ * paths into this function as the 2nd parameter, and if no config lines at all
+ * are present they will be added to the output list.  If the only config line
+ * present is '0' the input list will be unmodified.
+ */
 static int
-parse_unix_socket_config(smartlist_t *out, const config_line_t *cfg,
-                         int listener_type)
+parse_unix_socket_config(smartlist_t *out, smartlist_t *defaults,
+                         const config_line_t *cfg, int listener_type)
 {
+  /* We can say things like SocksSocket 0 or ControlSocket 0 to explicitly
+   * disable this feature; use this to track if we've seen a disable line
+   */
+
+  int unix_socket_disable = 0;
+  size_t len;
+  smartlist_t *ports_to_add = NULL;
 
   if (!out)
     return 0;
 
+  ports_to_add = smartlist_new();
+
   for ( ; cfg; cfg = cfg->next) {
-    size_t len = strlen(cfg->value);
-    port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1);
-    port->is_unix_addr = 1;
-    memcpy(port->unix_addr, cfg->value, len+1);
-    port->type = listener_type;
-    smartlist_add(out, port);
+    if (strcmp(cfg->value, "0") != 0) {
+      /* We have a non-disable; add it */
+      len = strlen(cfg->value);
+      port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1);
+      port->is_unix_addr = 1;
+      memcpy(port->unix_addr, cfg->value, len+1);
+      port->type = listener_type;
+      if (listener_type == CONN_TYPE_AP_LISTENER) {
+        /* Some more bits to twiddle for this case
+         *
+         * XXX this should support parsing the same options
+         * parse_port_config() does, and probably that code should be
+         * factored out into a function we can call from here.  For
+         * now, some reasonable defaults.
+         */
+
+        port->ipv4_traffic = 1;
+        port->ipv6_traffic = 1;
+        port->cache_ipv4_answers = 1;
+        port->cache_ipv6_answers = 1;
+      }
+      smartlist_add(ports_to_add, port);
+    } else {
+      /* Keep track that we've seen a disable */
+      unix_socket_disable = 1;
+    }
+  }
+
+  if (unix_socket_disable) {
+    if (smartlist_len(ports_to_add) > 0) {
+      /* We saw a disable line and a path; bad news */
+      SMARTLIST_FOREACH(ports_to_add, port_cfg_t *, port, tor_free(port));
+      smartlist_free(ports_to_add);
+      return -1;
+    }
+    /* else we have a disable and nothing else, so add nothing to out */
+  } else {
+    /* No disable; do we have any ports to add that we parsed? */
+    if (smartlist_len(ports_to_add) > 0) {
+      SMARTLIST_FOREACH_BEGIN(ports_to_add, port_cfg_t *, port) {
+        smartlist_add(out, port);
+      } SMARTLIST_FOREACH_END(port);
+    } else if (defaults != NULL && smartlist_len(defaults) > 0) {
+      /* No, but we have some defaults to copy */
+      SMARTLIST_FOREACH_BEGIN(defaults, const port_cfg_t *, defport) {
+        tor_assert(defport->is_unix_addr);
+        tor_assert(defport->unix_addr);
+        len = sizeof(port_cfg_t) + strlen(defport->unix_addr) + 1;
+        port_cfg_t *port = tor_malloc_zero(len);
+        memcpy(port, defport, len);
+        smartlist_add(out, port);
+      } SMARTLIST_FOREACH_END(defport);
+    }
+
+    /* Free the temporary smartlist we used */
+    smartlist_free(ports_to_add);
   }
 
   return 0;
@@ -6143,12 +6224,19 @@ parse_ports(or_options_t *options, int validate_only,
                         "configuration");
       goto err;
     }
-    if (parse_unix_socket_config(ports,
+
+    if (parse_unix_socket_config(ports, NULL,
                                  options->ControlSocket,
                                  CONN_TYPE_CONTROL_LISTENER) < 0) {
       *msg = tor_strdup("Invalid ControlSocket configuration");
       goto err;
     }
+    if (parse_unix_socket_config(ports, NULL,
+                                 options->SocksSocket,
+                                 CONN_TYPE_AP_LISTENER) < 0) {
+      *msg = tor_strdup("Invalid SocksSocket configuration");
+      goto err;
+    }
   }
   if (! options->ClientOnly) {
     if (parse_port_config(ports,
@@ -6192,6 +6280,8 @@ parse_ports(or_options_t *options, int validate_only,
     !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER);
   options->SocksPort_set =
     !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
+  options->SocksSocket_set =
+    !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
   options->TransPort_set =
     !! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER);
   options->NATDPort_set =

+ 117 - 29
src/or/connection.c

@@ -308,6 +308,8 @@ entry_connection_new(int type, int socket_family)
     entry_conn->ipv4_traffic_ok = 1;
   else if (socket_family == AF_INET6)
     entry_conn->ipv6_traffic_ok = 1;
+  else if (socket_family == AF_UNIX)
+    entry_conn->is_socks_socket = 1;
   return entry_conn;
 }
 
@@ -516,9 +518,10 @@ connection_free_(connection_t *conn)
     buf_free(conn->outbuf);
   } else {
     if (conn->socket_family == AF_UNIX) {
-      /* For now only control ports can be Unix domain sockets
+      /* For now only control and SOCKS ports can be Unix domain sockets
        * and listeners at the same time */
-      tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
+      tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER ||
+                 conn->type == CONN_TYPE_AP_LISTENER);
 
       if (unlink(conn->address) < 0 && errno != ENOENT) {
         log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
@@ -915,13 +918,57 @@ warn_too_many_conns(void)
 }
 
 #ifdef HAVE_SYS_UN_H
+
+#define UNIX_SOCKET_PURPOSE_CONTROL_SOCKET 0
+#define UNIX_SOCKET_PURPOSE_SOCKS_SOCKET 1
+
+/** Check if the purpose isn't one of the ones we know what to do with */
+
+static int
+is_valid_unix_socket_purpose(int purpose)
+{
+  int valid = 0;
+
+  switch (purpose) {
+    case UNIX_SOCKET_PURPOSE_CONTROL_SOCKET:
+    case UNIX_SOCKET_PURPOSE_SOCKS_SOCKET:
+      valid = 1;
+      break;
+  }
+
+  return valid;
+}
+
+/** Return a string description of a unix socket purpose */
+static const char *
+unix_socket_purpose_to_string(int purpose)
+{
+  const char *s = "unknown-purpose socket";
+
+  switch (purpose) {
+    case UNIX_SOCKET_PURPOSE_CONTROL_SOCKET:
+      s = "control socket";
+      break;
+    case UNIX_SOCKET_PURPOSE_SOCKS_SOCKET:
+      s = "SOCKS socket";
+      break;
+  }
+
+  return s;
+}
+
 /** Check whether we should be willing to open an AF_UNIX socket in
  * <b>path</b>.  Return 0 if we should go ahead and -1 if we shouldn't. */
 static int
-check_location_for_unix_socket(const or_options_t *options, const char *path)
+check_location_for_unix_socket(const or_options_t *options, const char *path,
+                               int purpose)
 {
   int r = -1;
-  char *p = tor_strdup(path);
+  char *p = NULL;
+
+  tor_assert(is_valid_unix_socket_purpose(purpose));
+
+  p = tor_strdup(path);
   cpd_check_t flags = CPD_CHECK_MODE_ONLY;
   if (get_parent_directory(p)<0 || p[0] != '/') {
     log_warn(LD_GENERAL, "Bad unix socket address '%s'.  Tor does not support "
@@ -929,18 +976,23 @@ check_location_for_unix_socket(const or_options_t *options, const char *path)
     goto done;
   }
 
-  if (options->ControlSocketsGroupWritable)
+  if ((purpose == UNIX_SOCKET_PURPOSE_CONTROL_SOCKET &&
+       options->ControlSocketsGroupWritable) ||
+      (purpose == UNIX_SOCKET_PURPOSE_SOCKS_SOCKET &&
+       options->SocksSocketsGroupWritable)) {
     flags |= CPD_GROUP_OK;
+  }
 
   if (check_private_dir(p, flags, options->User) < 0) {
     char *escpath, *escdir;
     escpath = esc_for_log(path);
     escdir = esc_for_log(p);
-    log_warn(LD_GENERAL, "Before Tor can create a control socket in %s, the "
-             "directory %s needs to exist, and to be accessible only by the "
-             "user%s account that is running Tor.  (On some Unix systems, "
-             "anybody who can list a socket can connect to it, so Tor is "
-             "being careful.)", escpath, escdir,
+    log_warn(LD_GENERAL, "Before Tor can create a %s in %s, the directory "
+             "%s needs to exist, and to be accessible only by the user%s "
+             "account that is running Tor.  (On some Unix systems, anybody "
+             "who can list a socket can connect to it, so Tor is being "
+             "careful.)",
+             unix_socket_purpose_to_string(purpose), escpath, escdir,
              options->ControlSocketsGroupWritable ? " and group" : "");
     tor_free(escpath);
     tor_free(escdir);
@@ -1030,8 +1082,8 @@ connection_listener_new(const struct sockaddr *listensockaddr,
 
   if (listensockaddr->sa_family == AF_INET ||
       listensockaddr->sa_family == AF_INET6) {
-    int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
-    if (is_tcp)
+    int is_stream = (type != CONN_TYPE_AP_DNS_LISTENER);
+    if (is_stream)
       start_reading = 1;
 
     tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
@@ -1040,10 +1092,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
                conn_type_to_string(type), fmt_addrport(&addr, usePort));
 
     s = tor_open_socket_nonblocking(tor_addr_family(&addr),
-                        is_tcp ? SOCK_STREAM : SOCK_DGRAM,
-                        is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
+      is_stream ? SOCK_STREAM : SOCK_DGRAM,
+      is_stream ? IPPROTO_TCP: IPPROTO_UDP);
     if (!SOCKET_OK(s)) {
-      log_warn(LD_NET,"Socket creation failed: %s",
+      log_warn(LD_NET, "Socket creation failed: %s",
                tor_socket_strerror(tor_socket_errno(-1)));
       goto err;
     }
@@ -1100,7 +1152,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
       goto err;
     }
 
-    if (is_tcp) {
+    if (is_stream) {
       if (tor_listen(s) < 0) {
         log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
                  tor_socket_strerror(tor_socket_errno(s)));
@@ -1123,15 +1175,25 @@ connection_listener_new(const struct sockaddr *listensockaddr,
       tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort);
     }
 #ifdef HAVE_SYS_UN_H
+  /*
+   * AF_UNIX generic setup stuff (this covers both CONN_TYPE_CONTROL_LISTENER
+   * and CONN_TYPE_AP_LISTENER cases)
+   */
   } else if (listensockaddr->sa_family == AF_UNIX) {
+    /* We want to start reading for both AF_UNIX cases */
     start_reading = 1;
 
-    /* For now only control ports can be Unix domain sockets
+    /* For now only control ports or SOCKS ports can be Unix domain sockets
      * and listeners at the same time */
-    tor_assert(type == CONN_TYPE_CONTROL_LISTENER);
+    tor_assert(type == CONN_TYPE_CONTROL_LISTENER ||
+               type == CONN_TYPE_AP_LISTENER);
 
-    if (check_location_for_unix_socket(options, address) < 0)
-      goto err;
+    if (check_location_for_unix_socket(options, address,
+          (type == CONN_TYPE_CONTROL_LISTENER) ?
+           UNIX_SOCKET_PURPOSE_CONTROL_SOCKET :
+           UNIX_SOCKET_PURPOSE_SOCKS_SOCKET) < 0) {
+        goto err;
+    }
 
     log_notice(LD_NET, "Opening %s on %s",
                conn_type_to_string(type), address);
@@ -1143,17 +1205,20 @@ connection_listener_new(const struct sockaddr *listensockaddr,
                        strerror(errno));
       goto err;
     }
+
     s = tor_open_socket_nonblocking(AF_UNIX, SOCK_STREAM, 0);
     if (! SOCKET_OK(s)) {
       log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
       goto err;
     }
 
-    if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) {
+    if (bind(s, listensockaddr,
+             (socklen_t)sizeof(struct sockaddr_un)) == -1) {
       log_warn(LD_NET,"Bind to %s failed: %s.", address,
                tor_socket_strerror(tor_socket_errno(s)));
       goto err;
     }
+
 #ifdef HAVE_PWD_H
     if (options->User) {
       pw = tor_getpwnam(options->User);
@@ -1168,13 +1233,27 @@ connection_listener_new(const struct sockaddr *listensockaddr,
       }
     }
 #endif
-    if (options->ControlSocketsGroupWritable) {
+
+    if ((type == CONN_TYPE_CONTROL_LISTENER &&
+         options->ControlSocketsGroupWritable) ||
+        (type == CONN_TYPE_AP_LISTENER &&
+         options->SocksSocketsGroupWritable)) {
       /* We need to use chmod; fchmod doesn't work on sockets on all
        * platforms. */
       if (chmod(address, 0660) < 0) {
         log_warn(LD_FS,"Unable to make %s group-writable.", address);
         goto err;
       }
+    } else if ((type == CONN_TYPE_CONTROL_LISTENER &&
+                !(options->ControlSocketsGroupWritable)) ||
+               (type == CONN_TYPE_AP_LISTENER &&
+                !(options->SocksSocketsGroupWritable))) {
+      /* We need to use chmod; fchmod doesn't work on sockets on all
+       * platforms. */
+      if (chmod(address, 0600) < 0) {
+        log_warn(LD_FS,"Unable to make %s group-writable.", address);
+        goto err;
+      }
     }
 
     if (listen(s, SOMAXCONN) < 0) {
@@ -1182,8 +1261,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
                tor_socket_strerror(tor_socket_errno(s)));
       goto err;
     }
-#else
-    (void)options;
 #endif /* HAVE_SYS_UN_H */
   } else {
     log_err(LD_BUG, "Got unexpected address family %d.",
@@ -1294,6 +1371,8 @@ check_sockaddr(const struct sockaddr *sa, int len, int level)
              "Address for new connection has address/port equal to zero.");
       ok = 0;
     }
+  } else if (sa->sa_family == AF_UNIX) {
+    ok = 1;
   } else {
     ok = 0;
   }
@@ -1378,7 +1457,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
     return 0;
   }
 
-  if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6) {
+  if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6 ||
+     (conn->socket_family == AF_UNIX && new_type == CONN_TYPE_AP)) {
     tor_addr_t addr;
     uint16_t port;
     if (check_sockaddr(remote, remotelen, LOG_INFO)<0) {
@@ -1419,7 +1499,16 @@ connection_handle_listener_read(connection_t *conn, int new_type)
     newconn->port = port;
     newconn->address = tor_dup_addr(&addr);
 
-    if (new_type == CONN_TYPE_AP) {
+    if (new_type == CONN_TYPE_AP && conn->socket_family != AF_UNIX) {
+      log_notice(LD_NET, "New SOCKS connection opened from %s.",
+                 fmt_and_decorate_addr(&addr));
+      TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth =
+        TO_LISTENER_CONN(conn)->socks_prefer_no_auth;
+    }
+    if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
+      newconn->port = 0;
+      newconn->address = tor_strdup(conn->address);
+      log_info(LD_NET, "New SOCKS SocksSocket connection opened");
       TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth =
         TO_LISTENER_CONN(conn)->socks_prefer_no_auth;
     }
@@ -1428,9 +1517,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
                  fmt_and_decorate_addr(&addr));
     }
 
-  } else if (conn->socket_family == AF_UNIX) {
-    /* For now only control ports can be Unix domain sockets
-     * and listeners at the same time */
+  } else if (conn->socket_family == AF_UNIX && conn->type != CONN_TYPE_AP) {
     tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
     tor_assert(new_type == CONN_TYPE_CONTROL);
     log_notice(LD_CONTROL, "New control connection opened.");
@@ -2392,6 +2479,7 @@ connection_is_rate_limited(connection_t *conn)
     return 0; /* Internal connection */
   else if (! options->CountPrivateBandwidth &&
            (tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */
+            tor_addr_family(&conn->addr) == AF_UNIX ||   /* no address */
             tor_addr_is_internal(&conn->addr, 0)))
     return 0; /* Internal address */
   else

+ 4 - 0
src/or/main.c

@@ -391,6 +391,10 @@ connection_remove(connection_t *conn)
             (int)conn->s, conn_type_to_string(conn->type),
             smartlist_len(connection_array));
 
+  if (conn->type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
+    log_info(LD_NET, "Closing SOCKS SocksSocket connection");
+  }
+
   control_event_conn_bandwidth(conn);
 
   tor_assert(conn->conn_array_index >= 0);

+ 8 - 0
src/or/or.h

@@ -1702,6 +1702,9 @@ typedef struct entry_connection_t {
    * do we prefer IPv6? */
   unsigned int prefer_ipv6_virtaddr : 1;
 
+  /** Are we a socks SocksSocket listener? */
+  unsigned int is_socks_socket:1;
+
 } entry_connection_t;
 
 typedef enum {
@@ -3528,6 +3531,10 @@ typedef struct {
                                  * for control connections. */
 
   int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */
+  config_line_t *SocksSocket; /**< List of Unix Domain Sockets to listen on
+                                 * for SOCKS connections. */
+
+  int SocksSocketsGroupWritable; /**< Boolean: Are SOCKS sockets g+rw? */
   /** Ports to listen on for directory connections. */
   config_line_t *DirPort_lines;
   config_line_t *DNSPort_lines; /**< Ports to listen on for DNS requests. */
@@ -3550,6 +3557,7 @@ typedef struct {
    */
   unsigned int ORPort_set : 1;
   unsigned int SocksPort_set : 1;
+  unsigned int SocksSocket_set : 1;
   unsigned int TransPort_set : 1;
   unsigned int NATDPort_set : 1;
   unsigned int ControlPort_set : 1;

+ 2 - 2
src/or/relay.c

@@ -1327,8 +1327,8 @@ connection_edge_process_relay_cell_not_open(
         return 0;
       }
 
-      if ((family == AF_INET && ! entry_conn->ipv4_traffic_ok) ||
-          (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok)) {
+      if (((family == AF_INET && ! entry_conn->ipv4_traffic_ok) ||
+          (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok))) {
         log_fn(LOG_PROTOCOL_WARN, LD_APP,
                "Got a connected cell to %s with unsupported address family."
                " Closing.", fmt_addr(&addr));