diff options
author | teor (Tim Wilson-Brown) <teor2345@gmail.com> | 2015-09-15 17:04:18 +1000 |
---|---|---|
committer | teor (Tim Wilson-Brown) <teor2345@gmail.com> | 2015-09-15 17:04:18 +1000 |
commit | 31eb486c4624d1437d982ffdfc1f9d7d83c5ffd6 (patch) | |
tree | 63993443cc4c4eb32efc6e218e0c35a03d956158 /src/common/address.c | |
parent | a444b11323799536b4cd7902e29f711b0806293a (diff) | |
download | tor-31eb486c4624d1437d982ffdfc1f9d7d83c5ffd6.tar.gz tor-31eb486c4624d1437d982ffdfc1f9d7d83c5ffd6.zip |
Add get_interface_address[6]_list for a list of interface IP addresses
Add get_interface_address[6]_list by refactoring
get_interface_address6. Add unit tests for new and existing functions.
Preparation for ticket 17027. Patch by "teor".
Patch on 42b8fb5a1523 (11 Nov 2007), released in 0.2.0.11-alpha.
Diffstat (limited to 'src/common/address.c')
-rw-r--r-- | src/common/address.c | 107 |
1 files changed, 87 insertions, 20 deletions
diff --git a/src/common/address.c b/src/common/address.c index dd336257ef..0614256521 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -1503,7 +1503,7 @@ get_interface_addresses_raw(int severity) } /** Return true iff <b>a</b> is a multicast address. */ -static int +STATIC int tor_addr_is_multicast(const tor_addr_t *a) { sa_family_t family = tor_addr_family(a); @@ -1593,27 +1593,26 @@ get_interface_address6_via_udp_socket_hack(int severity, return r; } -/** Set *<b>addr</b> to the IP address (if any) of whatever interface - * connects to the Internet. This address should only be used in checking - * whether our address has changed. Return 0 on success, -1 on failure. +/** Set *<b>addr</b> to an arbitrary IP address (if any) of an interface that + * connects to the Internet. Prefer public IP addresses to internal IP + * addresses. This address should only be used in checking whether our + * address has changed, as it may be an internal IP address. Return 0 on + * success, -1 on failure. + * Prefer get_interface_address6_list for a list of all addresses on all + * interfaces which connect to the Internet. */ MOCK_IMPL(int, get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) { - /* XXX really, this function should yield a smartlist of addresses. */ smartlist_t *addrs; tor_assert(addr); - /* Try to do this the smart way if possible. */ - if ((addrs = get_interface_addresses_raw(severity))) { + /* Get a list of public or internal IPs in arbitrary order */ + if ((addrs = get_interface_address6_list(severity, family, 1))) { int rv = -1; + /* Find the first non-internal address, or the last internal address + * Ideally, we want the default route, see #12377 for details */ SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { - if (family != AF_UNSPEC && family != tor_addr_family(a)) - continue; - if (tor_addr_is_loopback(a) || - tor_addr_is_multicast(a)) - continue; - tor_addr_copy(addr, a); rv = 0; @@ -1623,13 +1622,78 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) break; } SMARTLIST_FOREACH_END(a); - SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a)); - smartlist_free(addrs); + free_interface_address6_list(addrs); return rv; } + return -1; +} + +/** Free a smartlist of IP addresses returned by get_interface_address6_list. + */ +void free_interface_address6_list(smartlist_t *addrs) { + SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a)); + smartlist_free(addrs); +} + +/** Return a smartlist of the IP addresses of type family from all interfaces + * on the server. Excludes loopback and multicast addresses. Only includes + * internal addresses if include_internal is true. (Note that a relay behind + * NAT may use an internal address to connect to the Internet.) + * An empty smartlist means that there are no addresses of the selected type + * matching these criteria. + * Returns NULL on failure. + * Use free_interface_address6_list to free the returned list. + */ +MOCK_IMPL(smartlist_t *,get_interface_address6_list,(int severity, + sa_family_t family, + int include_internal)) +{ + smartlist_t *addrs; + tor_addr_t addr; + + /* Try to do this the smart way if possible. */ + if ((addrs = get_interface_addresses_raw(severity))) { + SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { + if (family != AF_UNSPEC && family != tor_addr_family(a)){ + SMARTLIST_DEL_CURRENT(addrs, a); + tor_free(a); + continue; + } + + if (tor_addr_is_loopback(a) || + tor_addr_is_multicast(a)) { + SMARTLIST_DEL_CURRENT(addrs, a); + tor_free(a); + continue; + } + + if (!include_internal && tor_addr_is_internal(a, 0)){ + SMARTLIST_DEL_CURRENT(addrs, a); + tor_free(a); + continue; + } + } SMARTLIST_FOREACH_END(a); + } + + if (addrs && smartlist_len(addrs) > 0) { + return addrs; + } + + /* if we removed all entries as unsuitable */ + if (addrs) { + smartlist_free(addrs); + } + /* Okay, the smart way is out. */ - return get_interface_address6_via_udp_socket_hack(severity,family,addr); + get_interface_address6_via_udp_socket_hack(severity,family,&addr); + if (!include_internal && tor_addr_is_internal(&addr, 0)) { + return smartlist_new(); + } else { + addrs = smartlist_new(); + smartlist_add(addrs, tor_dup_addr(&addr)); + return addrs; + } } /* ====== @@ -1871,10 +1935,13 @@ tor_dup_ip(uint32_t addr) } /** - * Set *<b>addr</b> to the host-order IPv4 address (if any) of whatever - * interface connects to the Internet. This address should only be used in - * checking whether our address has changed. Return 0 on success, -1 on - * failure. + * Set *<b>addr</b> to a host-order IPv4 address (if any) of an + * interface that connects to the Internet. Prefer public IP addresses to + * internal IP addresses. This address should only be used in checking + * whether our address has changed, as it may be an internal IPv4 address. + * Return 0 on success, -1 on failure. + * Prefer get_interface_address_list6 for a list of all IPv4 and IPv6 + * addresses on all interfaces which connect to the Internet. */ MOCK_IMPL(int, get_interface_address,(int severity, uint32_t *addr)) |