Add family argument to get_interface_addresses_raw (and subfunctions).

This commit is contained in:
rl1987 2016-01-03 15:35:45 +01:00
parent cdbb04be10
commit 44497e9ebc
4 changed files with 44 additions and 31 deletions

5
changes/feature17950 Normal file
View File

@ -0,0 +1,5 @@
o Minor features:
- Add a family argument to get_interface_addresses_raw() and
subfunctions to make network interface address interogation more
efficient. Now Tor can specifically ask for IPv4, IPv6 or both
types of interfaces from the operating system. Resolves ticket 17950.

View File

@ -1274,7 +1274,7 @@ typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
* into smartlist of <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
ifaddrs_to_smartlist(const struct ifaddrs *ifa)
ifaddrs_to_smartlist(const struct ifaddrs *ifa, sa_family_t family)
{
smartlist_t *result = smartlist_new();
const struct ifaddrs *i;
@ -1285,8 +1285,7 @@ ifaddrs_to_smartlist(const struct ifaddrs *ifa)
continue;
if (!i->ifa_addr)
continue;
if (i->ifa_addr->sa_family != AF_INET &&
i->ifa_addr->sa_family != AF_INET6)
if (family != AF_UNSPEC && i->ifa_addr->sa_family != family)
continue;
if (tor_addr_from_sockaddr(&tmp, i->ifa_addr, NULL) < 0)
continue;
@ -1301,7 +1300,7 @@ ifaddrs_to_smartlist(const struct ifaddrs *ifa)
* <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
get_interface_addresses_ifaddrs(int severity)
get_interface_addresses_ifaddrs(int severity, sa_family_t family)
{
/* Most free Unixy systems provide getifaddrs, which gives us a linked list
@ -1314,7 +1313,7 @@ get_interface_addresses_ifaddrs(int severity)
return NULL;
}
result = ifaddrs_to_smartlist(ifa);
result = ifaddrs_to_smartlist(ifa, family);
freeifaddrs(ifa);
@ -1356,7 +1355,7 @@ ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses)
* <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
get_interface_addresses_win32(int severity)
get_interface_addresses_win32(int severity, sa_family_t family)
{
/* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
@ -1390,7 +1389,7 @@ get_interface_addresses_win32(int severity)
/* Guess how much space we need. */
size = 15*1024;
addresses = tor_malloc(size);
res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
res = fn(family, FLAGS, NULL, addresses, &size);
if (res == ERROR_BUFFER_OVERFLOW) {
/* we didn't guess that we needed enough space; try again */
tor_free(addresses);
@ -1464,7 +1463,7 @@ ifreq_to_smartlist(char *buf, size_t buflen)
* <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
get_interface_addresses_ioctl(int severity)
get_interface_addresses_ioctl(int severity, sa_family_t family)
{
/* Some older unixy systems make us use ioctl(SIOCGIFCONF) */
struct ifconf ifc;
@ -1473,7 +1472,14 @@ get_interface_addresses_ioctl(int severity)
/* This interface, AFAICT, only supports AF_INET addresses,
* except on AIX. For Solaris, we could use SIOCGLIFCONF. */
fd = socket(AF_INET, SOCK_DGRAM, 0);
/* FIXME: for now, we bail out if family is not AF_INET since
* ioctl() technique supports non-IPv4 interface addresses on
* a small number of niche systems only. */
if (family != AF_INET)
return NULL;
fd = socket(family, SOCK_DGRAM, 0);
if (fd < 0) {
tor_log(severity, LD_NET, "socket failed: %s", strerror(errno));
goto done;
@ -1508,21 +1514,23 @@ get_interface_addresses_ioctl(int severity)
/** Try to ask our network interfaces what addresses they are bound to.
* Return a new smartlist of tor_addr_t on success, and NULL on failure.
* (An empty smartlist indicates that we successfully learned that we have no
* addresses.) Log failure messages at <b>severity</b>. */
* addresses.) Log failure messages at <b>severity</b>. Only return the
* interface addresses of requested <b>family</b> and ignore the addresses
* of other address families. */
MOCK_IMPL(smartlist_t *,
get_interface_addresses_raw,(int severity))
get_interface_addresses_raw,(int severity, sa_family_t family))
{
smartlist_t *result = NULL;
#if defined(HAVE_IFADDRS_TO_SMARTLIST)
if ((result = get_interface_addresses_ifaddrs(severity)))
if ((result = get_interface_addresses_ifaddrs(severity, family)))
return result;
#endif
#if defined(HAVE_IP_ADAPTER_TO_SMARTLIST)
if ((result = get_interface_addresses_win32(severity)))
if ((result = get_interface_addresses_win32(severity, family)))
return result;
#endif
#if defined(HAVE_IFCONF_TO_SMARTLIST)
if ((result = get_interface_addresses_ioctl(severity)))
if ((result = get_interface_addresses_ioctl(severity, family)))
return result;
#endif
(void) severity;
@ -1686,15 +1694,9 @@ MOCK_IMPL(smartlist_t *,get_interface_address6_list,(int severity,
tor_addr_t addr;
/* Try to do this the smart way if possible. */
if ((addrs = get_interface_addresses_raw(severity))) {
if ((addrs = get_interface_addresses_raw(severity, family))) {
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);

View File

@ -311,26 +311,31 @@ get_interface_address_list(int severity, int include_internal)
tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
#ifdef ADDRESS_PRIVATE
MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity));
MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity,
sa_family_t family));
MOCK_DECL(int,get_interface_address6_via_udp_socket_hack,(int severity,
sa_family_t family,
tor_addr_t *addr));
#ifdef HAVE_IFADDRS_TO_SMARTLIST
STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa);
STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity);
STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa,
sa_family_t family);
STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity,
sa_family_t family);
#endif
#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
STATIC smartlist_t *ip_adapter_addresses_to_smartlist(
const IP_ADAPTER_ADDRESSES *addresses);
STATIC smartlist_t *get_interface_addresses_win32(int severity);
STATIC smartlist_t *get_interface_addresses_win32(int severity,
sa_family_t family);
#endif
#ifdef HAVE_IFCONF_TO_SMARTLIST
STATIC smartlist_t *ifreq_to_smartlist(char *ifr,
size_t buflen);
STATIC smartlist_t *get_interface_addresses_ioctl(int severity);
STATIC smartlist_t *get_interface_addresses_ioctl(int severity,
sa_family_t family);
#endif
#endif // ADDRESS_PRIVATE

