|
@@ -43,11 +43,12 @@
|
|
|
static connection_t *connection_create_listener(
|
|
|
const struct sockaddr *listensockaddr,
|
|
|
socklen_t listensocklen, int type,
|
|
|
- char* address);
|
|
|
+ const char *address,
|
|
|
+ const port_cfg_t *portcfg);
|
|
|
static void connection_init(time_t now, connection_t *conn, int type,
|
|
|
int socket_family);
|
|
|
static int connection_init_accepted_conn(connection_t *conn,
|
|
|
- uint8_t listener_type);
|
|
|
+ const listener_connection_t *listener);
|
|
|
static int connection_handle_listener_read(connection_t *conn, int new_type);
|
|
|
#ifndef USE_BUFFEREVENTS
|
|
|
static int connection_bucket_should_increase(int bucket,
|
|
@@ -76,6 +77,15 @@ static uint32_t last_interface_ip = 0;
|
|
|
* Used to detect IP address changes. */
|
|
|
static smartlist_t *outgoing_addrs = NULL;
|
|
|
|
|
|
+#define CASE_ANY_LISTENER_TYPE \
|
|
|
+ case CONN_TYPE_OR_LISTENER: \
|
|
|
+ case CONN_TYPE_AP_LISTENER: \
|
|
|
+ case CONN_TYPE_DIR_LISTENER: \
|
|
|
+ case CONN_TYPE_CONTROL_LISTENER: \
|
|
|
+ case CONN_TYPE_AP_TRANS_LISTENER: \
|
|
|
+ case CONN_TYPE_AP_NATD_LISTENER: \
|
|
|
+ case CONN_TYPE_AP_DNS_LISTENER
|
|
|
+
|
|
|
/**************************************************************/
|
|
|
|
|
|
/**
|
|
@@ -116,13 +126,7 @@ conn_state_to_string(int type, int state)
|
|
|
{
|
|
|
static char buf[96];
|
|
|
switch (type) {
|
|
|
- case CONN_TYPE_OR_LISTENER:
|
|
|
- case CONN_TYPE_AP_LISTENER:
|
|
|
- case CONN_TYPE_AP_TRANS_LISTENER:
|
|
|
- case CONN_TYPE_AP_NATD_LISTENER:
|
|
|
- case CONN_TYPE_AP_DNS_LISTENER:
|
|
|
- case CONN_TYPE_DIR_LISTENER:
|
|
|
- case CONN_TYPE_CONTROL_LISTENER:
|
|
|
+ CASE_ANY_LISTENER_TYPE:
|
|
|
if (state == LISTENER_STATE_READY)
|
|
|
return "ready";
|
|
|
break;
|
|
@@ -265,6 +269,17 @@ control_connection_new(int socket_family)
|
|
|
return control_conn;
|
|
|
}
|
|
|
|
|
|
+/** Allocate and return a new listener_connection_t, initialized as by
|
|
|
+ * connection_init(). */
|
|
|
+listener_connection_t *
|
|
|
+listener_connection_new(int type, int socket_family)
|
|
|
+{
|
|
|
+ listener_connection_t *listener_conn =
|
|
|
+ tor_malloc_zero(sizeof(listener_connection_t));
|
|
|
+ connection_init(time(NULL), TO_CONN(listener_conn), type, socket_family);
|
|
|
+ return listener_conn;
|
|
|
+}
|
|
|
+
|
|
|
/** Allocate, initialize, and return a new connection_t subtype of <b>type</b>
|
|
|
* to make or receive connections of address family <b>socket_family</b>. The
|
|
|
* type should be one of the CONN_TYPE_* constants. */
|
|
@@ -285,6 +300,9 @@ connection_new(int type, int socket_family)
|
|
|
case CONN_TYPE_CONTROL:
|
|
|
return TO_CONN(control_connection_new(socket_family));
|
|
|
|
|
|
+ CASE_ANY_LISTENER_TYPE:
|
|
|
+ return TO_CONN(listener_connection_new(type, socket_family));
|
|
|
+
|
|
|
default: {
|
|
|
connection_t *conn = tor_malloc_zero(sizeof(connection_t));
|
|
|
connection_init(time(NULL), conn, type, socket_family);
|
|
@@ -325,6 +343,8 @@ connection_init(time_t now, connection_t *conn, int type, int socket_family)
|
|
|
case CONN_TYPE_CONTROL:
|
|
|
conn->magic = CONTROL_CONNECTION_MAGIC;
|
|
|
break;
|
|
|
+ CASE_ANY_LISTENER_TYPE:
|
|
|
+ conn->magic = LISTENER_CONNECTION_MAGIC;
|
|
|
default:
|
|
|
conn->magic = BASE_CONNECTION_MAGIC;
|
|
|
break;
|
|
@@ -396,6 +416,11 @@ _connection_free(connection_t *conn)
|
|
|
mem = TO_CONTROL_CONN(conn);
|
|
|
memlen = sizeof(control_connection_t);
|
|
|
break;
|
|
|
+ CASE_ANY_LISTENER_TYPE:
|
|
|
+ tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC);
|
|
|
+ mem = TO_LISTENER_CONN(conn);
|
|
|
+ memlen = sizeof(listener_connection_t);
|
|
|
+ break;
|
|
|
default:
|
|
|
tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
|
|
|
mem = conn;
|
|
@@ -442,9 +467,9 @@ _connection_free(connection_t *conn)
|
|
|
if (CONN_IS_EDGE(conn)) {
|
|
|
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
|
|
|
tor_free(edge_conn->chosen_exit_name);
|
|
|
+ tor_free(edge_conn->original_dest_address);
|
|
|
if (edge_conn->socks_request)
|
|
|
socks_request_free(edge_conn->socks_request);
|
|
|
-
|
|
|
rend_data_free(edge_conn->rend_data);
|
|
|
}
|
|
|
if (conn->type == CONN_TYPE_CONTROL) {
|
|
@@ -701,48 +726,6 @@ connection_expire_held_open(void)
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-/** 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 not NULL <b>readable_address</b> will contain a copy of the host part of
|
|
|
- * <b>listenaddress</b>.
|
|
|
- *
|
|
|
- * The listenaddr struct has to be freed by the caller.
|
|
|
- */
|
|
|
-static struct sockaddr_in *
|
|
|
-create_inet_sockaddr(const char *listenaddress, int listenport,
|
|
|
- char **readable_address, socklen_t *socklen_out) {
|
|
|
- struct sockaddr_in *listenaddr = NULL;
|
|
|
- uint32_t addr;
|
|
|
- uint16_t usePort = 0;
|
|
|
-
|
|
|
- if (parse_addr_port(LOG_WARN,
|
|
|
- listenaddress, readable_address, &addr, &usePort)<0) {
|
|
|
- log_warn(LD_CONFIG,
|
|
|
- "Error parsing/resolving ListenAddress %s", listenaddress);
|
|
|
- goto err;
|
|
|
- }
|
|
|
- if (usePort==0) {
|
|
|
- if (listenport != CFG_AUTO_PORT)
|
|
|
- usePort = listenport;
|
|
|
- }
|
|
|
-
|
|
|
- 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);
|
|
|
-
|
|
|
- *socklen_out = sizeof(struct sockaddr_in);
|
|
|
-
|
|
|
- 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.
|
|
@@ -877,12 +860,15 @@ make_socket_reuseable(tor_socket_t sock)
|
|
|
static connection_t *
|
|
|
connection_create_listener(const struct sockaddr *listensockaddr,
|
|
|
socklen_t socklen,
|
|
|
- int type, char* address)
|
|
|
+ int type, const char *address,
|
|
|
+ const port_cfg_t *port_cfg)
|
|
|
{
|
|
|
+ listener_connection_t *lis_conn;
|
|
|
connection_t *conn;
|
|
|
tor_socket_t s; /* the socket we're going to make */
|
|
|
uint16_t usePort = 0, gotPort = 0;
|
|
|
int start_reading = 0;
|
|
|
+ static int global_next_session_group = SESSION_GROUP_FIRST_AUTO;
|
|
|
|
|
|
if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
|
|
|
warn_too_many_conns();
|
|
@@ -999,12 +985,23 @@ connection_create_listener(const struct sockaddr *listensockaddr,
|
|
|
|
|
|
set_socket_nonblocking(s);
|
|
|
|
|
|
- conn = connection_new(type, listensockaddr->sa_family);
|
|
|
+ lis_conn = listener_connection_new(type, listensockaddr->sa_family);
|
|
|
+ conn = TO_CONN(lis_conn);
|
|
|
conn->socket_family = listensockaddr->sa_family;
|
|
|
conn->s = s;
|
|
|
conn->address = tor_strdup(address);
|
|
|
conn->port = gotPort;
|
|
|
|
|
|
+ if (port_cfg->isolation_flags) {
|
|
|
+ lis_conn->isolation_flags = port_cfg->isolation_flags;
|
|
|
+ if (port_cfg->session_group >= 0) {
|
|
|
+ lis_conn->session_group = port_cfg->session_group;
|
|
|
+ } else {
|
|
|
+ /* XXXX023 This can wrap after ~INT_MAX ports are opened. */
|
|
|
+ lis_conn->session_group = global_next_session_group--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (connection_add(conn) < 0) { /* no space, forget it */
|
|
|
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
|
|
|
connection_free(conn);
|
|
@@ -1217,7 +1214,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
|
|
return 0; /* no need to tear down the parent */
|
|
|
}
|
|
|
|
|
|
- if (connection_init_accepted_conn(newconn, conn->type) < 0) {
|
|
|
+ if (connection_init_accepted_conn(newconn, TO_LISTENER_CONN(conn)) < 0) {
|
|
|
if (! newconn->marked_for_close)
|
|
|
connection_mark_for_close(newconn);
|
|
|
return 0;
|
|
@@ -1231,7 +1228,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
|
|
* and place it in circuit_wait.
|
|
|
*/
|
|
|
static int
|
|
|
-connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
|
|
|
+connection_init_accepted_conn(connection_t *conn,
|
|
|
+ const listener_connection_t *listener)
|
|
|
{
|
|
|
connection_start_reading(conn);
|
|
|
|
|
@@ -1240,7 +1238,10 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
|
|
|
control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
|
|
|
return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
|
|
|
case CONN_TYPE_AP:
|
|
|
- switch (listener_type) {
|
|
|
+ TO_EDGE_CONN(conn)->isolation_flags = listener->isolation_flags;
|
|
|
+ TO_EDGE_CONN(conn)->session_group = listener->session_group;
|
|
|
+ TO_EDGE_CONN(conn)->nym_epoch = get_signewnym_epoch();
|
|
|
+ switch (TO_CONN(listener)->type) {
|
|
|
case CONN_TYPE_AP_LISTENER:
|
|
|
conn->state = AP_CONN_STATE_SOCKS_WAIT;
|
|
|
break;
|
|
@@ -1741,175 +1742,185 @@ connection_read_proxy_handshake(connection_t *conn)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Launch any configured listener connections of type <b>type</b>. (A
|
|
|
- * listener is configured if <b>port_option</b> is non-zero. If any
|
|
|
- * ListenAddress configuration options are given in <b>cfg</b>, create a
|
|
|
- * connection binding to each one. Otherwise, create a single
|
|
|
- * connection binding to the address <b>default_addr</b>.)
|
|
|
- *
|
|
|
- * Only launch the listeners of this type that are not already open, and
|
|
|
- * only close listeners that are no longer wanted. Existing listeners
|
|
|
- * that are still configured are not touched.
|
|
|
+/** Given a list of listener connections in <b>old_conns</b>, and list of
|
|
|
+ * port_cfg_t entries in <b>ports</b>, open a new listener for every port in
|
|
|
+ * <b>ports</b> that does not already have a listener in <b>old_conns</b>.
|
|
|
*
|
|
|
- * If <b>disable_all_conns</b> is set, then never open new conns, and
|
|
|
- * close the existing ones.
|
|
|
+ * Remove from <b>old_conns</b> every connection that has a corresponding
|
|
|
+ * entry in <b>ports</b>. Add to <b>new_conns</b> new every connection we
|
|
|
+ * launch.
|
|
|
*
|
|
|
- * Add all old conns that should be closed to <b>replaced_conns</b>.
|
|
|
- * Add all new connections to <b>new_conns</b>.
|
|
|
- */
|
|
|
+ * Return 0 on success, -1 on failure.
|
|
|
+ **/
|
|
|
static int
|
|
|
-retry_listeners(int type, config_line_t *cfg,
|
|
|
- int port_option, const char *default_addr,
|
|
|
- smartlist_t *replaced_conns,
|
|
|
- smartlist_t *new_conns,
|
|
|
- int disable_all_conns,
|
|
|
- int socket_family)
|
|
|
+retry_listener_ports(smartlist_t *old_conns,
|
|
|
+ const smartlist_t *ports,
|
|
|
+ smartlist_t *new_conns)
|
|
|
{
|
|
|
- smartlist_t *launch = smartlist_create(), *conns;
|
|
|
- int free_launch_elts = 1;
|
|
|
- int r;
|
|
|
- config_line_t *c;
|
|
|
- connection_t *conn;
|
|
|
- config_line_t *line;
|
|
|
-
|
|
|
- tor_assert(socket_family == AF_INET || socket_family == AF_UNIX);
|
|
|
+ smartlist_t *launch = smartlist_create();
|
|
|
+ int r = 0;
|
|
|
|
|
|
- if (cfg && port_option) {
|
|
|
- for (c = cfg; c; c = c->next) {
|
|
|
- smartlist_add(launch, c);
|
|
|
- }
|
|
|
- free_launch_elts = 0;
|
|
|
- } else if (port_option) {
|
|
|
- line = tor_malloc_zero(sizeof(config_line_t));
|
|
|
- line->key = tor_strdup("");
|
|
|
- line->value = tor_strdup(default_addr);
|
|
|
- smartlist_add(launch, line);
|
|
|
- }
|
|
|
+ smartlist_add_all(launch, ports);
|
|
|
|
|
|
- /*
|
|
|
- SMARTLIST_FOREACH(launch, config_line_t *, l,
|
|
|
- log_fn(LOG_NOTICE, "#%s#%s", l->key, l->value));
|
|
|
- */
|
|
|
+ /* Iterate through old_conns, comparing it to launch: remove from both lists
|
|
|
+ * each pair of elements that corresponds to the same port. */
|
|
|
+ SMARTLIST_FOREACH_BEGIN(old_conns, connection_t *, conn) {
|
|
|
+ const port_cfg_t *found_port = NULL;
|
|
|
|
|
|
- conns = get_connection_array();
|
|
|
- SMARTLIST_FOREACH(conns, connection_t *, conn,
|
|
|
- {
|
|
|
- if (conn->type != type ||
|
|
|
- conn->socket_family != socket_family ||
|
|
|
- conn->marked_for_close)
|
|
|
- continue;
|
|
|
/* Okay, so this is a listener. Is it configured? */
|
|
|
- line = NULL;
|
|
|
- SMARTLIST_FOREACH(launch, config_line_t *, wanted,
|
|
|
- {
|
|
|
- char *address=NULL;
|
|
|
- uint16_t port;
|
|
|
- switch (socket_family) {
|
|
|
- case AF_INET:
|
|
|
- if (!parse_addr_port(LOG_WARN,
|
|
|
- wanted->value, &address, NULL, &port)) {
|
|
|
- int addr_matches = !strcasecmp(address, conn->address);
|
|
|
- int port_matches;
|
|
|
- tor_free(address);
|
|
|
- if (port) {
|
|
|
- /* The Listener line has a port */
|
|
|
- port_matches = (port == conn->port);
|
|
|
- } else if (port_option == CFG_AUTO_PORT) {
|
|
|
- /* The Listener line has no port, and the Port line is "auto".
|
|
|
- * "auto" matches anything; transitions from any port to
|
|
|
- * "auto" succeed. */
|
|
|
- port_matches = 1;
|
|
|
- } else {
|
|
|
- /* The Listener line has no port, and the Port line is "auto".
|
|
|
- * "auto" matches anything; transitions from any port to
|
|
|
- * "auto" succeed. */
|
|
|
- port_matches = (port_option == conn->port);
|
|
|
- }
|
|
|
- if (port_matches && addr_matches) {
|
|
|
- line = wanted;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
- case AF_UNIX:
|
|
|
- if (!strcasecmp(wanted->value, conn->address)) {
|
|
|
- line = wanted;
|
|
|
- break;
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
- tor_assert(0);
|
|
|
+ SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, wanted) {
|
|
|
+ if (conn->type != wanted->type)
|
|
|
+ continue;
|
|
|
+ if ((conn->socket_family != AF_UNIX && wanted->is_unix_addr) ||
|
|
|
+ (conn->socket_family == AF_UNIX && ! wanted->is_unix_addr))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (wanted->is_unix_addr) {
|
|
|
+ if (conn->socket_family == AF_UNIX &&
|
|
|
+ !strcmp(wanted->unix_addr, conn->address)) {
|
|
|
+ found_port = wanted;
|
|
|
+ break;
|
|
|
}
|
|
|
- });
|
|
|
- if (!line || disable_all_conns) {
|
|
|
- /* This one isn't configured. Close it. */
|
|
|
- log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
|
|
|
- conn_type_to_string(type), conn->address, conn->port);
|
|
|
- if (replaced_conns) {
|
|
|
- smartlist_add(replaced_conns, conn);
|
|
|
} else {
|
|
|
- connection_close_immediate(conn);
|
|
|
- connection_mark_for_close(conn);
|
|
|
+ int port_matches;
|
|
|
+ if (wanted->port == CFG_AUTO_PORT) {
|
|
|
+ port_matches = 1;
|
|
|
+ } else {
|
|
|
+ port_matches = (wanted->port == conn->port);
|
|
|
+ }
|
|
|
+ if (port_matches && tor_addr_eq(&wanted->addr, &conn->addr)) {
|
|
|
+ found_port = wanted;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- } else {
|
|
|
- /* It's configured; we don't need to launch it. */
|
|
|
+ } SMARTLIST_FOREACH_END(wanted);
|
|
|
+
|
|
|
+ if (found_port) {
|
|
|
+ /* This listener is already running; we don't need to launch it. */
|
|
|
// log_debug(LD_NET, "Already have %s on %s:%d",
|
|
|
// conn_type_to_string(type), conn->address, conn->port);
|
|
|
- smartlist_remove(launch, line);
|
|
|
- if (free_launch_elts)
|
|
|
- config_free_lines(line);
|
|
|
+ smartlist_remove(launch, found_port);
|
|
|
+ /* And we can remove the connection from old_conns too. */
|
|
|
+ SMARTLIST_DEL_CURRENT(old_conns, conn);
|
|
|
}
|
|
|
- });
|
|
|
+ } SMARTLIST_FOREACH_END(conn);
|
|
|
|
|
|
/* Now open all the listeners that are configured but not opened. */
|
|
|
- r = 0;
|
|
|
- if (!disable_all_conns) {
|
|
|
- SMARTLIST_FOREACH_BEGIN(launch, config_line_t *, cfg_line) {
|
|
|
- char *address = NULL;
|
|
|
- struct sockaddr *listensockaddr;
|
|
|
- socklen_t listensocklen = 0;
|
|
|
-
|
|
|
- switch (socket_family) {
|
|
|
- case AF_INET:
|
|
|
- listensockaddr = (struct sockaddr *)
|
|
|
- create_inet_sockaddr(cfg_line->value,
|
|
|
- port_option,
|
|
|
- &address, &listensocklen);
|
|
|
- break;
|
|
|
- case AF_UNIX:
|
|
|
- listensockaddr = (struct sockaddr *)
|
|
|
- create_unix_sockaddr(cfg_line->value,
|
|
|
- &address, &listensocklen);
|
|
|
- break;
|
|
|
- default:
|
|
|
- tor_assert(0);
|
|
|
- }
|
|
|
+ SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, port) {
|
|
|
+ struct sockaddr *listensockaddr;
|
|
|
+ socklen_t listensocklen = 0;
|
|
|
+ char *address=NULL;
|
|
|
+ connection_t *conn;
|
|
|
+
|
|
|
+ if (port->is_unix_addr) {
|
|
|
+ listensockaddr = (struct sockaddr *)
|
|
|
+ create_unix_sockaddr(port->unix_addr,
|
|
|
+ &address, &listensocklen);
|
|
|
+ } else {
|
|
|
+ listensockaddr = tor_malloc(sizeof(struct sockaddr_storage));
|
|
|
+ listensocklen = tor_addr_to_sockaddr(&port->addr,
|
|
|
+ port->port,
|
|
|
+ listensockaddr,
|
|
|
+ sizeof(struct sockaddr_storage));
|
|
|
+ address = tor_dup_addr(&port->addr);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (listensockaddr) {
|
|
|
+ conn = connection_create_listener(listensockaddr, listensocklen,
|
|
|
+ port->type, address, port);
|
|
|
+ tor_free(listensockaddr);
|
|
|
+ tor_free(address);
|
|
|
+ } else {
|
|
|
+ conn = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!conn) {
|
|
|
+ r = -1;
|
|
|
+ } else {
|
|
|
+ if (new_conns)
|
|
|
+ smartlist_add(new_conns, conn);
|
|
|
+ }
|
|
|
+ } SMARTLIST_FOREACH_END(port);
|
|
|
+
|
|
|
+ smartlist_free(launch);
|
|
|
+
|
|
|
+ return r;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Launch any configured listener connections of type <b>type</b>. (A
|
|
|
+ * listener is configured if <b>port_option</b> is non-zero. If any
|
|
|
+ * ListenAddress configuration options are given in <b>cfg</b>, create a
|
|
|
+ * connection binding to each one. Otherwise, create a single
|
|
|
+ * connection binding to the address <b>default_addr</b>.)
|
|
|
+ *
|
|
|
+ * We assume that we're starting with a list of existing listener connection_t
|
|
|
+ * pointers in <b>old_conns</b>: we do not launch listeners that are already
|
|
|
+ * in that list. Instead, we just remove them from the list.
|
|
|
+ *
|
|
|
+ * All new connections we launch are added to <b>new_conns</b>.
|
|
|
+ */
|
|
|
+static int
|
|
|
+retry_listeners(smartlist_t *old_conns,
|
|
|
+ int type, const config_line_t *cfg,
|
|
|
+ int port_option, const char *default_addr,
|
|
|
+ smartlist_t *new_conns,
|
|
|
+ int is_sockaddr_un)
|
|
|
+{
|
|
|
+ smartlist_t *ports = smartlist_create();
|
|
|
+ tor_addr_t dflt_addr;
|
|
|
+ int retval = 0;
|
|
|
|
|
|
- if (listensockaddr) {
|
|
|
- conn = connection_create_listener(listensockaddr, listensocklen,
|
|
|
- type, address);
|
|
|
- tor_free(listensockaddr);
|
|
|
- tor_free(address);
|
|
|
- } else
|
|
|
- conn = NULL;
|
|
|
+ if (default_addr) {
|
|
|
+ tor_addr_from_str(&dflt_addr, default_addr);
|
|
|
+ } else {
|
|
|
+ tor_addr_make_unspec(&dflt_addr);
|
|
|
+ }
|
|
|
|
|
|
- if (!conn) {
|
|
|
- r = -1;
|
|
|
+ if (port_option) {
|
|
|
+ if (!cfg) {
|
|
|
+ port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t));
|
|
|
+ tor_addr_copy(&port->addr, &dflt_addr);
|
|
|
+ port->port = port_option;
|
|
|
+ port->type = type;
|
|
|
+ smartlist_add(ports, port);
|
|
|
+ } else {
|
|
|
+ const config_line_t *c;
|
|
|
+ for (c = cfg; c; c = c->next) {
|
|
|
+ port_cfg_t *port;
|
|
|
+ tor_addr_t addr;
|
|
|
+ uint16_t portval = 0;
|
|
|
+ if (is_sockaddr_un) {
|
|
|
+ size_t len = strlen(c->value);
|
|
|
+ port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1);
|
|
|
+ port->is_unix_addr = 1;
|
|
|
+ memcpy(port->unix_addr, c->value, len+1);
|
|
|
} else {
|
|
|
- if (new_conns)
|
|
|
- smartlist_add(new_conns, conn);
|
|
|
+ if (tor_addr_port_parse(c->value, &addr, &portval) < 0) {
|
|
|
+ log_warn(LD_CONFIG, "Can't parse/resolve %s %s",
|
|
|
+ c->key, c->value);
|
|
|
+ retval = -1;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ port = tor_malloc_zero(sizeof(port_cfg_t));
|
|
|
+ tor_addr_copy(&port->addr, &addr);
|
|
|
}
|
|
|
- } SMARTLIST_FOREACH_END(cfg_line);
|
|
|
+ port->type = type;
|
|
|
+ port->port = portval ? portval : port_option;
|
|
|
+ smartlist_add(ports, port);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (free_launch_elts) {
|
|
|
- SMARTLIST_FOREACH(launch, config_line_t *, cfg_line,
|
|
|
- config_free_lines(cfg_line));
|
|
|
- }
|
|
|
- smartlist_free(launch);
|
|
|
+ if (retval == -1)
|
|
|
+ goto cleanup;
|
|
|
|
|
|
- return r;
|
|
|
+ retval = retry_listener_ports(old_conns, ports, new_conns);
|
|
|
+
|
|
|
+ cleanup:
|
|
|
+ SMARTLIST_FOREACH(ports, port_cfg_t *, p, tor_free(p));
|
|
|
+ smartlist_free(ports);
|
|
|
+ return retval;
|
|
|
}
|
|
|
|
|
|
/** Launch listeners for each port you should have open. Only launch
|
|
@@ -1923,54 +1934,62 @@ int
|
|
|
retry_all_listeners(smartlist_t *replaced_conns,
|
|
|
smartlist_t *new_conns)
|
|
|
{
|
|
|
+ smartlist_t *listeners = smartlist_create();
|
|
|
const or_options_t *options = get_options();
|
|
|
int retval = 0;
|
|
|
const uint16_t old_or_port = router_get_advertised_or_port(options);
|
|
|
const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0);
|
|
|
|
|
|
- if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress,
|
|
|
- options->ORPort, "0.0.0.0",
|
|
|
- replaced_conns, new_conns, options->ClientOnly,
|
|
|
- AF_INET)<0)
|
|
|
- retval = -1;
|
|
|
- if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
|
|
|
- options->DirPort, "0.0.0.0",
|
|
|
- replaced_conns, new_conns, options->ClientOnly,
|
|
|
- AF_INET)<0)
|
|
|
- retval = -1;
|
|
|
- if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress,
|
|
|
- options->SocksPort, "127.0.0.1",
|
|
|
- replaced_conns, new_conns, 0,
|
|
|
- AF_INET)<0)
|
|
|
- retval = -1;
|
|
|
- if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
|
|
|
- options->TransPort, "127.0.0.1",
|
|
|
- replaced_conns, new_conns, 0,
|
|
|
- AF_INET)<0)
|
|
|
- retval = -1;
|
|
|
- if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NATDListenAddress,
|
|
|
- options->NATDPort, "127.0.0.1",
|
|
|
- replaced_conns, new_conns, 0,
|
|
|
- AF_INET)<0)
|
|
|
- retval = -1;
|
|
|
- if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress,
|
|
|
- options->DNSPort, "127.0.0.1",
|
|
|
- replaced_conns, new_conns, 0,
|
|
|
- AF_INET)<0)
|
|
|
+ SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
|
|
|
+ if (connection_is_listener(conn) && !conn->marked_for_close)
|
|
|
+ smartlist_add(listeners, conn);
|
|
|
+ } SMARTLIST_FOREACH_END(conn);
|
|
|
+
|
|
|
+ if (! options->ClientOnly) {
|
|
|
+ if (retry_listeners(listeners,
|
|
|
+ CONN_TYPE_OR_LISTENER, options->ORListenAddress,
|
|
|
+ options->ORPort, "0.0.0.0",
|
|
|
+ new_conns, 0) < 0)
|
|
|
+ retval = -1;
|
|
|
+ if (retry_listeners(listeners,
|
|
|
+ CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
|
|
|
+ options->DirPort, "0.0.0.0",
|
|
|
+ new_conns, 0) < 0)
|
|
|
+ retval = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (retry_listener_ports(listeners,
|
|
|
+ get_configured_client_ports(),
|
|
|
+ new_conns) < 0)
|
|
|
retval = -1;
|
|
|
- if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
|
|
|
+ if (retry_listeners(listeners,
|
|
|
+ CONN_TYPE_CONTROL_LISTENER,
|
|
|
options->ControlListenAddress,
|
|
|
options->ControlPort, "127.0.0.1",
|
|
|
- replaced_conns, new_conns, 0,
|
|
|
- AF_INET)<0)
|
|
|
+ new_conns, 0) < 0)
|
|
|
return -1;
|
|
|
- if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
|
|
|
+ if (retry_listeners(listeners,
|
|
|
+ CONN_TYPE_CONTROL_LISTENER,
|
|
|
options->ControlSocket,
|
|
|
options->ControlSocket ? 1 : 0, NULL,
|
|
|
- replaced_conns, new_conns, 0,
|
|
|
- AF_UNIX)<0)
|
|
|
+ new_conns, 1) < 0)
|
|
|
return -1;
|
|
|
|
|
|
+ /* Any members that were still in 'listeners' don't correspond to
|
|
|
+ * any configured port. Kill 'em. */
|
|
|
+ SMARTLIST_FOREACH_BEGIN(listeners, connection_t *, conn) {
|
|
|
+ log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
|
|
|
+ conn_type_to_string(conn->type), conn->address, conn->port);
|
|
|
+ if (replaced_conns) {
|
|
|
+ smartlist_add(replaced_conns, conn);
|
|
|
+ } else {
|
|
|
+ connection_close_immediate(conn);
|
|
|
+ connection_mark_for_close(conn);
|
|
|
+ }
|
|
|
+ } SMARTLIST_FOREACH_END(conn);
|
|
|
+
|
|
|
+ smartlist_free(listeners);
|
|
|
+
|
|
|
if (old_or_port != router_get_advertised_or_port(options) ||
|
|
|
old_dir_port != router_get_advertised_dir_port(options, 0)) {
|
|
|
/* Our chosen ORPort or DirPort is not what it used to be: the
|
|
@@ -3994,13 +4013,7 @@ assert_connection_ok(connection_t *conn, time_t now)
|
|
|
|
|
|
switch (conn->type)
|
|
|
{
|
|
|
- case CONN_TYPE_OR_LISTENER:
|
|
|
- case CONN_TYPE_AP_LISTENER:
|
|
|
- case CONN_TYPE_AP_TRANS_LISTENER:
|
|
|
- case CONN_TYPE_AP_NATD_LISTENER:
|
|
|
- case CONN_TYPE_DIR_LISTENER:
|
|
|
- case CONN_TYPE_CONTROL_LISTENER:
|
|
|
- case CONN_TYPE_AP_DNS_LISTENER:
|
|
|
+ CASE_ANY_LISTENER_TYPE:
|
|
|
tor_assert(conn->state == LISTENER_STATE_READY);
|
|
|
break;
|
|
|
case CONN_TYPE_OR:
|