Merge branch 'bug5535_only_rebased'

This commit is contained in:
Nick Mathewson 2012-09-04 18:24:20 -04:00
commit d7a646edcf
8 changed files with 128 additions and 44 deletions

5
changes/bug5535 Normal file
View File

@ -0,0 +1,5 @@
o Major features:
- If configured with ClientUseIPv6, clients may connect to entry
nodes over IPv6. Another new config option, ClientPreferIPv6ORPort,
can be set to make this even more likely to happen.
Implements ticket 5535.

View File

@ -1171,6 +1171,18 @@ The following options are useful only for clients (that is, if
If no defaults are available there, these options default to 20, .70,
0.0, 200, and 4 respectively.
**ClientUseIPv6** **0**|**1**::
If this option is set to 1, Tor might connect to entry nodes over
IPv6. Note that clients configured with an IPv6 address in a
**Bridge** option will try connecting over IPv6 if even if
**ClientUseIPv6** is set to 0. (Default: 0)
**ClientPreferIPv6ORPort** **0**|**1**::
If this option is set to 1, Tor prefers an OR port with an IPv6
address over one with IPv4 if a given entry node has both. Other
things may influence the choice. This option breaks a tie to the
favor of IPv6. (Default: 0)
SERVER OPTIONS
--------------

View File

@ -3792,12 +3792,10 @@ onion_extend_cpath(origin_circuit_t *circ)
} else if (cur_len == 0) { /* picking first node */
const node_t *r = choose_good_entry_server(purpose, state);
if (r) {
/* If we're extending to a bridge, use the preferred address
rather than the primary, for potentially extending to an IPv6
bridge. */
int use_pref_addr = (r->ri != NULL &&
r->ri->purpose == ROUTER_PURPOSE_BRIDGE);
info = extend_info_from_node(r, use_pref_addr);
/* If we're a client, use the preferred address rather than the
primary address, for potentially connecting to an IPv6 OR
port. */
info = extend_info_from_node(r, server_mode(get_options()) == 0);
tor_assert(info);
}
} else {
@ -3865,34 +3863,43 @@ extend_info_alloc(const char *nickname, const char *digest,
/** Allocate and return a new extend_info that can be used to build a
* circuit to or through the node <b>node</b>. Use the primary address
* of the node unless <b>for_direct_connect</b> is true, in which case
* the preferred address is used instead. May return NULL if there is
* not enough info about <b>node</b> to extend to it--for example, if
* there is no routerinfo_t or microdesc_t.
* of the node (i.e. its IPv4 address) unless
* <b>for_direct_connect</b> is true, in which case the preferred
* address is used instead. May return NULL if there is not enough
* info about <b>node</b> to extend to it--for example, if there is no
* routerinfo_t or microdesc_t.
**/
extend_info_t *
extend_info_from_node(const node_t *node, int for_direct_connect)
{
if (node->ri) {
const routerinfo_t *r = node->ri;
tor_addr_port_t ap;
if (for_direct_connect)
node_get_pref_orport(node, &ap);
else
node_get_prim_orport(node, &ap);
return extend_info_alloc(r->nickname, r->cache_info.identity_digest,
r->onion_pkey, &ap.addr, ap.port);
} else if (node->rs && node->md) {
tor_addr_t addr;
tor_addr_from_ipv4h(&addr, node->rs->addr);
tor_addr_port_t ap;
if (node->ri == NULL && (node->rs == NULL || node->md == NULL))
return NULL;
if (for_direct_connect)
node_get_pref_orport(node, &ap);
else
node_get_prim_orport(node, &ap);
log_debug(LD_CIRC, "using %s:%d for %s",
fmt_and_decorate_addr(&ap.addr), ap.port,
node->ri ? node->ri->nickname : node->rs->nickname);
if (node->ri)
return extend_info_alloc(node->ri->nickname,
node->identity,
node->ri->onion_pkey,
&ap.addr,
ap.port);
else if (node->rs && node->md)
return extend_info_alloc(node->rs->nickname,
node->identity,
node->md->onion_pkey,
&addr,
node->rs->or_port);
} else {
&ap.addr,
ap.port);
else
return NULL;
}
}
/** Release storage held by an extend_info_t struct. */
@ -5607,10 +5614,15 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
}
}
/* Indicate that we prefer connecting to this bridge over the
protocol that the bridge address indicates. Last bridge
descriptor handled wins. */
node->ipv6_preferred = tor_addr_family(&bridge->addr) == AF_INET6;
/* Mark bridge as preferably connected to over IPv6 if its IPv6
address is in a Bridge line and ClientPreferIPv6ORPort is
set. Unless both is true, a potential IPv6 OR port of this
bridge won't get selected.
XXX ipv6_preferred is never reset (#6757) */
if (get_options()->ClientPreferIPv6ORPort == 1 &&
tor_addr_family(&bridge->addr) == AF_INET6)
node->ipv6_preferred = 1;
/* XXXipv6 we lack support for falling back to another address for
the same relay, warn the user */