View File

@ -220,7 +220,7 @@ test_address_ifaddrs_to_smartlist(void *arg)
ifa_ipv6->ifa_dstaddr = NULL;
ifa_ipv6->ifa_data = NULL;
smartlist = ifaddrs_to_smartlist(ifa);
smartlist = ifaddrs_to_smartlist(ifa, AF_UNSPEC);
tt_assert(smartlist);
tt_assert(smartlist_len(smartlist) == 3);
@ -281,7 +281,7 @@ test_address_get_if_addrs_ifaddrs(void *arg)
(void)arg;
results = get_interface_addresses_ifaddrs(LOG_ERR);
results = get_interface_addresses_ifaddrs(LOG_ERR, AF_UNSPEC);
tt_assert(results);
/* Some FreeBSD jails don't have localhost IP address. Instead, they only
@ -314,7 +314,7 @@ test_address_get_if_addrs_win32(void *arg)
(void)arg;
results = get_interface_addresses_win32(LOG_ERR);
results = get_interface_addresses_win32(LOG_ERR, AF_UNSPEC);
tt_int_op(smartlist_len(results),>=,1);
tt_assert(smartlist_contains_localhost_tor_addr(results));
@ -511,7 +511,7 @@ test_address_get_if_addrs_ioctl(void *arg)
(void)arg;
result = get_interface_addresses_ioctl(LOG_ERR);
result = get_interface_addresses_ioctl(LOG_ERR, AF_INET);
/* On an IPv6-only system, this will fail and return NULL
tt_assert(result);
@ -845,9 +845,10 @@ test_address_get_if_addrs6_list_no_internal(void *arg)
static int called_get_interface_addresses_raw = 0;
static smartlist_t *
mock_get_interface_addresses_raw_fail(int severity)
mock_get_interface_addresses_raw_fail(int severity, sa_family_t family)
{
(void)severity;
(void)family;
called_get_interface_addresses_raw++;
return smartlist_new();