From 03d6a31716dcdddd164391c7910cb3eb6f0083bc Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Thu, 22 Jan 2015 02:22:33 +0000 Subject: [PATCH 1/6] Groundwork for AF_UNIX hidden services in rendservice.c --- src/or/rendservice.c | 60 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 5a12d074ac..2e0f83c6f3 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -66,9 +66,16 @@ static ssize_t rend_service_parse_intro_for_v3( * a real port on some IP. */ typedef struct rend_service_port_config_t { + /* The incoming HS virtual port we're mapping */ uint16_t virtual_port; + /* Is this an AF_UNIX port? */ + unsigned int is_unix_addr:1; + /* The outgoing TCP port to use, if !is_unix_addr */ uint16_t real_port; + /* The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */ tor_addr_t real_addr; + /* The socket path to connect to, if is_unix_addr */ + char unix_addr[FLEXIBLE_ARRAY_MEMBER]; } rend_service_port_config_t; /** Try to maintain this many intro points per service by default. */ @@ -279,8 +286,24 @@ rend_add_service(rend_service_t *service) service->directory); for (i = 0; i < smartlist_len(service->ports); ++i) { p = smartlist_get(service->ports, i); - log_debug(LD_REND,"Service maps port %d to %s", - p->virtual_port, fmt_addrport(&p->real_addr, p->real_port)); + if (!(p->is_unix_addr)) { + log_debug(LD_REND, + "Service maps port %d to %s", + p->virtual_port, + fmt_addrport(&p->real_addr, p->real_port)); + } else { +#ifdef HAVE_SYS_UN_H + log_debug(LD_REND, + "Service maps port %d to socket at \"%s\"", + p->virtual_port, p->unix_addr); +#else + log_debug(LD_REND, + "Service maps port %d to an AF_UNIX socket, but we " + "have no AF_UNIX support on this platform. This is " + "probably a bug.", + p->virtual_port); +#endif /* defined(HAVE_SYS_UN_H) */ + } } } } @@ -345,6 +368,8 @@ parse_port_config(const char *string) result = tor_malloc(sizeof(rend_service_port_config_t)); result->virtual_port = virtport; + /* TODO actually support AF_UNIX here */ + result->is_unix_addr = 0; result->real_port = realport; tor_addr_copy(&result->real_addr, &addr); err: @@ -3416,6 +3441,7 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; smartlist_t *matching_ports; rend_service_port_config_t *chosen_port; + int unix_addrs; tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); tor_assert(circ->rend_data); @@ -3431,10 +3457,19 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, return -2; } matching_ports = smartlist_new(); + unix_addrs = 0; SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p, { + /* + * TODO don't just ignore AF_UNIX ports, but set up edge_connection_t + * properly to use them. + */ if (conn->base_.port == p->virtual_port) { - smartlist_add(matching_ports, p); + if (!(p->is_unix_addr)) { + smartlist_add(matching_ports, p); + } else { + ++unix_addrs; + } } }); chosen_port = smartlist_choose(matching_ports); @@ -3444,8 +3479,23 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, conn->base_.port = chosen_port->real_port; return 0; } - log_info(LD_REND, "No virtual port mapping exists for port %d on service %s", - conn->base_.port,serviceid); + if (!unix_addrs) { + log_info(LD_REND, + "No virtual port mapping exists for port %d on service %s", + conn->base_.port, serviceid); + } else { +#ifdef HAVE_SYS_UN_H + log_info(LD_REND, + "Only AF_UNIX virtual port mappings exists for port %d " + "on service %s, and support is not yet implemented", + conn->base_.port, serviceid); +#else + log_info(LD_REND, + "Only AF_UNIX virtual port mappings exists for port %d " + "on service %s, and support is not available on this platform", + conn->base_.port, serviceid); +#endif /* defined(HAVE_SYS_UN_H) */ + } if (service->allow_unknown_ports) return -1; else From 6564291601540bf61c1ca3294b6c22f0c5021a20 Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Fri, 23 Jan 2015 14:45:12 +0000 Subject: [PATCH 2/6] Handle config options for AF_UNIX hidden services rendservice.c --- src/or/rendservice.c | 58 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 2e0f83c6f3..fac782bd9f 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -308,10 +308,26 @@ rend_add_service(rend_service_t *service) } } +/** Return a new rend_service_port_config_t with its path set to + * socket_path or empty if socket_path is NULL */ +static rend_service_port_config_t * +rend_service_port_config_new(const char *socket_path) +{ + if (!socket_path) + return tor_malloc_zero(sizeof(rend_service_port_config_t)); + + const size_t pathlen = strlen(socket_path) + 1; + rend_service_port_config_t *conf = + tor_malloc_zero(sizeof(rend_service_port_config_t) + pathlen); + memcpy(conf->unix_addr, socket_path, pathlen); + conf->is_unix_addr = 1; + return conf; +} + /** Parses a real-port to virtual-port mapping and returns a new * rend_service_port_config_t. * - * The format is: VirtualPort (IP|RealPort|IP:RealPort)? + * The format is: VirtualPort (IP|RealPort|IP:RealPort|'socket':path)? * * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort. */ @@ -325,6 +341,9 @@ parse_port_config(const char *string) tor_addr_t addr; const char *addrport; rend_service_port_config_t *result = NULL; + const char *socket_prefix = "socket:"; + unsigned int is_unix_addr = 0; + char *socket_path = NULL; sl = smartlist_new(); smartlist_split_string(sl, string, " ", @@ -347,7 +366,26 @@ parse_port_config(const char *string) tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */ } else { addrport = smartlist_get(sl,1); - if (strchr(addrport, ':') || strchr(addrport, '.')) { + /* If it starts with socket:, try to parse it as a socket path */ + if (!strcmpstart(addrport, socket_prefix)) { + if (strlen(addrport + strlen(socket_prefix)) > 0) { +#ifdef HAVE_SYS_UN_H + is_unix_addr = 1; + socket_path = tor_strdup(addrport + strlen(socket_prefix)); +#else + log_warn(LD_CONFIG, + "Hidden service port configuration %s is for an AF_UNIX " + "socket, but we have no support available on this platform", + escaped(addrport)); + goto err; +#endif /* defined(HAVE_SYS_UN_H) */ + } else { + log_warn(LD_CONFIG, + "Empty socket path in hidden service port configuration."); + goto err; + } + } else if (strchr(addrport, ':') || strchr(addrport, '.')) { + /* else try it as an IP:port pair if it has a : or . in it */ if (tor_addr_port_lookup(addrport, &addr, &p)<0) { log_warn(LD_CONFIG,"Unparseable address in hidden service port " "configuration."); @@ -366,15 +404,21 @@ parse_port_config(const char *string) } } - result = tor_malloc(sizeof(rend_service_port_config_t)); + /* Allow room for unix_addr */ + result = rend_service_port_config_new(socket_path); result->virtual_port = virtport; - /* TODO actually support AF_UNIX here */ - result->is_unix_addr = 0; - result->real_port = realport; - tor_addr_copy(&result->real_addr, &addr); + result->is_unix_addr = is_unix_addr; + if (!is_unix_addr) { + result->real_port = realport; + tor_addr_copy(&result->real_addr, &addr); + result->unix_addr[0] = '\0'; + } + err: SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); smartlist_free(sl); + if (socket_path) tor_free(socket_path); + return result; } From ca5ba2956bcd4b5ee1e526ccf5914f52fe6e6d51 Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Sat, 24 Jan 2015 17:31:12 +0000 Subject: [PATCH 3/6] Support connection_exit_connect() to AF_UNIX sockets --- src/or/connection.c | 220 ++++++++++++++++++++++++++------------- src/or/connection.h | 7 ++ src/or/connection_edge.c | 36 +++++-- 3 files changed, 181 insertions(+), 82 deletions(-) diff --git a/src/or/connection.c b/src/or/connection.c index 97fdee732e..f26ada096b 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -56,6 +56,11 @@ #include #endif +#ifdef HAVE_SYS_UN_H +#include +#include +#endif + static connection_t *connection_listener_new( const struct sockaddr *listensockaddr, socklen_t listensocklen, int type, @@ -1585,6 +1590,98 @@ connection_init_accepted_conn(connection_t *conn, return 0; } + +static int +connection_connect_sockaddr(connection_t *conn, + const struct sockaddr *sa, + socklen_t sa_len, + const struct sockaddr *bindaddr, + socklen_t bindaddr_len, + int *socket_error) +{ + tor_socket_t s; + int inprogress = 0; + const or_options_t *options = get_options(); + int protocol_family; + + tor_assert(conn); + tor_assert(sa); + tor_assert(socket_error); + + if (get_n_open_sockets() >= get_options()->ConnLimit_-1) { + warn_too_many_conns(); + *socket_error = SOCK_ERRNO(ENOBUFS); + return -1; + } + + protocol_family = sa->sa_family; + + if (get_options()->DisableNetwork) { + /* We should never even try to connect anyplace if DisableNetwork is set. + * Warn if we do, and refuse to make the connection. */ + static ratelim_t disablenet_violated = RATELIM_INIT(30*60); + *socket_error = SOCK_ERRNO(ENETUNREACH); + log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG, + "Tried to open a socket with DisableNetwork set."); + tor_fragile_assert(); + return -1; + } + + s = tor_open_socket_nonblocking(protocol_family, SOCK_STREAM, 0); + if (! SOCKET_OK(s)) { + *socket_error = tor_socket_errno(-1); + log_warn(LD_NET,"Error creating network socket: %s", + tor_socket_strerror(*socket_error)); + return -1; + } + + if (make_socket_reuseable(s) < 0) { + log_warn(LD_NET, "Error setting SO_REUSEADDR flag on new connection: %s", + tor_socket_strerror(errno)); + } + + if (bindaddr && bind(s, bindaddr, bindaddr_len) < 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; + } + + tor_assert(options); + if (options->ConstrainedSockets) + set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize); + + if (connect(s, sa, sa_len) < 0) { + int e = tor_socket_errno(s); + if (!ERRNO_IS_CONN_EINPROGRESS(e)) { + /* yuck. kill it. */ + *socket_error = e; + log_info(LD_NET, + "connect() to socket failed: %s", + tor_socket_strerror(e)); + tor_close_socket(s); + return -1; + } else { + inprogress = 1; + } + } + + /* it succeeded. we're connected. */ + log_fn(inprogress ? LOG_DEBUG : LOG_INFO, LD_NET, + "Connection to socket %s (sock "TOR_SOCKET_T_FORMAT").", + inprogress ? "in progress" : "established", s); + conn->s = s; + if (connection_add_connecting(conn) < 0) { + /* no space, forget it */ + *socket_error = SOCK_ERRNO(ENOBUFS); + return -1; + } + return inprogress ? 0 : 1; + +} + + /** Take conn, make a nonblocking socket; try to connect to * addr:port (they arrive in *host order*). If fail, return -1 and if * applicable put your best guess about errno into *socket_error. @@ -1598,49 +1695,19 @@ int connection_connect(connection_t *conn, const char *address, const tor_addr_t *addr, uint16_t port, int *socket_error) { - tor_socket_t s; - int inprogress = 0; struct sockaddr_storage addrbuf; + struct sockaddr_storage bind_addr_ss; + struct sockaddr *bind_addr = NULL; struct sockaddr *dest_addr; - int dest_addr_len; + int dest_addr_len, bind_addr_len = 0; const or_options_t *options = get_options(); int protocol_family; - if (get_n_open_sockets() >= get_options()->ConnLimit_-1) { - warn_too_many_conns(); - *socket_error = SOCK_ERRNO(ENOBUFS); - return -1; - } - if (tor_addr_family(addr) == AF_INET6) protocol_family = PF_INET6; else protocol_family = PF_INET; - if (get_options()->DisableNetwork) { - /* We should never even try to connect anyplace if DisableNetwork is set. - * Warn if we do, and refuse to make the connection. */ - static ratelim_t disablenet_violated = RATELIM_INIT(30*60); - *socket_error = SOCK_ERRNO(ENETUNREACH); - log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG, - "Tried to open a socket with DisableNetwork set."); - tor_fragile_assert(); - return -1; - } - - s = tor_open_socket_nonblocking(protocol_family,SOCK_STREAM,IPPROTO_TCP); - if (! SOCKET_OK(s)) { - *socket_error = tor_socket_errno(-1); - log_warn(LD_NET,"Error creating network socket: %s", - tor_socket_strerror(*socket_error)); - return -1; - } - - if (make_socket_reuseable(s) < 0) { - log_warn(LD_NET, "Error setting SO_REUSEADDR flag on new connection: %s", - tor_socket_strerror(errno)); - } - if (!tor_addr_is_loopback(addr)) { const tor_addr_t *ext_addr = NULL; if (protocol_family == AF_INET && @@ -1650,33 +1717,21 @@ connection_connect(connection_t *conn, const char *address, !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)); + memset(&bind_addr_ss, 0, sizeof(bind_addr_ss)); + bind_addr_len = tor_addr_to_sockaddr(ext_addr, 0, + (struct sockaddr *) &bind_addr_ss, + sizeof(bind_addr_ss)); if (ext_addr_len == 0) { log_warn(LD_NET, "Error converting OutboundBindAddress %s into sockaddr. " "Ignoring.", fmt_and_decorate_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_and_decorate_addr(ext_addr), - tor_socket_strerror(*socket_error)); - tor_close_socket(s); - return -1; - } + bind_addr = (struct sockaddr *)&bind_addr_ss; } } } - tor_assert(options); - if (options->ConstrainedSockets) - set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize); - memset(&addrbuf,0,sizeof(addrbuf)); dest_addr = (struct sockaddr*) &addrbuf; dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf)); @@ -1685,36 +1740,51 @@ connection_connect(connection_t *conn, const char *address, log_debug(LD_NET, "Connecting to %s:%u.", escaped_safe_str_client(address), port); - if (connect(s, dest_addr, (socklen_t)dest_addr_len) < 0) { - int e = tor_socket_errno(s); - if (!ERRNO_IS_CONN_EINPROGRESS(e)) { - /* yuck. kill it. */ - *socket_error = e; - log_info(LD_NET, - "connect() to %s:%u failed: %s", - escaped_safe_str_client(address), - port, tor_socket_strerror(e)); - tor_close_socket(s); - return -1; - } else { - inprogress = 1; - } - } + return connection_connect_sockaddr(conn, dest_addr, dest_addr_len, + bind_addr, bind_addr_len, socket_error); +} - /* it succeeded. we're connected. */ - log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET, - "Connection to %s:%u %s (sock "TOR_SOCKET_T_FORMAT").", - escaped_safe_str_client(address), - port, inprogress?"in progress":"established", s); - conn->s = s; - if (connection_add_connecting(conn) < 0) { - /* no space, forget it */ - *socket_error = SOCK_ERRNO(ENOBUFS); +#ifdef HAVE_SYS_UN_H + +/** Take conn, make a nonblocking socket; try to connect to + * an AF_UNIX socket at socket_path. If fail, return -1 and if applicable + * put your best guess about errno into *socket_error. Else assign s + * to conn-\>s: if connected return 1, if EAGAIN return 0. + * + * On success, add conn to the list of polled connections. + */ +int +connection_connect_unix(connection_t *conn, const char *socket_path, + int *socket_error) +{ + struct sockaddr_un dest_addr; + + tor_assert(socket_path); + + /* Check that we'll be able to fit it into dest_addr later */ + if (strlen(socket_path) + 1 > sizeof(dest_addr.sun_path)) { + log_warn(LD_NET, + "Path %s is too long for an AF_UNIX socket\n", + escaped_safe_str_client(socket_path)); + *socket_error = SOCK_ERRNO(ENAMETOOLONG); return -1; } - return inprogress ? 0 : 1; + + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.sun_family = AF_UNIX; + strlcpy(dest_addr.sun_path, socket_path, sizeof(dest_addr.sun_path)); + + log_debug(LD_NET, + "Connecting to AF_UNIX socket at %s.", + escaped_safe_str_client(socket_path)); + + return connection_connect_sockaddr(conn, + (struct sockaddr *)&dest_addr, sizeof(dest_addr), + NULL, 0, socket_error); } +#endif /* defined(HAVE_SYS_UN_H) */ + /** Convert state number to string representation for logging purposes. */ static const char * diff --git a/src/or/connection.h b/src/or/connection.h index ce6ed284c1..50bea51e5b 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -89,6 +89,13 @@ int connection_connect(connection_t *conn, const char *address, const tor_addr_t *addr, uint16_t port, int *socket_error); +#ifdef HAVE_SYS_UN_H + +int connection_connect_unix(connection_t *conn, const char *socket_path, + int *socket_error); + +#endif /* defined(HAVE_SYS_UN_H) */ + /** Maximum size of information that we can fit into SOCKS5 username or password fields. */ #define MAX_SOCKS5_AUTH_FIELD_SIZE 255 diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index f541249992..9690653d59 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -2940,7 +2940,7 @@ connection_exit_connect(edge_connection_t *edge_conn) const tor_addr_t *addr; uint16_t port; connection_t *conn = TO_CONN(edge_conn); - int socket_error = 0; + int socket_error = 0, result; if ( (!connection_edge_is_rendezvous_stream(edge_conn) && router_compare_to_my_exit_policy(&edge_conn->base_.addr, @@ -2955,14 +2955,36 @@ connection_exit_connect(edge_connection_t *edge_conn) return; } - addr = &conn->addr; - port = conn->port; +#ifdef HAVE_SYS_UN_H + if (conn->socket_family != AF_UNIX) { +#else + { +#endif /* defined(HAVE_SYS_UN_H) */ + addr = &conn->addr; + port = conn->port; - if (tor_addr_family(addr) == AF_INET6) - conn->socket_family = AF_INET6; + if (tor_addr_family(addr) == AF_INET6) + conn->socket_family = AF_INET6; - log_debug(LD_EXIT,"about to try connecting"); - switch (connection_connect(conn, conn->address, addr, port, &socket_error)) { + log_debug(LD_EXIT, "about to try connecting"); + result = connection_connect(conn, conn->address, + addr, port, &socket_error); +#ifdef HAVE_SYS_UN_H + } else { + /* + * In the AF_UNIX case, we expect to have already had conn->port = 1, + * tor_addr_make_unspec(conn->addr) (cf. the way we mark in the incoming + * case in connection_handle_listener_read()), and conn->address should + * have the socket path to connect to. + */ + tor_assert(conn->address && strlen(conn->address) > 0); + + log_debug(LD_EXIT, "about to try connecting"); + result = connection_connect_unix(conn, conn->address, &socket_error); +#endif /* defined(HAVE_SYS_UN_H) */ + } + + switch (result) { case -1: { int reason = errno_to_stream_end_reason(socket_error); connection_edge_end(edge_conn, reason); From bce824a9ad10b9a9d6ecc8363084ca3aef4e636a Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Tue, 27 Jan 2015 13:12:40 +0000 Subject: [PATCH 4/6] Actually make connections to HSes on AF_UNIX sockets --- src/or/rendservice.c | 67 +++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/or/rendservice.c b/src/or/rendservice.c index fac782bd9f..920a8cfe11 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -3485,7 +3485,9 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; smartlist_t *matching_ports; rend_service_port_config_t *chosen_port; - int unix_addrs; +#ifndef HAVE_SYS_UN_H + int unix_addrs_rejected; +#endif /* !defined(HAVE_SYS_UN_H) */ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); tor_assert(circ->rend_data); @@ -3501,45 +3503,58 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, return -2; } matching_ports = smartlist_new(); - unix_addrs = 0; +#ifndef HAVE_SYS_UN_H + unix_addrs_rejected = 0; +#endif /* !defined(HAVE_SYS_UN_H) */ SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p, { - /* - * TODO don't just ignore AF_UNIX ports, but set up edge_connection_t - * properly to use them. - */ if (conn->base_.port == p->virtual_port) { +#ifdef HAVE_SYS_UN_H + smartlist_add(matching_ports, p); +#else if (!(p->is_unix_addr)) { smartlist_add(matching_ports, p); } else { - ++unix_addrs; + if (unix_addrs_rejected == 0) { + /* If we have no support, bitch about it for just the first one */ + log_warn(LD_REND, + "Saw AF_UNIX virtual port mapping for port %d on service " + "%s, which is unsupported on this platform. Ignoring it.", + conn->base_.port, serviceid); + } + ++unix_addrs_rejected; } +#endif /* defined(HAVE_SYS_UN_H) */ } }); chosen_port = smartlist_choose(matching_ports); smartlist_free(matching_ports); if (chosen_port) { - tor_addr_copy(&conn->base_.addr, &chosen_port->real_addr); - conn->base_.port = chosen_port->real_port; +#ifdef HAVE_SYS_UN_H + if (!(chosen_port->is_unix_addr)) { +#else + { +#endif /* defined(HAVE_SYS_UN_H) */ + /* Get a non-AF_UNIX connection ready for connection_exit_connect() */ + tor_addr_copy(&conn->base_.addr, &chosen_port->real_addr); + conn->base_.port = chosen_port->real_port; +#ifdef HAVE_SYS_UN_H + } else { + /* Get an AF_UNIX connection ready for connection_exit_connect() */ + conn->base_.socket_family = AF_UNIX; + tor_addr_make_unspec(&conn->base_.addr); + conn->base_.port = 1; + conn->base_.address = tor_strdup(chosen_port->unix_addr); +#endif /* defined(HAVE_SYS_UN_H) */ + } + return 0; } - if (!unix_addrs) { - log_info(LD_REND, - "No virtual port mapping exists for port %d on service %s", - conn->base_.port, serviceid); - } else { -#ifdef HAVE_SYS_UN_H - log_info(LD_REND, - "Only AF_UNIX virtual port mappings exists for port %d " - "on service %s, and support is not yet implemented", - conn->base_.port, serviceid); -#else - log_info(LD_REND, - "Only AF_UNIX virtual port mappings exists for port %d " - "on service %s, and support is not available on this platform", - conn->base_.port, serviceid); -#endif /* defined(HAVE_SYS_UN_H) */ - } + + log_info(LD_REND, + "No virtual port mapping exists for port %d on service %s", + conn->base_.port, serviceid); + if (service->allow_unknown_ports) return -1; else From 603708d747c39ef90ae4123b3a712fcf165d38b5 Mon Sep 17 00:00:00 2001 From: Andrea Shepard Date: Tue, 27 Jan 2015 13:18:22 +0000 Subject: [PATCH 5/6] Changes file for ticket #11485 --- changes/ticket11485 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket11485 diff --git a/changes/ticket11485 b/changes/ticket11485 new file mode 100644 index 0000000000..9d341c57ab --- /dev/null +++ b/changes/ticket11485 @@ -0,0 +1,3 @@ + o Features (hidden services): + - Support mapping hidden service virtual ports to AF_UNIX sockets on + suitable platforms. Resolves ticket #11485. From fb523b543a95e6eeb85ee93dcad24e1aeb79328f Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 28 Jan 2015 13:11:21 -0500 Subject: [PATCH 6/6] fixup! Refactor the use of ifdef HAVE_SYS_UN_H Signed-off-by: David Goulet --- src/or/rendservice.c | 99 ++++++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 31 deletions(-) diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 920a8cfe11..9f58bb16c2 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -3471,6 +3471,56 @@ rend_service_dump_stats(int severity) } } +#ifdef HAVE_SYS_UN_H + +/** Given ports, a smarlist containing rend_service_port_config_t, + * add the given p, a AF_UNIX port to the list. Return 0 on success + * else return -ENOSYS if AF_UNIX is not supported (see function in the + * #else statement below). */ +static int +add_unix_port(smartlist_t *ports, rend_service_port_config_t *p) +{ + tor_assert(ports); + tor_assert(p); + tor_assert(p->is_unix_addr); + + smartlist_add(ports, p); + return 0; +} + +/** Given conn set it to use the given port p values. Return 0 + * on success else return -ENOSYS if AF_UNIX is not supported (see function + * in the #else statement below). */ +static int +set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p) +{ + tor_assert(conn); + tor_assert(p); + tor_assert(p->is_unix_addr); + + conn->base_.socket_family = AF_UNIX; + tor_addr_make_unspec(&conn->base_.addr); + conn->base_.port = 1; + conn->base_.address = tor_strdup(p->unix_addr); + return 0; +} + +#else /* defined(HAVE_SYS_UN_H) */ + +static int +set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p) +{ + return -ENOSYS; +} + +static int +add_unix_port(smartlist_t *ports, rend_service_port_config_t *p) +{ + return -ENOSYS; +} + +#endif /* HAVE_SYS_UN_H */ + /** Given conn, a rendezvous exit stream, look up the hidden service for * 'circ', and look up the port and address based on conn-\>port. * Assign the actual conn-\>addr and conn-\>port. Return -2 on failure @@ -3485,9 +3535,7 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; smartlist_t *matching_ports; rend_service_port_config_t *chosen_port; -#ifndef HAVE_SYS_UN_H - int unix_addrs_rejected; -#endif /* !defined(HAVE_SYS_UN_H) */ + unsigned int warn_once = 0; tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED); tor_assert(circ->rend_data); @@ -3503,51 +3551,40 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, return -2; } matching_ports = smartlist_new(); -#ifndef HAVE_SYS_UN_H - unix_addrs_rejected = 0; -#endif /* !defined(HAVE_SYS_UN_H) */ SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p, { - if (conn->base_.port == p->virtual_port) { -#ifdef HAVE_SYS_UN_H + if (conn->base_.port != p->virtual_port) { + continue; + } + if (!(p->is_unix_addr)) { smartlist_add(matching_ports, p); -#else - if (!(p->is_unix_addr)) { - smartlist_add(matching_ports, p); - } else { - if (unix_addrs_rejected == 0) { - /* If we have no support, bitch about it for just the first one */ + } else { + if (add_unix_port(matching_ports, p)) { + if (!warn_once) { + /* Unix port not supported so warn only once. */ log_warn(LD_REND, - "Saw AF_UNIX virtual port mapping for port %d on service " - "%s, which is unsupported on this platform. Ignoring it.", - conn->base_.port, serviceid); + "Saw AF_UNIX virtual port mapping for port %d on service " + "%s, which is unsupported on this platform. Ignoring it.", + conn->base_.port, serviceid); } - ++unix_addrs_rejected; + warn_once++; } -#endif /* defined(HAVE_SYS_UN_H) */ } }); chosen_port = smartlist_choose(matching_ports); smartlist_free(matching_ports); if (chosen_port) { -#ifdef HAVE_SYS_UN_H if (!(chosen_port->is_unix_addr)) { -#else - { -#endif /* defined(HAVE_SYS_UN_H) */ /* Get a non-AF_UNIX connection ready for connection_exit_connect() */ tor_addr_copy(&conn->base_.addr, &chosen_port->real_addr); conn->base_.port = chosen_port->real_port; -#ifdef HAVE_SYS_UN_H } else { - /* Get an AF_UNIX connection ready for connection_exit_connect() */ - conn->base_.socket_family = AF_UNIX; - tor_addr_make_unspec(&conn->base_.addr); - conn->base_.port = 1; - conn->base_.address = tor_strdup(chosen_port->unix_addr); -#endif /* defined(HAVE_SYS_UN_H) */ + if (set_unix_port(conn, chosen_port)) { + /* Simply impossible to end up here else we were able to add a Unix + * port without AF_UNIX support... ? */ + tor_assert(0); + } } - return 0; }