View File

@ -225,8 +225,10 @@ static config_var_t _option_vars[] = {
V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
V(ClientOnly, BOOL, "0"),
V(ClientPreferIPv6ORPort, BOOL, "0"),
V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientTransportPlugin, LINELIST, NULL),
V(ClientUseIPv6, BOOL, "0"),
V(ConsensusParams, STRING, NULL),
V(ConnLimit, UINT, "1000"),
V(ConnDirectionStatistics, BOOL, "0"),

View File

@ -206,6 +206,7 @@ nodelist_set_consensus(networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v2(options) || authdir_mode_v3(options);
int client = !server_mode(options);
init_nodelist();
if (ns->flavor == FLAV_MICRODESC)
@ -242,6 +243,11 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_bad_directory = rs->is_bad_directory;
node->is_bad_exit = rs->is_bad_exit;
node->is_hs_dir = rs->is_hs_dir;
node->ipv6_preferred = 0;
if (client && options->ClientPreferIPv6ORPort == 1 &&
(tor_addr_is_null(&rs->ipv6_addr) == 0 ||
(node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
node->ipv6_preferred = 1;
}
} SMARTLIST_FOREACH_END(rs);
@ -815,31 +821,44 @@ node_get_declared_family(const node_t *node)
int
node_ipv6_preferred(const node_t *node)
{
tor_addr_port_t ipv4_addr;
node_assert_ok(node);
if (node->ri)
return (!tor_addr_is_null(&node->ri->ipv6_addr)
&& (node->ipv6_preferred || node->ri->addr == 0));
if (node->rs)
return (!tor_addr_is_null(&node->rs->ipv6_addr)
&& (node->ipv6_preferred || node->rs->addr == 0));
if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) {
if (node->ri)
return !tor_addr_is_null(&node->ri->ipv6_addr);
if (node->md)
return !tor_addr_is_null(&node->md->ipv6_addr);
if (node->rs)
return !tor_addr_is_null(&node->rs->ipv6_addr);
}
return 0;
}
/** Copy the primary (IPv4) OR port (IP address and TCP port) for
* <b>node</b> into *<b>ap_out</b>. */
void
* <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
* port was copied, else return non-zero.*/
int
node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
{
node_assert_ok(node);
tor_assert(ap_out);
if (node->ri) {
if (node->ri->addr == 0 || node->ri->or_port == 0)
return -1;
tor_addr_from_ipv4h(&ap_out->addr, node->ri->addr);
ap_out->port = node->ri->or_port;
} else if (node->rs) {
return 0;
}
if (node->rs) {
if (node->rs->addr == 0 || node->rs->or_port == 0)
return -1;
tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
ap_out->port = node->rs->or_port;
return 0;
}
return -1;
}
/** Copy the preferred OR port (IP address and TCP port) for
@ -849,7 +868,13 @@ node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out)
{
tor_assert(ap_out);
if (node_ipv6_preferred(node))
/* Cheap implementation of config option ClientUseIPv6 -- simply
don't prefer IPv6 when ClientUseIPv6 is not set. (See #4455 for
more on this subject.) Note that this filter is too strict since
we're hindering not only clients! Erring on the safe side
shouldn't be a problem though. XXX move this check to where
outgoing connections are made? -LN */
if (get_options()->ClientUseIPv6 == 1 && node_ipv6_preferred(node))
node_get_pref_ipv6_orport(node, ap_out);
else
node_get_prim_orport(node, ap_out);
@ -863,9 +888,17 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
node_assert_ok(node);
tor_assert(ap_out);
/* We prefer the microdesc over a potential routerstatus here. They
are not being synchronised atm so there might be a chance that
they differ at some point, f.ex. when flipping
UseMicrodescriptors? -LN */
if (node->ri) {
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
ap_out->port = node->ri->ipv6_orport;
} else if (node->md) {
tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr);
ap_out->port = node->md->ipv6_orport;
} else if (node->rs) {
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
ap_out->port = node->rs->ipv6_orport;

View File

@ -42,18 +42,18 @@ int node_get_purpose(const node_t *node);
int node_is_me(const node_t *node);
int node_exit_policy_rejects_all(const node_t *node);
smartlist_t *node_get_all_orports(const node_t *node);
void node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
uint32_t node_get_prim_addr_ipv4h(const node_t *node);
int node_allows_single_hop_exits(const node_t *node);
const char *node_get_nickname(const node_t *node);
const char *node_get_platform(const node_t *node);
uint32_t node_get_prim_addr_ipv4h(const node_t *node);
void node_get_address_string(const node_t *node, char *cp, size_t len);
long node_get_declared_uptime(const node_t *node);
time_t node_get_published_on(const node_t *node);
const smartlist_t *node_get_declared_family(const node_t *node);
int node_ipv6_preferred(const node_t *node);
int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
smartlist_t *nodelist_get_list(void);

View File

@ -1960,6 +1960,10 @@ typedef struct microdesc_t {
/** As routerinfo_t.onion_pkey */
crypto_pk_t *onion_pkey;
/** As routerinfo_t.ipv6_add */
tor_addr_t ipv6_addr;
/** As routerinfo_t.ipv6_orport */
uint16_t ipv6_orport;
/** As routerinfo_t.family */
smartlist_t *family;
/** Exit policy summary */
@ -3487,6 +3491,13 @@ typedef struct {
* over randomly chosen exits. */
int ClientRejectInternalAddresses;
/** If true, clients may connect over IPv6. XXX we don't really
enforce this -- clients _may_ set up outgoing IPv6 connections
even when this option is not set. */
int ClientUseIPv6;
/** If true, prefer an IPv6 OR port over an IPv4 one. */
int ClientPreferIPv6ORPort;
/** The length of time that we think a consensus should be fresh. */
int V3AuthVotingInterval;
/** The length of time we think it will take to distribute votes. */

View File

@ -524,6 +524,7 @@ static token_rule_t networkstatus_detached_signature_token_table[] = {
/** List of tokens recognized in microdescriptors */
static token_rule_t microdesc_token_table[] = {
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
T0N("a", K_A, GE(1), NO_OBJ ),
T01("family", K_FAMILY, ARGS, NO_OBJ ),
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ),
@ -4454,6 +4455,14 @@ microdescs_parse_from_string(const char *s, const char *eos,
md->onion_pkey = tok->key;
tok->key = NULL;
{
smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
if (a_lines) {
find_single_ipv6_orport(a_lines, &md->ipv6_addr, &md->ipv6_orport);
smartlist_free(a_lines);
}
}
if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) {
int i;
md->family = smartlist_new();