diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/or/circuitlist.c | 2 | ||||
-rw-r--r-- | src/or/config.c | 24 | ||||
-rw-r--r-- | src/or/connection.c | 34 | ||||
-rw-r--r-- | src/or/connection_edge.c | 141 | ||||
-rw-r--r-- | src/or/connection_edge.h | 8 | ||||
-rw-r--r-- | src/or/dnsserv.c | 10 | ||||
-rw-r--r-- | src/or/or.h | 57 |
7 files changed, 253 insertions, 23 deletions
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 93f5fd3493..9f688801f3 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 0774b28916..2ca9c66999 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 db0d78975a..b627dcae16 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 f2ddfc76dc..6d247dcebd 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 1cb1281dbd..59865f414b 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 350b138726..b1316ecc6a 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 e284a14ce3..c5e5793720 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 */ |