aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/circuitlist.c2
-rw-r--r--src/or/config.c24
-rw-r--r--src/or/connection.c34
-rw-r--r--src/or/connection_edge.c141
-rw-r--r--src/or/connection_edge.h8
-rw-r--r--src/or/dnsserv.c10
-rw-r--r--src/or/or.h57
7 files changed, 253 insertions, 23 deletions
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 93f5fd349..9f688801f 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -550,6 +550,8 @@ circuit_free(circuit_t *circ)
crypto_free_pk_env(ocirc->intro_key);
rend_data_free(ocirc->rend_data);
+
+ tor_free(ocirc->dest_address);
} else {
or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
/* Remember cell statistics for this circuit before deallocating. */
diff --git a/src/or/config.c b/src/or/config.c
index 0774b2891..2ca9c6699 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -577,6 +577,7 @@ static int parse_client_transport_line(const char *line, int validate_only);
static int parse_dir_server_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
+static void port_cfg_free(port_cfg_t *port);
static int parse_client_ports(const or_options_t *options, int validate_only,
char **msg_out, int *n_ports_out);
static int validate_data_directory(or_options_t *options);
@@ -4846,6 +4847,13 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
return r;
}
+/** Free all storage held in <b>port</b> */
+static void
+port_cfg_free(port_cfg_t *port)
+{
+ tor_free(port);
+}
+
/** Warn for every port in <b>ports</b> that is not on a loopback address. */
static void
warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname)
@@ -4955,8 +4963,8 @@ parse_client_port_config(smartlist_t *out,
cfg->type = listener_type;
cfg->port = port ? port : defaultport;
tor_addr_copy(&cfg->addr, &addr);
- cfg->sessiongroup = -1;
- cfg->isolate = ISO_DEFAULT;
+ cfg->session_group = -1;
+ cfg->isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg);
}
}
@@ -4974,8 +4982,8 @@ parse_client_port_config(smartlist_t *out,
cfg->type = listener_type;
cfg->port = defaultport;
tor_addr_from_str(&cfg->addr, defaultaddr);
- cfg->sessiongroup = -1;
- cfg->isolate = ISO_DEFAULT;
+ cfg->session_group = -1;
+ cfg->isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg);
}
return 0;
@@ -5094,8 +5102,8 @@ parse_client_port_config(smartlist_t *out,
cfg->type = listener_type;
cfg->port = port;
tor_addr_copy(&cfg->addr, &addr);
- cfg->sessiongroup = sessiongroup;
- cfg->isolate = isolation;
+ cfg->session_group = sessiongroup;
+ cfg->isolation_flags = isolation;
smartlist_add(out, cfg);
}
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
@@ -5169,7 +5177,7 @@ parse_client_ports(const or_options_t *options, int validate_only,
if (!validate_only) {
if (configured_client_ports) {
SMARTLIST_FOREACH(configured_client_ports,
- port_cfg_t *, p, tor_free(p));
+ port_cfg_t *, p, port_cfg_free(p));
smartlist_free(configured_client_ports);
}
configured_client_ports = ports;
@@ -5179,7 +5187,7 @@ parse_client_ports(const or_options_t *options, int validate_only,
retval = 0;
err:
if (ports) {
- SMARTLIST_FOREACH(ports, port_cfg_t *, p, tor_free(p));
+ SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p));
smartlist_free(ports);
}
return retval;
diff --git a/src/or/connection.c b/src/or/connection.c
index db0d78975..b627dcae1 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -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,
@@ -859,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 = -2;
if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
warn_too_many_conns();
@@ -981,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);
@@ -1199,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;
@@ -1213,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);
@@ -1222,7 +1238,9 @@ 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;
+ switch (TO_CONN(listener)->type) {
case CONN_TYPE_AP_LISTENER:
conn->state = AP_CONN_STATE_SOCKS_WAIT;
break;
@@ -1808,7 +1826,7 @@ retry_listener_ports(smartlist_t *old_conns,
if (listensockaddr) {
conn = connection_create_listener(listensockaddr, listensocklen,
- port->type, address);
+ port->type, address, port);
tor_free(listensockaddr);
tor_free(address);
} else {
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index f2ddfc76d..6d247dceb 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -3266,3 +3266,144 @@ parse_extended_hostname(char *address, int allowdotexit)
return BAD_HOSTNAME;
}
+/** Return true iff <b>a</b> and <b>b</b> have isolation rules and fields that
+ * make it permissible to put them on the same circuit.*/
+int
+connection_edge_streams_are_compatible(const edge_connection_t *a,
+ const edge_connection_t *b)
+{
+ const uint8_t iso = a->isolation_flags | b->isolation_flags;
+
+ if ((iso & ISO_DESTPORT) && a->socks_request->port != b->socks_request->port)
+ return 0;
+ /* XXXX023 Not quite right: we care about addresses that resolve to the same
+ place */
+ if ((iso & ISO_DESTADDR) &&
+ strcasecmp(a->socks_request->address, b->socks_request->address))
+ return 0;
+ /* XXXX023 Waititing for ticket #1666 */
+ /*
+ if ((iso & ISO_SOCKSAUTH) &&
+ strcasecmp(a->socks_request->auth, b->socks_request->auth))
+ return 0;
+ */
+ if ((iso & ISO_CLIENTPROTO) &&
+ (TO_CONN(a)->type != TO_CONN(b)->type ||
+ a->socks_request->socks_version != b->socks_request->socks_version))
+ return 0;
+ if ((iso & ISO_CLIENTADDR) &&
+ !tor_addr_eq(&TO_CONN(a)->addr, &TO_CONN(b)->addr))
+ return 0;
+ if ((iso & ISO_SESSIONGRP) && a->session_group != b->session_group)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * Return true iff none of the isolation flags and fields in <b>conn</b>
+ * should prevent it from being attached to <b>circ</b>.
+ */
+int
+connection_edge_compatible_with_circuit(const edge_connection_t *conn,
+ const origin_circuit_t *circ)
+{
+ const uint8_t iso = conn->isolation_flags;
+
+ /* If circ has never been used for an isolated connection, we can
+ * totally use it for this one. */
+ if (!circ->isolation_values_set)
+ return 1;
+
+ /* If circ has been used for connections having more than one value
+ * for some field f, it will have the corresponding bit set in
+ * isolation_flags_mixed. If isolation_flags_mixed has any bits
+ * in common with iso, then conn must be isolated from at least
+ * one stream that has been attached to circ. */
+ if ((iso & circ->isolation_flags_mixed) != 0) {
+ /* For at least one field where conn is isolated, the circuit
+ * already has mixed streams. */
+ return 0;
+ }
+
+ if ((iso & ISO_DESTPORT) && conn->socks_request->port != circ->dest_port)
+ return 0;
+ /* XXXX023 Not quite right: we care about addresses that resolve to the same
+ place */
+ if ((iso & ISO_DESTADDR) &&
+ strcasecmp(conn->socks_request->address, circ->dest_address))
+ return 0;
+ /* XXXX023 Waititing for ticket #1666 */
+ /*
+ if ((iso & ISO_SOCKSAUTH) &&
+ strcasecmp(a->socks_request->auth, b->socks_request->auth))
+ return 0;
+ */
+ if ((iso & ISO_CLIENTPROTO) &&
+ (TO_CONN(conn)->type != circ->client_proto_type ||
+ conn->socks_request->socks_version != circ->client_proto_socksver))
+ return 0;
+ if ((iso & ISO_CLIENTADDR) &&
+ !tor_addr_eq(&TO_CONN(conn)->addr, &circ->client_addr))
+ return 0;
+ if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * If <b>dry_run</b> is false, update <b>circ</b>'s isolation flags and fields
+ * to reflect having had <b>conn</b> attached to it, and return 0. Otherwise,
+ * if <b>dry_run</b> is true, then make no changes to <b>circ</b>, and return
+ * a bitfield of isolation flags that we would have to set in
+ * isolation_flags_mixed to add <b>conn</b> to <b>circ</b>, or -1 if
+ * <b>circ</b> has had no streams attached to it.
+ */
+int
+connection_edge_update_circuit_isolation(const edge_connection_t *conn,
+ origin_circuit_t *circ,
+ int dry_run)
+{
+ if (!circ->isolation_values_set) {
+ if (dry_run)
+ return -1;
+ circ->dest_port = conn->socks_request->port;
+ circ->dest_address = tor_strdup(conn->socks_request->address);
+ circ->client_proto_type = TO_CONN(conn)->type;
+ circ->client_proto_socksver = conn->socks_request->socks_version;
+ tor_addr_copy(&circ->client_addr, &TO_CONN(conn)->addr);
+ circ->session_group = conn->session_group;
+ /* XXXX023 auth too, once #1666 is in. */
+
+ circ->isolation_values_set = 1;
+ return 0;
+ } else {
+ uint8_t mixed = 0;
+ if (conn->socks_request->port != circ->dest_port)
+ mixed |= ISO_DESTPORT;
+ /* XXXX023 Not quite right: we care about addresses that resolve to the
+ same place */
+ if (strcasecmp(conn->socks_request->address, circ->dest_address))
+ mixed |= ISO_DESTADDR;
+ /* XXXX023 auth too, once #1666 is in. */
+ if ((TO_CONN(conn)->type != circ->client_proto_type ||
+ conn->socks_request->socks_version != circ->client_proto_socksver))
+ mixed |= ISO_CLIENTPROTO;
+ if (!tor_addr_eq(&TO_CONN(conn)->addr, &circ->client_addr))
+ mixed |= ISO_CLIENTADDR;
+ if (conn->session_group != circ->session_group)
+ mixed |= ISO_SESSIONGRP;
+
+ if (dry_run)
+ return mixed;
+
+ if ((mixed & conn->isolation_flags) != 0) {
+ log_warn(LD_BUG, "Updating a circuit with seemingly incomaptible "
+ "isolation flags.");
+ }
+ circ->isolation_flags_mixed |= mixed;
+ return 0;
+ }
+}
+
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index 1cb1281db..59865f414 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -103,5 +103,13 @@ hostname_type_t parse_extended_hostname(char *address, int allowdotexit);
int get_pf_socket(void);
#endif
+int connection_edge_streams_are_compatible(const edge_connection_t *a,
+ const edge_connection_t *b);
+int connection_edge_compatible_with_circuit(const edge_connection_t *conn,
+ const origin_circuit_t *circ);
+int connection_edge_update_circuit_isolation(const edge_connection_t *conn,
+ origin_circuit_t *circ,
+ int dry_run);
+
#endif
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 350b13872..b1316ecc6 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -29,8 +29,9 @@
* DNSPort. We need to eventually answer the request <b>req</b>.
*/
static void
-evdns_server_callback(struct evdns_server_request *req, void *_data)
+evdns_server_callback(struct evdns_server_request *req, void *data_)
{
+ const listener_connection_t *listener = data_;
edge_connection_t *conn;
int i = 0;
struct evdns_server_question *q = NULL;
@@ -43,7 +44,7 @@ evdns_server_callback(struct evdns_server_request *req, void *_data)
char *q_name;
tor_assert(req);
- tor_assert(_data == NULL);
+
log_info(LD_APP, "Got a new DNS request!");
req->flags |= 0x80; /* set RA */
@@ -131,6 +132,8 @@ evdns_server_callback(struct evdns_server_request *req, void *_data)
sizeof(conn->socks_request->address));
conn->dns_server_request = req;
+ conn->isolation_flags = listener->isolation_flags;
+ conn->session_group = listener->session_group;
if (connection_add(TO_CONN(conn)) < 0) {
log_warn(LD_APP, "Couldn't register dummy connection for DNS request");
@@ -312,7 +315,8 @@ dnsserv_configure_listener(connection_t *conn)
listener_conn = TO_LISTENER_CONN(conn);
listener_conn->dns_server_port =
- tor_evdns_add_server_port(conn->s, 0, evdns_server_callback, NULL);
+ tor_evdns_add_server_port(conn->s, 0, evdns_server_callback,
+ listener_conn);
}
/** Free the evdns server port for <b>conn</b>, which must be an
diff --git a/src/or/or.h b/src/or/or.h
index e284a14ce..c5e579372 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1055,6 +1055,19 @@ typedef struct listener_connection_t {
* to the evdns_server_port it uses to listen to and answer connections. */
struct evdns_server_port *dns_server_port;
+ /** @name Isolation parameters
+ *
+ * For an AP listener, these fields describe how to isolate streams that
+ * arrive on the listener.
+ *
+ * @{
+ */
+ /** The session group for this listener. */
+ int session_group;
+ /** One or more ISO_ flags to describe how to isolate streams. */
+ uint8_t isolation_flags;
+ /**@}*/
+
} listener_connection_t;
/** Stores flags and information related to the portion of a v2 Tor OR
@@ -1194,6 +1207,16 @@ typedef struct edge_connection_t {
/** What rendezvous service are we querying for? (AP only) */
rend_data_t *rend_data;
+ /* === Isolation related, AP only. === */
+ /** AP only: based on which factors do we isolate this stream? */
+ uint8_t isolation_flags;
+ /** AP only: what session group is this stream in? */
+ int session_group;
+ /* Other fields to isolate on already exist. The ClientAddr is addr. The
+ ClientProtocol is a combination of type and socks_request->
+ socks_version. SocksAuth will be added to socks_request by ticket
+ #1666. DestAddr and DestPort are in socks_request->address. */
+
/** Number of times we've reassigned this application connection to
* a new circuit. We keep track because the timeout is longer if we've
* already retried several times. */
@@ -2436,6 +2459,32 @@ typedef struct origin_circuit_t {
/* XXXX NM This can get re-used after 2**32 circuits. */
uint32_t global_identifier;
+ /** True if we have attached at least one stream to this circuit, thereby
+ * setting the isolation paramaters for this circuit. */
+ unsigned int isolation_values_set : 1;
+ /** A bitfield of ISO_* flags for every isolation field such that this
+ * circuit has had streams with more than one value for that field
+ * attached to it. */
+ uint8_t isolation_flags_mixed;
+
+ /** @name Isolation parameters
+ *
+ * If any streams have been attached to this circuit (isolation_values_set
+ * == 1), and all streams attached to the circuit have had the same value
+ * for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these
+ * elements hold the value for that field.
+ *
+ * @{
+ */
+ uint8_t client_proto_type;
+ uint8_t client_proto_socksver;
+ uint16_t dest_port;
+ tor_addr_t client_addr;
+ char *dest_address;
+ int session_group;
+ /* XXXX023 do auth once #1666 is merged */
+ /**@}*/
+
} origin_circuit_t;
/** An or_circuit_t holds information needed to implement a circuit at an
@@ -2579,16 +2628,16 @@ typedef enum invalid_router_usage_t {
/** Configuration for a single port that we're listening on. */
typedef struct port_cfg_t {
- tor_addr_t addr; /**< The configured address to listen on. */
+ tor_addr_t addr; /**< The actual IP to listen on, if !is_unix_addr. */
int port; /**< The configured port, or CFG_AUTO_PORT to tell Tor to pick its
* own port. */
uint8_t type; /**< One of CONN_TYPE_*_LISTENER */
unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */
/* Client port types (socks, dns, trans, natd) only: */
- uint8_t isolate; /**< Zero or more isolation flags */
- int sessiongroup; /**< A session group, or -1 if this port is not in a
- * session group. */
+ uint8_t isolation_flags; /**< Zero or more isolation flags */
+ int session_group; /**< A session group, or -1 if this port is not in a
+ * session group. */
/* Unix sockets only: */
/** Path for an AF_UNIX address */