[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: control interface via unix domain socket
On Mon, 04 Jun 2007, Nick Mathewson wrote:
> > Things that remain to be done:
> > - make relative filenames relative to datadir?
> > - document in manpage
> - Right now, your code rejects the ControlSocket option as
> unrecognized. if the code can't support it. That's not how we
> handle unsupported options right now; instead, we try to give a
> message that says, "this Tor can't support that (otherwise valid)
> option." (In some cases, we just ignore the option. That's bad
> too.)
Fixed.
> - Make sure your code passes "make check-spaces".
It should now.
> - I'm not sure we need to have a new listener type for this.
> I think, instead, that connection_create_listener should
> take a "struct sockaddr" as its argument, and that its callers
> should pass it a sockaddr of the right kind. This will avoid
> bloating connection_create_listener, and will make the eventual
> IPv6 listeners easier too.
>
> To handle the special-cases on AF_UNIX later on, we could add a
> one-bit is_unix_socket flag to connection_t.
I added a new field to connection_t, sa_family. Right now it will
always be AF_INET or AF_UNIX, but it may be AF_INET6 in the future.
Also, the additional connection type is gone. relaunch_listener()
now takes an extra argument specifying if you want unix or inet sockets.
> - I think you missed the code to make connection_is_listener() work,
> in case you don't go with the above.
N/A anymore :)
> With that in mind, this looks pretty close to complete. Would you
> like to do the cleanup, or should I?
How does this look?
--
| .''`. ** Debian GNU/Linux **
Peter Palfrader | : :' : The universal
http://www.palfrader.org/ | `. `' Operating System
| `- http://www.debian.org/
Index: configure.in
===================================================================
--- configure.in (revision 10502)
+++ configure.in (working copy)
@@ -240,7 +240,7 @@
AC_CHECK_HEADERS(unistd.h string.h signal.h ctype.h sys/stat.h sys/types.h fcntl.h sys/fcntl.h sys/time.h errno.h assert.h time.h, , AC_MSG_WARN(Some headers were not found, compilation may fail. If compilation succeeds, please send your orconfig.h to the developers so we can fix this warning.))
-AC_CHECK_HEADERS(netdb.h sys/ioctl.h sys/socket.h arpa/inet.h netinet/in.h pwd.h grp.h)
+AC_CHECK_HEADERS(netdb.h sys/ioctl.h sys/socket.h arpa/inet.h netinet/in.h pwd.h grp.h sys/un.h)
dnl These headers are not essential
Index: src/or/connection_or.c
===================================================================
--- src/or/connection_or.c (revision 10502)
+++ src/or/connection_or.c (working copy)
@@ -465,7 +465,7 @@
return NULL;
}
- conn = TO_OR_CONN(connection_new(CONN_TYPE_OR));
+ conn = TO_OR_CONN(connection_new(CONN_TYPE_OR, AF_INET));
/* set up conn so it's got all the data we need to remember */
connection_or_init_conn_from_address(conn, addr, port, id_digest, 1);
Index: src/or/config.c
===================================================================
--- src/or/config.c (revision 10502)
+++ src/or/config.c (working copy)
@@ -149,6 +149,7 @@
VAR("ContactInfo", STRING, ContactInfo, NULL),
VAR("ControlListenAddress",LINELIST, ControlListenAddress, NULL),
VAR("ControlPort", UINT, ControlPort, "0"),
+ VAR("ControlSocket", LINELIST, ControlSocket, NULL),
VAR("CookieAuthentication",BOOL, CookieAuthentication, "0"),
VAR("DataDirectory", STRING, DataDirectory, NULL),
OBSOLETE("DebugLogFile"),
@@ -811,6 +812,14 @@
start_daemon();
}
+#ifndef HAVE_SYS_UN_H
+ if (options->ControlSocket) {
+ *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported"
+ " on this OS/with this build.");
+ goto rollback;
+ }
+#endif
+
if (running_tor) {
/* We need to set the connection limit before we can open the listeners. */
options->_ConnLimit =
Index: src/or/connection_edge.c
===================================================================
--- src/or/connection_edge.c (revision 10502)
+++ src/or/connection_edge.c (working copy)
@@ -1916,7 +1916,7 @@
log_notice(LD_APP,"Making internal anonymized tunnel to %s:%d ...",
safe_str(address),port); /* XXXX020 Downgrade back to info. */
- conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP));
+ conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP, AF_INET));
conn->_base.linked = 1; /* so that we can add it safely below. */
/* populate conn->socks_request */
@@ -2210,7 +2210,7 @@
}
log_debug(LD_EXIT,"Creating new exit connection.");
- n_stream = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT));
+ n_stream = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT, AF_INET));
n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
n_stream->stream_id = rh.stream_id;
@@ -2316,7 +2316,7 @@
* resolved; but if we didn't store them in a connection like this,
* the housekeeping in dns.c would get way more complicated.)
*/
- dummy_conn = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT));
+ dummy_conn = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT, AF_INET));
dummy_conn->stream_id = rh.stream_id;
dummy_conn->_base.address = tor_strndup(cell->payload+RELAY_HEADER_SIZE,
rh.length);
@@ -2450,7 +2450,7 @@
exitconn->_base.state = EXIT_CONN_STATE_OPEN;
- dirconn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR));
+ dirconn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR, AF_INET));
dirconn->_base.addr = 0x7f000001;
dirconn->_base.port = 0;
Index: src/or/or.h
===================================================================
--- src/or/or.h (revision 10502)
+++ src/or/or.h (working copy)
@@ -56,6 +56,9 @@
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -790,6 +793,9 @@
* could write? */
time_t timestamp_created; /**< When was this connection_t created? */
+ int sa_family; /**< Address family of this connection's socket. Usually
+ * AF_INET, but it can also be AF_UNIX, or in the future
+ * AF_INET6 */
uint32_t addr; /**< IP of the other side of the connection; used to identify
* routers, along with port. */
uint16_t port; /**< If non-zero, port on the other end
@@ -1819,6 +1825,8 @@
int TransPort;
int NatdPort; /**< Port to listen on for transparent natd connections. */
int ControlPort; /**< Port to listen on for control connections. */
+ config_line_t * ControlSocket; /**< Unix Domain Socket to listen on
+ * for control connections. */
int DirPort; /**< Port to listen on for directory connections. */
int DNSPort; /**< Port to listen on for DNS requests. */
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
@@ -2341,7 +2349,7 @@
const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
-connection_t *connection_new(int type);
+connection_t *connection_new(int type, int sa_family);
void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
void connection_unregister_events(connection_t *conn);
void connection_free(connection_t *conn);
Index: src/or/connection.c
===================================================================
--- src/or/connection.c (revision 10502)
+++ src/or/connection.c (working copy)
@@ -14,8 +14,9 @@
#include "or.h"
-static connection_t *connection_create_listener(const char *listenaddress,
- uint16_t listenport, int type);
+static connection_t *connection_create_listener(
+ struct sockaddr *listensockaddr, int type,
+ char* address);
static int connection_init_accepted_conn(connection_t *conn,
uint8_t listener_type);
static int connection_handle_listener_read(connection_t *conn, int new_type);
@@ -156,7 +157,7 @@
* Initialize conn's timestamps to now.
*/
connection_t *
-connection_new(int type)
+connection_new(int type, int sa_family)
{
static uint32_t n_connections_allocated = 1;
connection_t *conn;
@@ -194,6 +195,7 @@
conn->conn_array_index = -1; /* also default to 'not used' */
conn->type = type;
+ conn->sa_family = sa_family;
if (!connection_is_listener(conn)) { /* listeners never use their buf */
conn->inbuf = buf_new();
conn->outbuf = buf_new();
@@ -293,7 +295,18 @@
if (!connection_is_listener(conn)) {
buf_free(conn->inbuf);
buf_free(conn->outbuf);
+ } else {
+ if (conn->sa_family == AF_UNIX) {
+ /* For now only control ports can be unix domain sockets
+ * and listeners at the same time */
+ tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
+
+ if (unlink(conn->address) < 0 && errno != ENOENT) {
+ log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
+ strerror(errno));
}
+ }
+ }
tor_free(conn->address);
@@ -621,44 +634,97 @@
});
}
-/** Bind a new non-blocking socket listening to
- * <b>listenaddress</b>:<b>listenport</b>, and add this new connection
- * (of type <b>type</b>) to the connection array.
+/** Create an AF_INET listenaddr struct.
+ * <b>listenaddress</b> provides the host and optionally the port information
+ * for the new structure. If no port is provided in <b>listenaddress</b> then
+ * <b>listenport</b> is used.
*
- * If <b>listenaddress</b> includes a port, we bind on that port;
- * otherwise, we use listenport.
+ * If not NULL <b>readable_addrress</b> will contain a copy of the host part of
+ * <b>listenaddress</b>.
+ *
+ * The listenaddr struct has to be freed by the caller.
*/
-static connection_t *
-connection_create_listener(const char *listenaddress, uint16_t listenport,
- int type)
-{
- struct sockaddr_in listenaddr; /* where to bind */
- char *address = NULL;
- connection_t *conn;
- uint16_t usePort;
+struct sockaddr_in *
+create_inet_sockaddr(const char *listenaddress, uint16_t listenport,
+ char **readable_address) {
+ struct sockaddr_in *listenaddr = NULL;
uint32_t addr;
- int s; /* the socket we're going to make */
-#ifndef MS_WINDOWS
- int one=1;
-#endif
- int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
+ uint16_t usePort = 0;
- memset(&listenaddr,0,sizeof(struct sockaddr_in));
- if (parse_addr_port(LOG_WARN, listenaddress, &address, &addr, &usePort)<0) {
+ if (parse_addr_port(LOG_WARN,
+ listenaddress, readable_address, &addr, &usePort)<0) {
log_warn(LD_CONFIG,
"Error parsing/resolving ListenAddress %s", listenaddress);
- return NULL;
+ goto err;
}
-
if (usePort==0)
usePort = listenport;
- listenaddr.sin_addr.s_addr = htonl(addr);
- listenaddr.sin_family = AF_INET;
- listenaddr.sin_port = htons((uint16_t) usePort);
- log_notice(LD_NET, "Opening %s on %s:%d",
- conn_type_to_string(type), address, usePort);
+ listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in));
+ listenaddr->sin_addr.s_addr = htonl(addr);
+ listenaddr->sin_family = AF_INET;
+ listenaddr->sin_port = htons((uint16_t) usePort);
+ return listenaddr;
+
+ err:
+ tor_free(listenaddr);
+ return NULL;
+}
+
+#ifdef HAVE_SYS_UN_H
+/** Create an AF_UNIX listenaddr struct.
+ * <b>listenaddress</b> provides the path to the unix socket.
+ *
+ * Eventually <b>listenaddress</b> will also optionally contain user, group,
+ * and file permissions for the new socket. But not yet. XXX
+ * Also, since we do not create the socket here the information doesn't help
+ * here.
+ *
+ * If not NULL <b>readable_addrress</b> will contain a copy of the path part of
+ * <b>listenaddress</b>.
+ *
+ * The listenaddr struct has to be freed by the caller.
+ */
+struct sockaddr_un *
+create_unix_sockaddr(const char *listenaddress, char **readable_address)
+{
+ struct sockaddr_un *sockaddr = NULL;
+
+ sockaddr = tor_malloc_zero(sizeof(struct sockaddr_un));
+ sockaddr->sun_family = AF_UNIX;
+ strncpy(sockaddr->sun_path, listenaddress, sizeof(sockaddr->sun_path));
+
+ if (readable_address)
+ *readable_address = tor_strdup(listenaddress);
+
+ return sockaddr;
+}
+#else
+struct sockaddr *
+create_unix_sockaddr(const char *listenaddress, char **readable_address)
+{
+ log_fn(LOG_ERR, LD_BUG,
+ "Unix domain sockets not supported, yet we tried to create one.");
+ assert(0);
+};
+#endif /* HAVE_SYS_UN_H */
+
+/** Bind a new non-blocking socket listening to the socket described
+ * by <b>listensockaddr</b>.
+ *
+ * <b>address</b> is only used for logging purposes and to add the information
+ * to the conn.
+ */
+static connection_t *
+connection_create_listener(struct sockaddr *listensockaddr, int type,
+ char* address)
+{
+ connection_t *conn;
+ int s; /* the socket we're going to make */
+ uint16_t usePort = 0;
+ int start_reading = 0;
+
if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
int n_conns = get_n_open_sockets();
log_warn(LD_NET,"Failing because we have %d connections already. Please "
@@ -668,6 +734,20 @@
return NULL;
}
+ if (listensockaddr->sa_family == AF_INET) {
+ int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
+#ifndef MS_WINDOWS
+ int one=1;
+#endif
+ if (is_tcp)
+ start_reading = 1;
+
+ usePort = ntohs( (uint16_t)
+ ((struct sockaddr_in *)listensockaddr)->sin_port);
+
+ log_notice(LD_NET, "Opening %s on %s:%d",
+ conn_type_to_string(type), address, usePort);
+
s = tor_open_socket(PF_INET,
is_tcp ? SOCK_STREAM : SOCK_DGRAM,
is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
@@ -684,7 +764,7 @@
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one));
#endif
- if (bind(s,(struct sockaddr *)&listenaddr,sizeof(listenaddr)) < 0) {
+ if (bind(s,listensockaddr,sizeof(struct sockaddr_in)) < 0) {
const char *helpfulhint = "";
int e = tor_socket_errno(s);
if (ERRNO_IS_EADDRINUSE(e))
@@ -703,13 +783,56 @@
goto err;
}
}
+#ifdef HAVE_SYS_UN_H
+ } else if (listensockaddr->sa_family == AF_UNIX) {
+ int len;
+ start_reading = 1;
+ /* For now only control ports can be unix domain sockets
+ * and listeners at the same time */
+ tor_assert(type == CONN_TYPE_CONTROL_LISTENER);
+
+ log_notice(LD_NET, "Opening %s on %s",
+ conn_type_to_string(type), address);
+
+ if (unlink(address) < 0 && errno != ENOENT) {
+ log_warn(LD_NET, "Could not unlink %s: %s", address,
+ strerror(errno));
+ goto err;
+ }
+ s = tor_open_socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
+ goto err;
+ }
+
+ len = strlen(((struct sockaddr_un *)listensockaddr)->sun_path) +
+ sizeof(((struct sockaddr_un *)listensockaddr)->sun_family);
+ if (bind(s, listensockaddr, len) == -1) {
+ log_warn(LD_NET,"Bind to %s failed: %s.", address,
+ tor_socket_strerror(tor_socket_errno(s)));
+ goto err;
+ }
+
+ if (listen(s,SOMAXCONN) < 0) {
+ log_warn(LD_NET, "Could not listen on %s: %s", address,
+ tor_socket_strerror(tor_socket_errno(s)));
+ tor_close_socket(s);
+ goto err;
+ }
+#endif /* HAVE_SYS_UN_H */
+ } else {
+ log_err(LD_BUG,"Got unexpected address family %d.",
+ listensockaddr->sa_family);
+ tor_assert(0);
+ }
+
set_socket_nonblocking(s);
- conn = connection_new(type);
+ conn = connection_new(type, listensockaddr->sa_family);
+ conn->sa_family = listensockaddr->sa_family;
conn->s = s;
- conn->address = address;
- address = NULL;
+ conn->address = tor_strdup(address);
conn->port = usePort;
if (connection_add(conn) < 0) { /* no space, forget it */
@@ -722,7 +845,7 @@
conn_type_to_string(type), usePort);
conn->state = LISTENER_STATE_READY;
- if (is_tcp) {
+ if (start_reading) {
connection_start_reading(conn);
} else {
tor_assert(type == CONN_TYPE_AP_DNS_LISTENER);
@@ -732,7 +855,6 @@
return conn;
err:
- tor_free(address);
return NULL;
}
@@ -801,6 +923,9 @@
set_socket_nonblocking(news);
+ tor_assert(((struct sockaddr*)addrbuf)->sa_family == conn->sa_family);
+
+ if (conn->sa_family == AF_INET) {
if (check_sockaddr_in((struct sockaddr*)addrbuf, remotelen, LOG_INFO)<0) {
log_info(LD_NET,
"accept() returned a strange address; trying getsockname().");
@@ -826,7 +951,8 @@
/* check sockspolicy to see if we should accept it */
if (socks_policy_permits_address(ntohl(remote.sin_addr.s_addr)) == 0) {
tor_inet_ntoa(&remote.sin_addr, tmpbuf, sizeof(tmpbuf));
- log_notice(LD_APP,"Denying socks connection from untrusted address %s.",
+ log_notice(LD_APP,
+ "Denying socks connection from untrusted address %s.",
tmpbuf);
tor_close_socket(news);
return 0;
@@ -843,7 +969,7 @@
}
}
- newconn = connection_new(new_type);
+ newconn = connection_new(new_type, conn->sa_family);
newconn->s = news;
/* remember the remote address */
@@ -851,6 +977,22 @@
newconn->port = ntohs(remote.sin_port);
newconn->address = tor_dup_addr(newconn->addr);
+ } else if (conn->sa_family == AF_UNIX) {
+ /* For now only control ports can be unix domain sockets
+ * and listeners at the same time */
+ tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
+
+ newconn = connection_new(new_type, conn->sa_family);
+ newconn->s = news;
+
+ /* remember the remote address -- do we have anything sane to put here? */
+ newconn->addr = 0;
+ newconn->port = 1;
+ newconn->address = tor_strdup(conn->address);
+ } else {
+ tor_assert(0);
+ };
+
if (connection_add(newconn) < 0) { /* no space, forget it */
connection_free(newconn);
return 0; /* no need to tear down the parent */
@@ -1007,7 +1149,8 @@
int port_option, const char *default_addr,
smartlist_t *replaced_conns,
smartlist_t *new_conns,
- int never_open_conns)
+ int never_open_conns,
+ int sa_family)
{
smartlist_t *launch = smartlist_create(), *conns;
int free_launch_elts = 1;
@@ -1016,6 +1159,8 @@
connection_t *conn;
config_line_t *line;
+ tor_assert(sa_family == AF_INET || sa_family == AF_UNIX);
+
if (cfg && port_option) {
for (c = cfg; c; c = c->next) {
smartlist_add(launch, c);
@@ -1036,7 +1181,9 @@
conns = get_connection_array();
SMARTLIST_FOREACH(conns, connection_t *, conn,
{
- if (conn->type != type || conn->marked_for_close)
+ if (conn->type != type ||
+ conn->sa_family != sa_family ||
+ conn->marked_for_close)
continue;
/* Okay, so this is a listener. Is it configured? */
line = NULL;
@@ -1044,7 +1191,10 @@
{
char *address=NULL;
uint16_t port;
- if (!parse_addr_port(LOG_WARN, wanted->value, &address, NULL, &port)) {
+ switch (sa_family) {
+ case AF_INET:
+ if (!parse_addr_port(LOG_WARN,
+ wanted->value, &address, NULL, &port)) {
int addr_matches = !strcasecmp(address, conn->address);
tor_free(address);
if (! port)
@@ -1054,6 +1204,16 @@
break;
}
}
+ break;
+ case AF_UNIX:
+ if (!strcasecmp(wanted->value, conn->address)) {
+ line = wanted;
+ break;
+ }
+ break;
+ default:
+ tor_assert(0);
+ }
});
if (! line) {
/* This one isn't configured. Close it. */
@@ -1080,8 +1240,31 @@
if (!never_open_conns) {
SMARTLIST_FOREACH(launch, config_line_t *, cfg_line,
{
- conn = connection_create_listener(cfg_line->value,
- (uint16_t) port_option, type);
+ char *address = NULL;
+ struct sockaddr *listensockaddr;
+
+ switch (sa_family) {
+ case AF_INET:
+ listensockaddr = (struct sockaddr *)
+ create_inet_sockaddr(cfg_line->value,
+ (uint16_t) port_option,
+ &address);
+ break;
+ case AF_UNIX:
+ listensockaddr = (struct sockaddr *)
+ create_unix_sockaddr(cfg_line->value,
+ &address);
+ break;
+ default:
+ tor_assert(0);
+ }
+
+ if (listensockaddr) {
+ conn = connection_create_listener(listensockaddr, type, address);
+ tor_free(address);
+ } else
+ conn = NULL;
+
if (!conn) {
r = -1;
} else {
@@ -1115,33 +1298,46 @@
if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress,
options->ORPort, "0.0.0.0",
- replaced_conns, new_conns, options->ClientOnly)<0)
+ replaced_conns, new_conns, options->ClientOnly,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
options->DirPort, "0.0.0.0",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress,
options->SocksPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
options->TransPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NatdListenAddress,
options->NatdPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress,
options->DNSPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
options->ControlListenAddress,
options->ControlPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
+ if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
+ options->ControlSocket,
+ options->ControlSocket ? 1 : 0, NULL,
+ replaced_conns, new_conns, 0,
+ AF_UNIX)<0)
+ return -1;
return 0;
}
Index: src/or/directory.c
===================================================================
--- src/or/directory.c (revision 10502)
+++ src/or/directory.c (working copy)
@@ -490,7 +490,7 @@
tor_assert(0);
}
- conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR));
+ conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR, AF_INET));
/* set up conn so it's got all the data we need to remember */
conn->_base.addr = addr;
Index: src/or/cpuworker.c
===================================================================
--- src/or/cpuworker.c (revision 10502)
+++ src/or/cpuworker.c (working copy)
@@ -339,7 +339,7 @@
tor_free(fdarray);
#endif
- conn = connection_new(CONN_TYPE_CPUWORKER);
+ conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX);
set_socket_nonblocking(fd);
Index: src/or/dnsserv.c
===================================================================
--- src/or/dnsserv.c (revision 10502)
+++ src/or/dnsserv.c (working copy)
@@ -110,7 +110,7 @@
/* XXXX020 Send a stream event to the controller. */
/* Make a new dummy AP connection, and attach the request to it. */
- conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP));
+ conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP, AF_INET));
conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
if (q->type == EVDNS_TYPE_A)
conn->socks_request->command = SOCKS_COMMAND_RESOLVE;
Index: configure.in
===================================================================
--- configure.in (revision 10502)
+++ configure.in (working copy)
@@ -240,7 +240,7 @@
AC_CHECK_HEADERS(unistd.h string.h signal.h ctype.h sys/stat.h sys/types.h fcntl.h sys/fcntl.h sys/time.h errno.h assert.h time.h, , AC_MSG_WARN(Some headers were not found, compilation may fail. If compilation succeeds, please send your orconfig.h to the developers so we can fix this warning.))
-AC_CHECK_HEADERS(netdb.h sys/ioctl.h sys/socket.h arpa/inet.h netinet/in.h pwd.h grp.h)
+AC_CHECK_HEADERS(netdb.h sys/ioctl.h sys/socket.h arpa/inet.h netinet/in.h pwd.h grp.h sys/un.h)
dnl These headers are not essential
Index: src/or/connection_or.c
===================================================================
--- src/or/connection_or.c (revision 10502)
+++ src/or/connection_or.c (working copy)
@@ -465,7 +465,7 @@
return NULL;
}
- conn = TO_OR_CONN(connection_new(CONN_TYPE_OR));
+ conn = TO_OR_CONN(connection_new(CONN_TYPE_OR, AF_INET));
/* set up conn so it's got all the data we need to remember */
connection_or_init_conn_from_address(conn, addr, port, id_digest, 1);
Index: src/or/config.c
===================================================================
--- src/or/config.c (revision 10502)
+++ src/or/config.c (working copy)
@@ -149,6 +149,7 @@
VAR("ContactInfo", STRING, ContactInfo, NULL),
VAR("ControlListenAddress",LINELIST, ControlListenAddress, NULL),
VAR("ControlPort", UINT, ControlPort, "0"),
+ VAR("ControlSocket", LINELIST, ControlSocket, NULL),
VAR("CookieAuthentication",BOOL, CookieAuthentication, "0"),
VAR("DataDirectory", STRING, DataDirectory, NULL),
OBSOLETE("DebugLogFile"),
@@ -811,6 +812,14 @@
start_daemon();
}
+#ifndef HAVE_SYS_UN_H
+ if (options->ControlSocket) {
+ *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported"
+ " on this OS/with this build.");
+ goto rollback;
+ }
+#endif
+
if (running_tor) {
/* We need to set the connection limit before we can open the listeners. */
options->_ConnLimit =
Index: src/or/connection_edge.c
===================================================================
--- src/or/connection_edge.c (revision 10502)
+++ src/or/connection_edge.c (working copy)
@@ -1916,7 +1916,7 @@
log_notice(LD_APP,"Making internal anonymized tunnel to %s:%d ...",
safe_str(address),port); /* XXXX020 Downgrade back to info. */
- conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP));
+ conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP, AF_INET));
conn->_base.linked = 1; /* so that we can add it safely below. */
/* populate conn->socks_request */
@@ -2210,7 +2210,7 @@
}
log_debug(LD_EXIT,"Creating new exit connection.");
- n_stream = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT));
+ n_stream = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT, AF_INET));
n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
n_stream->stream_id = rh.stream_id;
@@ -2316,7 +2316,7 @@
* resolved; but if we didn't store them in a connection like this,
* the housekeeping in dns.c would get way more complicated.)
*/
- dummy_conn = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT));
+ dummy_conn = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT, AF_INET));
dummy_conn->stream_id = rh.stream_id;
dummy_conn->_base.address = tor_strndup(cell->payload+RELAY_HEADER_SIZE,
rh.length);
@@ -2450,7 +2450,7 @@
exitconn->_base.state = EXIT_CONN_STATE_OPEN;
- dirconn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR));
+ dirconn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR, AF_INET));
dirconn->_base.addr = 0x7f000001;
dirconn->_base.port = 0;
Index: src/or/or.h
===================================================================
--- src/or/or.h (revision 10502)
+++ src/or/or.h (working copy)
@@ -56,6 +56,9 @@
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -790,6 +793,9 @@
* could write? */
time_t timestamp_created; /**< When was this connection_t created? */
+ int sa_family; /**< Address family of this connection's socket. Usually
+ * AF_INET, but it can also be AF_UNIX, or in the future
+ * AF_INET6 */
uint32_t addr; /**< IP of the other side of the connection; used to identify
* routers, along with port. */
uint16_t port; /**< If non-zero, port on the other end
@@ -1819,6 +1825,8 @@
int TransPort;
int NatdPort; /**< Port to listen on for transparent natd connections. */
int ControlPort; /**< Port to listen on for control connections. */
+ config_line_t * ControlSocket; /**< Unix Domain Socket to listen on
+ * for control connections. */
int DirPort; /**< Port to listen on for directory connections. */
int DNSPort; /**< Port to listen on for DNS requests. */
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
@@ -2341,7 +2349,7 @@
const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
-connection_t *connection_new(int type);
+connection_t *connection_new(int type, int sa_family);
void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
void connection_unregister_events(connection_t *conn);
void connection_free(connection_t *conn);
Index: src/or/connection.c
===================================================================
--- src/or/connection.c (revision 10502)
+++ src/or/connection.c (working copy)
@@ -14,8 +14,9 @@
#include "or.h"
-static connection_t *connection_create_listener(const char *listenaddress,
- uint16_t listenport, int type);
+static connection_t *connection_create_listener(
+ struct sockaddr *listensockaddr, int type,
+ char* address);
static int connection_init_accepted_conn(connection_t *conn,
uint8_t listener_type);
static int connection_handle_listener_read(connection_t *conn, int new_type);
@@ -156,7 +157,7 @@
* Initialize conn's timestamps to now.
*/
connection_t *
-connection_new(int type)
+connection_new(int type, int sa_family)
{
static uint32_t n_connections_allocated = 1;
connection_t *conn;
@@ -194,6 +195,7 @@
conn->conn_array_index = -1; /* also default to 'not used' */
conn->type = type;
+ conn->sa_family = sa_family;
if (!connection_is_listener(conn)) { /* listeners never use their buf */
conn->inbuf = buf_new();
conn->outbuf = buf_new();
@@ -293,6 +295,17 @@
if (!connection_is_listener(conn)) {
buf_free(conn->inbuf);
buf_free(conn->outbuf);
+ } else {
+ if (conn->sa_family == AF_UNIX) {
+ /* For now only control ports can be unix domain sockets
+ * and listeners at the same time */
+ tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
+
+ if (unlink(conn->address) < 0 && errno != ENOENT) {
+ log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
+ strerror(errno));
+ }
+ }
}
tor_free(conn->address);
@@ -621,44 +634,97 @@
});
}
-/** Bind a new non-blocking socket listening to
- * <b>listenaddress</b>:<b>listenport</b>, and add this new connection
- * (of type <b>type</b>) to the connection array.
+/** Create an AF_INET listenaddr struct.
+ * <b>listenaddress</b> provides the host and optionally the port information
+ * for the new structure. If no port is provided in <b>listenaddress</b> then
+ * <b>listenport</b> is used.
*
- * If <b>listenaddress</b> includes a port, we bind on that port;
- * otherwise, we use listenport.
+ * If not NULL <b>readable_addrress</b> will contain a copy of the host part of
+ * <b>listenaddress</b>.
+ *
+ * The listenaddr struct has to be freed by the caller.
*/
-static connection_t *
-connection_create_listener(const char *listenaddress, uint16_t listenport,
- int type)
-{
- struct sockaddr_in listenaddr; /* where to bind */
- char *address = NULL;
- connection_t *conn;
- uint16_t usePort;
+struct sockaddr_in *
+create_inet_sockaddr(const char *listenaddress, uint16_t listenport,
+ char **readable_address) {
+ struct sockaddr_in *listenaddr = NULL;
uint32_t addr;
- int s; /* the socket we're going to make */
-#ifndef MS_WINDOWS
- int one=1;
-#endif
- int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
+ uint16_t usePort = 0;
- memset(&listenaddr,0,sizeof(struct sockaddr_in));
- if (parse_addr_port(LOG_WARN, listenaddress, &address, &addr, &usePort)<0) {
+ if (parse_addr_port(LOG_WARN,
+ listenaddress, readable_address, &addr, &usePort)<0) {
log_warn(LD_CONFIG,
"Error parsing/resolving ListenAddress %s", listenaddress);
- return NULL;
+ goto err;
}
-
if (usePort==0)
usePort = listenport;
- listenaddr.sin_addr.s_addr = htonl(addr);
- listenaddr.sin_family = AF_INET;
- listenaddr.sin_port = htons((uint16_t) usePort);
- log_notice(LD_NET, "Opening %s on %s:%d",
- conn_type_to_string(type), address, usePort);
+ listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in));
+ listenaddr->sin_addr.s_addr = htonl(addr);
+ listenaddr->sin_family = AF_INET;
+ listenaddr->sin_port = htons((uint16_t) usePort);
+ return listenaddr;
+
+ err:
+ tor_free(listenaddr);
+ return NULL;
+}
+
+#ifdef HAVE_SYS_UN_H
+/** Create an AF_UNIX listenaddr struct.
+ * <b>listenaddress</b> provides the path to the unix socket.
+ *
+ * Eventually <b>listenaddress</b> will also optionally contain user, group,
+ * and file permissions for the new socket. But not yet. XXX
+ * Also, since we do not create the socket here the information doesn't help
+ * here.
+ *
+ * If not NULL <b>readable_addrress</b> will contain a copy of the path part of
+ * <b>listenaddress</b>.
+ *
+ * The listenaddr struct has to be freed by the caller.
+ */
+struct sockaddr_un *
+create_unix_sockaddr(const char *listenaddress, char **readable_address)
+{
+ struct sockaddr_un *sockaddr = NULL;
+
+ sockaddr = tor_malloc_zero(sizeof(struct sockaddr_un));
+ sockaddr->sun_family = AF_UNIX;
+ strncpy(sockaddr->sun_path, listenaddress, sizeof(sockaddr->sun_path));
+
+ if (readable_address)
+ *readable_address = tor_strdup(listenaddress);
+
+ return sockaddr;
+}
+#else
+struct sockaddr *
+create_unix_sockaddr(const char *listenaddress, char **readable_address)
+{
+ log_fn(LOG_ERR, LD_BUG,
+ "Unix domain sockets not supported, yet we tried to create one.");
+ assert(0);
+};
+#endif /* HAVE_SYS_UN_H */
+
+/** Bind a new non-blocking socket listening to the socket described
+ * by <b>listensockaddr</b>.
+ *
+ * <b>address</b> is only used for logging purposes and to add the information
+ * to the conn.
+ */
+static connection_t *
+connection_create_listener(struct sockaddr *listensockaddr, int type,
+ char* address)
+{
+ connection_t *conn;
+ int s; /* the socket we're going to make */
+ uint16_t usePort = 0;
+ int start_reading = 0;
+
if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
int n_conns = get_n_open_sockets();
log_warn(LD_NET,"Failing because we have %d connections already. Please "
@@ -668,48 +734,105 @@
return NULL;
}
- s = tor_open_socket(PF_INET,
- is_tcp ? SOCK_STREAM : SOCK_DGRAM,
- is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
- if (s < 0) {
- log_warn(LD_NET,"Socket creation failed.");
- goto err;
- }
+ if (listensockaddr->sa_family == AF_INET) {
+ int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
+#ifndef MS_WINDOWS
+ int one=1;
+#endif
+ if (is_tcp)
+ start_reading = 1;
+ usePort = ntohs( (uint16_t)
+ ((struct sockaddr_in *)listensockaddr)->sin_port);
+
+ log_notice(LD_NET, "Opening %s on %s:%d",
+ conn_type_to_string(type), address, usePort);
+
+ s = tor_open_socket(PF_INET,
+ is_tcp ? SOCK_STREAM : SOCK_DGRAM,
+ is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
+ if (s < 0) {
+ log_warn(LD_NET,"Socket creation failed.");
+ goto err;
+ }
+
#ifndef MS_WINDOWS
- /* REUSEADDR on normal places means you can rebind to the port
- * right after somebody else has let it go. But REUSEADDR on win32
- * means you can bind to the port _even when somebody else
- * already has it bound_. So, don't do that on Win32. */
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one));
+ /* REUSEADDR on normal places means you can rebind to the port
+ * right after somebody else has let it go. But REUSEADDR on win32
+ * means you can bind to the port _even when somebody else
+ * already has it bound_. So, don't do that on Win32. */
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one));
#endif
- if (bind(s,(struct sockaddr *)&listenaddr,sizeof(listenaddr)) < 0) {
- const char *helpfulhint = "";
- int e = tor_socket_errno(s);
- if (ERRNO_IS_EADDRINUSE(e))
- helpfulhint = ". Is Tor already running?";
- log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
- tor_socket_strerror(e), helpfulhint);
- tor_close_socket(s);
- goto err;
- }
+ if (bind(s,listensockaddr,sizeof(struct sockaddr_in)) < 0) {
+ const char *helpfulhint = "";
+ int e = tor_socket_errno(s);
+ if (ERRNO_IS_EADDRINUSE(e))
+ helpfulhint = ". Is Tor already running?";
+ log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
+ tor_socket_strerror(e), helpfulhint);
+ tor_close_socket(s);
+ goto err;
+ }
- if (is_tcp) {
+ if (is_tcp) {
+ if (listen(s,SOMAXCONN) < 0) {
+ log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
+ tor_socket_strerror(tor_socket_errno(s)));
+ tor_close_socket(s);
+ goto err;
+ }
+ }
+#ifdef HAVE_SYS_UN_H
+ } else if (listensockaddr->sa_family == AF_UNIX) {
+ int len;
+ start_reading = 1;
+
+ /* For now only control ports can be unix domain sockets
+ * and listeners at the same time */
+ tor_assert(type == CONN_TYPE_CONTROL_LISTENER);
+
+ log_notice(LD_NET, "Opening %s on %s",
+ conn_type_to_string(type), address);
+
+ if (unlink(address) < 0 && errno != ENOENT) {
+ log_warn(LD_NET, "Could not unlink %s: %s", address,
+ strerror(errno));
+ goto err;
+ }
+ s = tor_open_socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
+ goto err;
+ }
+
+ len = strlen(((struct sockaddr_un *)listensockaddr)->sun_path) +
+ sizeof(((struct sockaddr_un *)listensockaddr)->sun_family);
+ if (bind(s, listensockaddr, len) == -1) {
+ log_warn(LD_NET,"Bind to %s failed: %s.", address,
+ tor_socket_strerror(tor_socket_errno(s)));
+ goto err;
+ }
+
if (listen(s,SOMAXCONN) < 0) {
- log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
+ log_warn(LD_NET, "Could not listen on %s: %s", address,
tor_socket_strerror(tor_socket_errno(s)));
tor_close_socket(s);
goto err;
}
+#endif /* HAVE_SYS_UN_H */
+ } else {
+ log_err(LD_BUG,"Got unexpected address family %d.",
+ listensockaddr->sa_family);
+ tor_assert(0);
}
set_socket_nonblocking(s);
- conn = connection_new(type);
+ conn = connection_new(type, listensockaddr->sa_family);
+ conn->sa_family = listensockaddr->sa_family;
conn->s = s;
- conn->address = address;
- address = NULL;
+ conn->address = tor_strdup(address);
conn->port = usePort;
if (connection_add(conn) < 0) { /* no space, forget it */
@@ -722,7 +845,7 @@
conn_type_to_string(type), usePort);
conn->state = LISTENER_STATE_READY;
- if (is_tcp) {
+ if (start_reading) {
connection_start_reading(conn);
} else {
tor_assert(type == CONN_TYPE_AP_DNS_LISTENER);
@@ -732,7 +855,6 @@
return conn;
err:
- tor_free(address);
return NULL;
}
@@ -801,56 +923,76 @@
set_socket_nonblocking(news);
- if (check_sockaddr_in((struct sockaddr*)addrbuf, remotelen, LOG_INFO)<0) {
- log_info(LD_NET,
- "accept() returned a strange address; trying getsockname().");
- remotelen=256;
- memset(addrbuf, 0, sizeof(addrbuf));
- if (getsockname(news, (struct sockaddr*)addrbuf, &remotelen)<0) {
- int e = tor_socket_errno(news);
- log_warn(LD_NET, "getsockname() for new connection failed: %s",
- tor_socket_strerror(e));
- } else {
- if (check_sockaddr_in((struct sockaddr*)addrbuf, remotelen,
- LOG_WARN) < 0) {
- log_warn(LD_NET,"Something's wrong with this conn. Closing it.");
+ tor_assert(((struct sockaddr*)addrbuf)->sa_family == conn->sa_family);
+
+ if (conn->sa_family == AF_INET) {
+ if (check_sockaddr_in((struct sockaddr*)addrbuf, remotelen, LOG_INFO)<0) {
+ log_info(LD_NET,
+ "accept() returned a strange address; trying getsockname().");
+ remotelen=256;
+ memset(addrbuf, 0, sizeof(addrbuf));
+ if (getsockname(news, (struct sockaddr*)addrbuf, &remotelen)<0) {
+ int e = tor_socket_errno(news);
+ log_warn(LD_NET, "getsockname() for new connection failed: %s",
+ tor_socket_strerror(e));
+ } else {
+ if (check_sockaddr_in((struct sockaddr*)addrbuf, remotelen,
+ LOG_WARN) < 0) {
+ log_warn(LD_NET,"Something's wrong with this conn. Closing it.");
+ tor_close_socket(news);
+ return 0;
+ }
+ }
+ }
+ memcpy(&remote, addrbuf, sizeof(struct sockaddr_in));
+
+ /* process entrance policies here, before we even create the connection */
+ if (new_type == CONN_TYPE_AP) {
+ /* check sockspolicy to see if we should accept it */
+ if (socks_policy_permits_address(ntohl(remote.sin_addr.s_addr)) == 0) {
+ tor_inet_ntoa(&remote.sin_addr, tmpbuf, sizeof(tmpbuf));
+ log_notice(LD_APP,
+ "Denying socks connection from untrusted address %s.",
+ tmpbuf);
tor_close_socket(news);
return 0;
}
}
- }
- memcpy(&remote, addrbuf, sizeof(struct sockaddr_in));
-
- /* process entrance policies here, before we even create the connection */
- if (new_type == CONN_TYPE_AP) {
- /* check sockspolicy to see if we should accept it */
- if (socks_policy_permits_address(ntohl(remote.sin_addr.s_addr)) == 0) {
- tor_inet_ntoa(&remote.sin_addr, tmpbuf, sizeof(tmpbuf));
- log_notice(LD_APP,"Denying socks connection from untrusted address %s.",
- tmpbuf);
- tor_close_socket(news);
- return 0;
+ if (new_type == CONN_TYPE_DIR) {
+ /* check dirpolicy to see if we should accept it */
+ if (dir_policy_permits_address(ntohl(remote.sin_addr.s_addr)) == 0) {
+ tor_inet_ntoa(&remote.sin_addr, tmpbuf, sizeof(tmpbuf));
+ log_notice(LD_DIRSERV,"Denying dir connection from address %s.",
+ tmpbuf);
+ tor_close_socket(news);
+ return 0;
+ }
}
- }
- if (new_type == CONN_TYPE_DIR) {
- /* check dirpolicy to see if we should accept it */
- if (dir_policy_permits_address(ntohl(remote.sin_addr.s_addr)) == 0) {
- tor_inet_ntoa(&remote.sin_addr, tmpbuf, sizeof(tmpbuf));
- log_notice(LD_DIRSERV,"Denying dir connection from address %s.",
- tmpbuf);
- tor_close_socket(news);
- return 0;
- }
- }
- newconn = connection_new(new_type);
- newconn->s = news;
+ newconn = connection_new(new_type, conn->sa_family);
+ newconn->s = news;
- /* remember the remote address */
- newconn->addr = ntohl(remote.sin_addr.s_addr);
- newconn->port = ntohs(remote.sin_port);
- newconn->address = tor_dup_addr(newconn->addr);
+ /* remember the remote address */
+ newconn->addr = ntohl(remote.sin_addr.s_addr);
+ newconn->port = ntohs(remote.sin_port);
+ newconn->address = tor_dup_addr(newconn->addr);
+ } else if (conn->sa_family == AF_UNIX) {
+ /* For now only control ports can be unix domain sockets
+ * and listeners at the same time */
+ tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
+
+ newconn = connection_new(new_type, conn->sa_family);
+ newconn->s = news;
+
+ /* remember the remote address -- do we have anything sane to put here? */
+ newconn->addr = 0;
+ newconn->port = 1;
+ newconn->address = tor_strdup(conn->address);
+ } else {
+ tor_assert(0);
+ };
+
if (connection_add(newconn) < 0) { /* no space, forget it */
connection_free(newconn);
return 0; /* no need to tear down the parent */
@@ -1007,7 +1149,8 @@
int port_option, const char *default_addr,
smartlist_t *replaced_conns,
smartlist_t *new_conns,
- int never_open_conns)
+ int never_open_conns,
+ int sa_family)
{
smartlist_t *launch = smartlist_create(), *conns;
int free_launch_elts = 1;
@@ -1016,6 +1159,8 @@
connection_t *conn;
config_line_t *line;
+ tor_assert(sa_family == AF_INET || sa_family == AF_UNIX);
+
if (cfg && port_option) {
for (c = cfg; c; c = c->next) {
smartlist_add(launch, c);
@@ -1036,7 +1181,9 @@
conns = get_connection_array();
SMARTLIST_FOREACH(conns, connection_t *, conn,
{
- if (conn->type != type || conn->marked_for_close)
+ if (conn->type != type ||
+ conn->sa_family != sa_family ||
+ conn->marked_for_close)
continue;
/* Okay, so this is a listener. Is it configured? */
line = NULL;
@@ -1044,15 +1191,28 @@
{
char *address=NULL;
uint16_t port;
- if (!parse_addr_port(LOG_WARN, wanted->value, &address, NULL, &port)) {
- int addr_matches = !strcasecmp(address, conn->address);
- tor_free(address);
- if (! port)
- port = port_option;
- if (port == conn->port && addr_matches) {
- line = wanted;
+ switch (sa_family) {
+ case AF_INET:
+ if (!parse_addr_port(LOG_WARN,
+ wanted->value, &address, NULL, &port)) {
+ int addr_matches = !strcasecmp(address, conn->address);
+ tor_free(address);
+ if (! port)
+ port = port_option;
+ if (port == conn->port && addr_matches) {
+ line = wanted;
+ break;
+ }
+ }
break;
- }
+ case AF_UNIX:
+ if (!strcasecmp(wanted->value, conn->address)) {
+ line = wanted;
+ break;
+ }
+ break;
+ default:
+ tor_assert(0);
}
});
if (! line) {
@@ -1080,8 +1240,31 @@
if (!never_open_conns) {
SMARTLIST_FOREACH(launch, config_line_t *, cfg_line,
{
- conn = connection_create_listener(cfg_line->value,
- (uint16_t) port_option, type);
+ char *address = NULL;
+ struct sockaddr *listensockaddr;
+
+ switch (sa_family) {
+ case AF_INET:
+ listensockaddr = (struct sockaddr *)
+ create_inet_sockaddr(cfg_line->value,
+ (uint16_t) port_option,
+ &address);
+ break;
+ case AF_UNIX:
+ listensockaddr = (struct sockaddr *)
+ create_unix_sockaddr(cfg_line->value,
+ &address);
+ break;
+ default:
+ tor_assert(0);
+ }
+
+ if (listensockaddr) {
+ conn = connection_create_listener(listensockaddr, type, address);
+ tor_free(address);
+ } else
+ conn = NULL;
+
if (!conn) {
r = -1;
} else {
@@ -1115,33 +1298,46 @@
if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress,
options->ORPort, "0.0.0.0",
- replaced_conns, new_conns, options->ClientOnly)<0)
+ replaced_conns, new_conns, options->ClientOnly,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
options->DirPort, "0.0.0.0",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress,
options->SocksPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
options->TransPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NatdListenAddress,
options->NatdPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress,
options->DNSPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
options->ControlListenAddress,
options->ControlPort, "127.0.0.1",
- replaced_conns, new_conns, 0)<0)
+ replaced_conns, new_conns, 0,
+ AF_INET)<0)
return -1;
+ if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
+ options->ControlSocket,
+ options->ControlSocket ? 1 : 0, NULL,
+ replaced_conns, new_conns, 0,
+ AF_UNIX)<0)
+ return -1;
return 0;
}
Index: src/or/directory.c
===================================================================
--- src/or/directory.c (revision 10502)
+++ src/or/directory.c (working copy)
@@ -490,7 +490,7 @@
tor_assert(0);
}
- conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR));
+ conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR, AF_INET));
/* set up conn so it's got all the data we need to remember */
conn->_base.addr = addr;
Index: src/or/cpuworker.c
===================================================================
--- src/or/cpuworker.c (revision 10502)
+++ src/or/cpuworker.c (working copy)
@@ -339,7 +339,7 @@
tor_free(fdarray);
#endif
- conn = connection_new(CONN_TYPE_CPUWORKER);
+ conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX);
set_socket_nonblocking(fd);
Index: src/or/dnsserv.c
===================================================================
--- src/or/dnsserv.c (revision 10502)
+++ src/or/dnsserv.c (working copy)
@@ -110,7 +110,7 @@
/* XXXX020 Send a stream event to the controller. */
/* Make a new dummy AP connection, and attach the request to it. */
- conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP));
+ conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP, AF_INET));
conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
if (q->type == EVDNS_TYPE_A)
conn->socks_request->command = SOCKS_COMMAND_RESOLVE;