diff options
-rw-r--r-- | src/common/address.h | 7 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 75 | ||||
-rw-r--r-- | src/or/circuitbuild.h | 6 | ||||
-rw-r--r-- | src/or/circuituse.c | 5 | ||||
-rw-r--r-- | src/or/control.c | 2 | ||||
-rw-r--r-- | src/or/nodelist.c | 121 | ||||
-rw-r--r-- | src/or/nodelist.h | 16 | ||||
-rw-r--r-- | src/or/or.h | 2 | ||||
-rw-r--r-- | src/or/rendclient.c | 2 | ||||
-rw-r--r-- | src/or/rendservice.c | 4 | ||||
-rw-r--r-- | src/or/router.c | 56 | ||||
-rw-r--r-- | src/or/router.h | 7 |
12 files changed, 253 insertions, 50 deletions
diff --git a/src/common/address.h b/src/common/address.h index bc225a65ea..4568c32bf9 100644 --- a/src/common/address.h +++ b/src/common/address.h @@ -31,6 +31,13 @@ typedef struct tor_addr_t } addr; } tor_addr_t; +/** Holds an IP address and a TCP/UDP port. */ +typedef struct tor_addr_port_t +{ + tor_addr_t addr; + uint16_t port; +} tor_addr_port_t; + static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a); static INLINE uint32_t tor_addr_to_ipv4n(const tor_addr_t *a); static INLINE uint32_t tor_addr_to_ipv4h(const tor_addr_t *a); diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 1cfeb030d3..fbd55ddfee 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -3012,7 +3012,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit) log_warn(LD_CIRC,"failed to choose an exit server"); return -1; } - exit = extend_info_from_node(node); + exit = extend_info_from_node(node, 0); tor_assert(exit); } state->chosen_exit = exit; @@ -3254,14 +3254,19 @@ 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) { - info = extend_info_from_node(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); tor_assert(info); } } else { const node_t *r = choose_good_middle_server(purpose, state, circ->cpath, cur_len); if (r) { - info = extend_info_from_node(r); + info = extend_info_from_node(r, 0); tor_assert(info); } } @@ -3320,28 +3325,37 @@ extend_info_alloc(const char *nickname, const char *digest, return info; } -/** Allocate and return a new extend_info_t that can be used to build a - * circuit to or through the router <b>r</b>. */ +/** Allocate and return a new extend_info_t that can be used to build + * a circuit to or through the router <b>r</b>. Use the primary + * address of the router unless <b>for_direct_connect</b> is true, in + * which case the preferred address is used instead. */ extend_info_t * -extend_info_from_router(const routerinfo_t *r) +extend_info_from_router(const routerinfo_t *r, int for_direct_connect) { tor_addr_t addr; + uint16_t port; tor_assert(r); - tor_addr_from_ipv4h(&addr, r->addr); + + if (for_direct_connect) + router_get_pref_addr_port(r, &addr, &port); + else + router_get_prim_addr_port(r, &addr, &port); return extend_info_alloc(r->nickname, r->cache_info.identity_digest, - r->onion_pkey, &addr, r->or_port); + r->onion_pkey, &addr, port); } -/** Allocate and return a new extend_info that can be used to build a ircuit - * to or through the node <b>node</b>. 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. +/** Allocate and return a new extend_info that can be used to build a + * ircuit 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. **/ extend_info_t * -extend_info_from_node(const node_t *node) +extend_info_from_node(const node_t *node, int for_direct_connect) { if (node->ri) { - return extend_info_from_router(node->ri); + return extend_info_from_router(node->ri, for_direct_connect); } else if (node->rs && node->md) { tor_addr_t addr; tor_addr_from_ipv4h(&addr, node->rs->addr); @@ -4858,18 +4872,31 @@ routerinfo_is_a_configured_bridge(const routerinfo_t *ri) int node_is_a_configured_bridge(const node_t *node) { - tor_addr_t addr; - uint16_t orport; + int retval = 0; /* Negative. */ + smartlist_t *orports = NULL; + if (!node) - return 0; - if (node_get_addr(node, &addr) < 0) - return 0; - orport = node_get_orport(node); - if (orport == 0) - return 0; + goto out; + + orports = node_get_all_orports(node); + if (orports == NULL) + goto out; - return get_configured_bridge_by_addr_port_digest( - &addr, orport, node->identity) != NULL; + SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, orport) { + if (get_configured_bridge_by_addr_port_digest(&orport->addr, orport->port, + node->identity) != NULL) { + retval = 1; + goto out; + } + } SMARTLIST_FOREACH_END(orport); + +out: + if (orports != NULL) { + SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); + smartlist_free(orports); + orports = NULL; + } + return retval; } /** We made a connection to a router at <b>addr</b>:<b>port</b> diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 1052db6153..8df2748708 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -59,8 +59,10 @@ void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop); extend_info_t *extend_info_alloc(const char *nickname, const char *digest, crypto_pk_env_t *onion_key, const tor_addr_t *addr, uint16_t port); -extend_info_t *extend_info_from_router(const routerinfo_t *r); -extend_info_t *extend_info_from_node(const node_t *node); +extend_info_t *extend_info_from_router(const routerinfo_t *r, + int for_direct_connect); +extend_info_t *extend_info_from_node(const node_t *node, + int for_direct_connect); extend_info_t *extend_info_dup(extend_info_t *info); void extend_info_free(extend_info_t *info); const node_t *build_state_get_exit_node(cpath_build_state_t *state); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 23efe05348..4382d44127 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1439,7 +1439,10 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, int opt = conn->chosen_exit_optional; r = node_get_by_nickname(conn->chosen_exit_name, 1); if (r && node_has_descriptor(r)) { - extend_info = extend_info_from_node(r); + /* We might want to connect to an IPv6 bridge for loading + descriptors so we use the preferred address rather than + the primary. */ + extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0); } else { log_debug(LD_DIR, "considering %d, %s", want_onehop, conn->chosen_exit_name); diff --git a/src/or/control.c b/src/or/control.c index e2d0eece02..65b161996a 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2402,7 +2402,7 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len, /* now circ refers to something that is ready to be extended */ SMARTLIST_FOREACH(nodes, const node_t *, node, { - extend_info_t *info = extend_info_from_node(node); + extend_info_t *info = extend_info_from_node(node, 0); tor_assert(info); /* True, since node_has_descriptor(node) == true */ circuit_append_new_exit(circ, info); extend_info_free(info); diff --git a/src/or/nodelist.c b/src/or/nodelist.c index b93b919c13..08dcde6f02 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -646,24 +646,59 @@ node_exit_policy_rejects_all(const node_t *node) return 1; } -/** Copy the address for <b>node</b> into *<b>addr_out</b>. */ -int -node_get_addr(const node_t *node, tor_addr_t *addr_out) +/** Return list of tor_addr_port_t with all OR ports (in the sense IP + * addr + TCP port) for <b>node</b>. Caller must free all elements + * using tor_free() and free the list using smartlist_free(). + * + * XXX this is potentially a memory fragmentation hog -- if on + * critical path consider the option of having the caller allocate the + * memory + */ +smartlist_t * +node_get_all_orports(const node_t *node) +{ + smartlist_t *sl = smartlist_create(); + + if (node->ri != NULL) { + if (node->ri->addr != 0) { + tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); + tor_addr_from_ipv4h(&ap->addr, node->ri->addr); + ap->port = node->ri->or_port; + smartlist_add(sl, ap); + } + if (!tor_addr_is_null(&node->ri->ipv6_addr)) { + tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); + tor_addr_copy(&ap->addr, &node->ri->ipv6_addr); + ap->port = node->ri->or_port; + smartlist_add(sl, ap); + } + } else if (node->rs != NULL) { + tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); + tor_addr_from_ipv4h(&ap->addr, node->rs->addr); + ap->port = node->rs->or_port; + smartlist_add(sl, ap); + } + + return sl; +} + +/** Copy the primary, IPv4, address for <b>node</b> into + * *<b>addr_out</b>. */ +void +node_get_prim_addr(const node_t *node, tor_addr_t *addr_out) { if (node->ri) { - tor_addr_from_ipv4h(addr_out, node->ri->addr); - return 0; - } else if (node->rs) { + router_get_prim_addr_port(node->ri, addr_out, NULL); + } + else if (node->rs) { tor_addr_from_ipv4h(addr_out, node->rs->addr); - return 0; } - return -1; } /** Return the host-order IPv4 address for <b>node</b>, or 0 if it doesn't * seem to have one. */ uint32_t -node_get_addr_ipv4h(const node_t *node) +node_get_prim_addr_ipv4h(const node_t *node) { if (node->ri) { return node->ri->addr; @@ -673,9 +708,45 @@ node_get_addr_ipv4h(const node_t *node) return 0; } -/** Copy a string representation of the IP address for <b>node</b> into the - * <b>len</b>-byte buffer at <b>buf</b>. - */ +/** Return 1 if we prefer the IPv6 address of <b>node</b>, else 0. */ +static int +node_ipv6_preferred(const node_t *node) +{ + if (node->ri != NULL) + return router_ipv6_preferred(node->ri); + return 0; +} + +/** Copy the preferred address for <b>node</b> into + * <b>addr_out</b>. */ +void +node_get_pref_addr(const node_t *node, tor_addr_t *addr_out) +{ + if (node->ri) { + router_get_pref_addr_port(node->ri, addr_out, NULL); + } else if (node->rs) { + /* No IPv6 in routerstatus_t yet. XXXprop186 ok for private + bridges but needs fixing */ + tor_addr_from_ipv4h(addr_out, node->rs->addr); + } +} + +/** Copy the preferred IPv6 address for <b>node</b> into + * *<b>addr_out</b>. */ +void +node_get_pref_ipv6_addr(const node_t *node, tor_addr_t *addr_out) +{ + if (node->ri) { + tor_addr_copy(addr_out, &node->ri->ipv6_addr); + } else if (node->rs) { + /* No IPv6 in routerstatus_t yet. XXXprop186 ok for private + bridges but needs fixing */ + tor_addr_make_unspec(addr_out); + } +} + +/** Copy a string representation of an IP address for <b>node</b> into + * the <b>len</b>-byte buffer at <b>buf</b>. */ void node_get_address_string(const node_t *node, char *buf, size_t len) { @@ -701,9 +772,9 @@ node_get_declared_uptime(const node_t *node) return -1; } -/** Return <b>node</b>'s declared or_port */ +/** Return <b>node</b>'s declared primary (IPv4) or_port. */ uint16_t -node_get_orport(const node_t *node) +node_get_prim_orport(const node_t *node) { if (node->ri) return node->ri->or_port; @@ -713,6 +784,28 @@ node_get_orport(const node_t *node) return 0; } +/** Return <b>node</b>'s preferred or_port. */ +uint16_t +node_get_pref_orport(const node_t *node) +{ + if (node_ipv6_preferred(node)) + return node_get_pref_ipv6_orport(node); + else + return node_get_prim_orport(node); +} + +/** Return <b>node</b>'s preferred IPv6 or_port. */ +uint16_t +node_get_pref_ipv6_orport(const node_t *node) +{ + if (node->ri) + return node->ri->ipv6_orport; + else if (node->rs) + return 0; /* No IPv6 in routerstatus_t yet. */ + else + return 0; +} + /** Return <b>node</b>'s platform string, or NULL if we don't know it. */ const char * node_get_platform(const node_t *node) diff --git a/src/or/nodelist.h b/src/or/nodelist.h index bd2e63953c..70c76d6d13 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -37,10 +37,15 @@ int node_get_purpose(const node_t *node); (node_get_purpose((node)) == ROUTER_PURPOSE_BRIDGE) int node_is_me(const node_t *node); int node_exit_policy_rejects_all(const node_t *node); -int node_get_addr(const node_t *node, tor_addr_t *addr_out); -uint32_t node_get_addr_ipv4h(const node_t *node); +smartlist_t *node_get_all_orports(const node_t *node); +void node_get_prim_addr(const node_t *node, tor_addr_t *addr_out); +void node_get_pref_addr(const node_t *node, tor_addr_t *addr_out); +void node_get_pref_ipv6_addr(const node_t *node, tor_addr_t *addr_out); +uint32_t node_get_prim_addr_ipv4h(const node_t *node); int node_allows_single_hop_exits(const node_t *node); -uint16_t node_get_orport(const node_t *node); +uint16_t node_get_prim_orport(const node_t *node); +uint16_t node_get_pref_orport(const node_t *node); +uint16_t node_get_pref_ipv6_orport(const node_t *node); const char *node_get_nickname(const node_t *node); const char *node_get_platform(const node_t *node); void node_get_address_string(const node_t *node, char *cp, size_t len); @@ -50,6 +55,11 @@ const smartlist_t *node_get_declared_family(const node_t *node); smartlist_t *nodelist_get_list(void); +/* Temporary aliases during transition to multiple addresses. */ +#define node_get_addr(n,a) node_get_prim_addr((n),(a)) +#define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n)) +#define node_get_orport(n) node_get_prim_orport((n)) + /* XXXX These need to move out of routerlist.c */ void nodelist_refresh_countries(void); void node_set_country(node_t *node); diff --git a/src/or/or.h b/src/or/or.h index 2adaa2239c..c342880fbc 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1760,6 +1760,8 @@ typedef struct { /** True if, after we have added this router, we should re-launch * tests for it. */ unsigned int needs_retest_if_added:1; + /** True if ipv6_addr:ipv6_orport is preferred. */ + unsigned int ipv6_preferred:1; /** Tor can use this router for general positions in circuits; we got it * from a directory server as usual, or we're an authority and a server diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 6a45207e29..cda03c21ef 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -1059,7 +1059,7 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, smartlist_del(usable_nodes, i); goto again; } - new_extend_info = extend_info_from_node(node); + new_extend_info = extend_info_from_node(node, 0); if (!new_extend_info) { log_info(LD_REND, "We don't have a descriptor for the intro-point relay " "'%s'; trying another.", diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 0ded538bef..b4ef8b4708 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -1142,7 +1142,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, goto err; } - extend_info = extend_info_from_node(node); + extend_info = extend_info_from_node(node, 0); } if (len != REND_COOKIE_LEN+DH_KEY_LEN) { @@ -2151,7 +2151,7 @@ rend_services_introduce(void) intro_point_set_changed = 1; smartlist_add(intro_nodes, (void*)node); intro = tor_malloc_zero(sizeof(rend_intro_point_t)); - intro->extend_info = extend_info_from_node(node); + intro->extend_info = extend_info_from_node(node, 0); intro->intro_key = crypto_new_pk_env(); tor_assert(!crypto_pk_generate_key(intro->intro_key)); intro->time_published = -1; diff --git a/src/or/router.c b/src/or/router.c index c92c5bd3ef..d0217371ed 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -893,7 +893,8 @@ consider_testing_reachability(int test_or, int test_dir) log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.", !orport_reachable ? "reachability" : "bandwidth", me->address, me->or_port); - ei = extend_info_from_router(me); + /* XXX IPv6 self testing IPv6 orports will need pref_addr */ + ei = extend_info_from_router(me, 0); circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei, CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); extend_info_free(ei); @@ -1201,7 +1202,6 @@ consider_publishable_server(int force) /** Return the port that we should advertise as our ORPort; this is either * the one configured in the ORPort option, or the one we actually bound to * if ORPort is "auto". - * DOCDOC */ uint16_t router_get_advertised_or_port(const or_options_t *options) @@ -2121,6 +2121,58 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, return (int)written+1; } + +/** Copy the primary, IPv4, address and port for <b>router</b> into + *<b>addr_out</b> and *<b>port_out</b>. */ +void +router_get_prim_addr_port(const routerinfo_t *router, tor_addr_t *addr_out, + uint16_t *port_out) +{ + if (addr_out != NULL) + tor_addr_from_ipv4h(addr_out, router->addr); + if (port_out != NULL) + *port_out = router->or_port; +} + +/** Copy the alternative, presumably IPv6, address and port for + <b>router</b> into *<b>addr_out</b> and *<b>port_out</b>. */ +void +router_get_alt_addr_port(const routerinfo_t *router, + tor_addr_t *addr_out, + uint16_t *port_out) +{ + if (addr_out != NULL) + tor_addr_copy(addr_out, &router->ipv6_addr); + if (port_out != NULL) + *port_out = router->ipv6_orport; +} + +/** Return 1 if we prefer the IPv6 address of <b>router</b>, else 0. + + We prefer the IPv6 address if the router has one and + i) the routerinfo_t says so + or + ii) the router has no IPv4 address. */ +int +router_ipv6_preferred(const routerinfo_t *router) +{ + return (!tor_addr_is_null(&router->ipv6_addr) + && (router->ipv6_preferred || router->addr == 0)); +} + +/** Copy the preferred IP address and port for <b>router</b> into + *<b>addr_out</b> and *<b>port_out</b> . */ +void +router_get_pref_addr_port(const routerinfo_t *router, + tor_addr_t *addr_out, + uint16_t *port_out) +{ + if (router_ipv6_preferred(router)) + router_get_alt_addr_port(router, addr_out, port_out); + else + router_get_prim_addr_port(router, addr_out, port_out); +} + /** Load the contents of <b>filename</b>, find the last line starting with * <b>end_line</b>, ensure that its timestamp is not more than 25 hours in * the past or more than 1 hour in the future with respect to <b>now</b>, diff --git a/src/or/router.h b/src/or/router.h index 6a9851cdbd..4094b665dc 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -85,6 +85,13 @@ int router_pick_published_address(const or_options_t *options, uint32_t *addr); int router_rebuild_descriptor(int force); int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, crypto_pk_env_t *ident_key); +void router_get_prim_addr_port(const routerinfo_t *router, tor_addr_t *addr_out, + uint16_t *port_out); +void router_get_alt_addr_port(const routerinfo_t *router, tor_addr_t *addr_out, + uint16_t *port_out); +void router_get_pref_addr_port(const routerinfo_t *router, tor_addr_t *addr_out, + uint16_t *port_out); +int router_ipv6_preferred(const routerinfo_t *router); int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo, crypto_pk_env_t *ident_key); int is_legal_nickname(const char *s); |