Loading configure.in +8 −4 Original line number Diff line number Diff line Loading @@ -300,10 +300,12 @@ AC_CHECK_FUNCS( flock \ ftime \ getaddrinfo \ getifaddrs \ getrlimit \ gettimeofday \ gmtime_r \ inet_aton \ ioctl \ localtime_r \ lround \ memmem \ Loading Loading @@ -624,6 +626,7 @@ dnl These headers are not essential AC_CHECK_HEADERS( arpa/inet.h \ grp.h \ ifaddrs.h \ inttypes.h \ limits.h \ linux/types.h \ Loading @@ -632,6 +635,7 @@ AC_CHECK_HEADERS( malloc/malloc.h \ malloc_np.h \ netdb.h \ net/if.h \ netinet/in.h \ netinet/in6.h \ pwd.h \ Loading src/common/address.c +205 −1 Original line number Diff line number Diff line Loading @@ -13,10 +13,16 @@ #include "util.h" #include "address.h" #include "torlog.h" #include "container.h" #ifdef MS_WINDOWS #include <process.h> #include <windows.h> #include <winsock2.h> /* For access to structs needed by GetAdaptersAddresses */ #undef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #include <iphlpapi.h> #endif #ifdef HAVE_SYS_TIME_H Loading Loading @@ -46,6 +52,15 @@ #ifdef HAVE_SYS_UN_H #include <sys/un.h> #endif #ifdef HAVE_IFADDRS_H #include <ifaddrs.h> #endif #ifdef HAVE_SYS_IOCTL_H #include <sys/ioctl.h> #endif #ifdef HAVE_NET_IF_H #include <net/if.h> #endif #include <stdarg.h> #include <stdio.h> #include <stdlib.h> Loading Loading @@ -1086,6 +1101,169 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) return -1; } #ifdef MS_WINDOWS typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)( ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG); #endif /** 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>. */ static smartlist_t * get_interface_addresses_raw(int severity) { #if defined(HAVE_GETIFADDRS) /* Most free Unixy systems provide getifaddrs, which gives us a linked list * of struct ifaddrs. */ struct ifaddrs *ifa = NULL; const struct ifaddrs *i; smartlist_t *result; if (getifaddrs(&ifa) < 0) { log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s", strerror(errno)); return NULL; } result = smartlist_create(); for (i = ifa; i; i = i->ifa_next) { tor_addr_t tmp; if (!i->ifa_addr) continue; if (i->ifa_addr->sa_family != AF_INET && i->ifa_addr->sa_family != AF_INET6) continue; if (tor_addr_from_sockaddr(&tmp, i->ifa_addr, NULL) < 0) continue; smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); } freeifaddrs(ifa); return result; #elif defined(MS_WINDOWS) /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a "GetAdaptersInfo", but that's deprecated; let's just try GetAdaptersAddresses and fall back to connect+getsockname. */ HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll")); smartlist_t *result = NULL; GetAdaptersAddresses_fn_t fn; ULONG size, res; IP_ADAPTER_ADDRESSES *addresses = NULL, *address; (void) severity; #define FLAGS (GAA_FLAG_SKIP_ANYCAST | \ GAA_FLAG_SKIP_MULTICAST | \ GAA_FLAG_SKIP_DNS_SERVER) if (!lib) { log_fn(severity, LD_NET, "Unable to load iphlpapi.dll"); goto done; } if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(lib, "GetAdaptersAddresses"))) { log_fn(severity, LD_NET, "Unable to obtain pointer to " "GetAdaptersAddresses"); goto done; } /* Guess how much space we need. */ size = 15*1024; addresses = tor_malloc(size); res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); if (res == ERROR_BUFFER_OVERFLOW) { /* we didn't guess that we needed enough space; try again */ tor_free(addresses); addresses = tor_malloc(size); res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); } if (res != NO_ERROR) { log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res); goto done; } result = smartlist_create(); for (address = addresses; address; address = address->Next) { IP_ADAPTER_UNICAST_ADDRESS *a; for (a = address->FirstUnicastAddress; a; a = a->Next) { /* Yes, it's a linked list inside a linked list */ struct sockaddr *sa = a->Address.lpSockaddr; tor_addr_t tmp; if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) continue; if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) continue; smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); } } done: if (lib) FreeLibrary(lib); tor_free(addresses); return result; #elif defined(SIOCGIFCONF) && defined(HAVE_IOCTL) /* Some older unixy systems make us use ioctl(SIOCGIFCONF) */ struct ifconf ifc; int fd, i, sz, n; smartlist_t *result = NULL; /* This interface, AFAICT, only supports AF_INET addresses */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { log(severity, LD_NET, "socket failed: %s", strerror(errno)); goto done; } /* Guess how much space we need. */ ifc.ifc_len = sz = 15*1024; ifc.ifc_ifcu.ifcu_req = tor_malloc(sz); if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { log(severity, LD_NET, "ioctl failed: %s", strerror(errno)); close(fd); goto done; } close(fd); result = smartlist_create(); if (ifc.ifc_len < sz) sz = ifc.ifc_len; n = sz / sizeof(struct ifreq); for (i = 0; i < n ; ++i) { struct ifreq *r = &ifc.ifc_ifcu.ifcu_req[i]; struct sockaddr *sa = &r->ifr_addr; tor_addr_t tmp; if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) continue; /* should be impossible */ if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) continue; smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); } done: tor_free(ifc.ifc_ifcu.ifcu_req); return result; #else (void) severity; return NULL; #endif } /** Return true iff <b>a</b> is a multicast address. */ static int tor_addr_is_multicast(const tor_addr_t *a) { sa_family_t family = tor_addr_family(a); if (family == AF_INET) { uint32_t ipv4h = tor_addr_to_ipv4h(a); if ((ipv4h >> 24) == 0xe0) return 1; /* Multicast */ } else if (family == AF_INET6) { const uint8_t *a32 = tor_addr_to_in6_addr8(a); if (a32[0] == 0xff) return 1; } return 0; } /** 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. Loading @@ -1093,12 +1271,38 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) 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; int sock=-1, r=-1; struct sockaddr_storage my_addr, target_addr; socklen_t addr_len; tor_assert(addr); /* Try to do this the smart way if possible. */ if ((addrs = get_interface_addresses_raw(severity))) { int rv = -1; 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; /* If we found a non-internal address, declare success. Otherwise, * keep looking. */ if (!tor_addr_is_internal(a, 0)) break; } SMARTLIST_FOREACH_END(a); SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a)); smartlist_free(addrs); return rv; } /* Okay, the smart way is out. */ memset(addr, 0, sizeof(tor_addr_t)); memset(&target_addr, 0, sizeof(target_addr)); /* Don't worry: no packets are sent. We just need to use a real address Loading src/test/test_addr.c +5 −6 Original line number Diff line number Diff line Loading @@ -613,12 +613,11 @@ test_addr_ip6_helpers(void) /* get interface addresses */ r = get_interface_address6(LOG_DEBUG, AF_INET, &t1); i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2); #if 0 tor_inet_ntop(AF_INET, &t1.sa.sin_addr, buf, sizeof(buf)); printf("\nv4 address: %s (family=%d)", buf, IN_FAMILY(&t1)); tor_inet_ntop(AF_INET6, &t2.sa6.sin6_addr, buf, sizeof(buf)); printf("\nv6 address: %s (family=%d)", buf, IN_FAMILY(&t2)); #endif TT_BLATHER(("v4 address: %s (family=%d)", fmt_addr(&t1), tor_addr_family(&t1))); TT_BLATHER(("v6 address: %s (family=%d)", fmt_addr(&t2), tor_addr_family(&t2))); done: ; Loading Loading
configure.in +8 −4 Original line number Diff line number Diff line Loading @@ -300,10 +300,12 @@ AC_CHECK_FUNCS( flock \ ftime \ getaddrinfo \ getifaddrs \ getrlimit \ gettimeofday \ gmtime_r \ inet_aton \ ioctl \ localtime_r \ lround \ memmem \ Loading Loading @@ -624,6 +626,7 @@ dnl These headers are not essential AC_CHECK_HEADERS( arpa/inet.h \ grp.h \ ifaddrs.h \ inttypes.h \ limits.h \ linux/types.h \ Loading @@ -632,6 +635,7 @@ AC_CHECK_HEADERS( malloc/malloc.h \ malloc_np.h \ netdb.h \ net/if.h \ netinet/in.h \ netinet/in6.h \ pwd.h \ Loading
src/common/address.c +205 −1 Original line number Diff line number Diff line Loading @@ -13,10 +13,16 @@ #include "util.h" #include "address.h" #include "torlog.h" #include "container.h" #ifdef MS_WINDOWS #include <process.h> #include <windows.h> #include <winsock2.h> /* For access to structs needed by GetAdaptersAddresses */ #undef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #include <iphlpapi.h> #endif #ifdef HAVE_SYS_TIME_H Loading Loading @@ -46,6 +52,15 @@ #ifdef HAVE_SYS_UN_H #include <sys/un.h> #endif #ifdef HAVE_IFADDRS_H #include <ifaddrs.h> #endif #ifdef HAVE_SYS_IOCTL_H #include <sys/ioctl.h> #endif #ifdef HAVE_NET_IF_H #include <net/if.h> #endif #include <stdarg.h> #include <stdio.h> #include <stdlib.h> Loading Loading @@ -1086,6 +1101,169 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) return -1; } #ifdef MS_WINDOWS typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)( ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG); #endif /** 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>. */ static smartlist_t * get_interface_addresses_raw(int severity) { #if defined(HAVE_GETIFADDRS) /* Most free Unixy systems provide getifaddrs, which gives us a linked list * of struct ifaddrs. */ struct ifaddrs *ifa = NULL; const struct ifaddrs *i; smartlist_t *result; if (getifaddrs(&ifa) < 0) { log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s", strerror(errno)); return NULL; } result = smartlist_create(); for (i = ifa; i; i = i->ifa_next) { tor_addr_t tmp; if (!i->ifa_addr) continue; if (i->ifa_addr->sa_family != AF_INET && i->ifa_addr->sa_family != AF_INET6) continue; if (tor_addr_from_sockaddr(&tmp, i->ifa_addr, NULL) < 0) continue; smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); } freeifaddrs(ifa); return result; #elif defined(MS_WINDOWS) /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a "GetAdaptersInfo", but that's deprecated; let's just try GetAdaptersAddresses and fall back to connect+getsockname. */ HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll")); smartlist_t *result = NULL; GetAdaptersAddresses_fn_t fn; ULONG size, res; IP_ADAPTER_ADDRESSES *addresses = NULL, *address; (void) severity; #define FLAGS (GAA_FLAG_SKIP_ANYCAST | \ GAA_FLAG_SKIP_MULTICAST | \ GAA_FLAG_SKIP_DNS_SERVER) if (!lib) { log_fn(severity, LD_NET, "Unable to load iphlpapi.dll"); goto done; } if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(lib, "GetAdaptersAddresses"))) { log_fn(severity, LD_NET, "Unable to obtain pointer to " "GetAdaptersAddresses"); goto done; } /* Guess how much space we need. */ size = 15*1024; addresses = tor_malloc(size); res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); if (res == ERROR_BUFFER_OVERFLOW) { /* we didn't guess that we needed enough space; try again */ tor_free(addresses); addresses = tor_malloc(size); res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); } if (res != NO_ERROR) { log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res); goto done; } result = smartlist_create(); for (address = addresses; address; address = address->Next) { IP_ADAPTER_UNICAST_ADDRESS *a; for (a = address->FirstUnicastAddress; a; a = a->Next) { /* Yes, it's a linked list inside a linked list */ struct sockaddr *sa = a->Address.lpSockaddr; tor_addr_t tmp; if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) continue; if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) continue; smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); } } done: if (lib) FreeLibrary(lib); tor_free(addresses); return result; #elif defined(SIOCGIFCONF) && defined(HAVE_IOCTL) /* Some older unixy systems make us use ioctl(SIOCGIFCONF) */ struct ifconf ifc; int fd, i, sz, n; smartlist_t *result = NULL; /* This interface, AFAICT, only supports AF_INET addresses */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { log(severity, LD_NET, "socket failed: %s", strerror(errno)); goto done; } /* Guess how much space we need. */ ifc.ifc_len = sz = 15*1024; ifc.ifc_ifcu.ifcu_req = tor_malloc(sz); if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { log(severity, LD_NET, "ioctl failed: %s", strerror(errno)); close(fd); goto done; } close(fd); result = smartlist_create(); if (ifc.ifc_len < sz) sz = ifc.ifc_len; n = sz / sizeof(struct ifreq); for (i = 0; i < n ; ++i) { struct ifreq *r = &ifc.ifc_ifcu.ifcu_req[i]; struct sockaddr *sa = &r->ifr_addr; tor_addr_t tmp; if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) continue; /* should be impossible */ if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) continue; smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); } done: tor_free(ifc.ifc_ifcu.ifcu_req); return result; #else (void) severity; return NULL; #endif } /** Return true iff <b>a</b> is a multicast address. */ static int tor_addr_is_multicast(const tor_addr_t *a) { sa_family_t family = tor_addr_family(a); if (family == AF_INET) { uint32_t ipv4h = tor_addr_to_ipv4h(a); if ((ipv4h >> 24) == 0xe0) return 1; /* Multicast */ } else if (family == AF_INET6) { const uint8_t *a32 = tor_addr_to_in6_addr8(a); if (a32[0] == 0xff) return 1; } return 0; } /** 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. Loading @@ -1093,12 +1271,38 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) 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; int sock=-1, r=-1; struct sockaddr_storage my_addr, target_addr; socklen_t addr_len; tor_assert(addr); /* Try to do this the smart way if possible. */ if ((addrs = get_interface_addresses_raw(severity))) { int rv = -1; 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; /* If we found a non-internal address, declare success. Otherwise, * keep looking. */ if (!tor_addr_is_internal(a, 0)) break; } SMARTLIST_FOREACH_END(a); SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a)); smartlist_free(addrs); return rv; } /* Okay, the smart way is out. */ memset(addr, 0, sizeof(tor_addr_t)); memset(&target_addr, 0, sizeof(target_addr)); /* Don't worry: no packets are sent. We just need to use a real address Loading
src/test/test_addr.c +5 −6 Original line number Diff line number Diff line Loading @@ -613,12 +613,11 @@ test_addr_ip6_helpers(void) /* get interface addresses */ r = get_interface_address6(LOG_DEBUG, AF_INET, &t1); i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2); #if 0 tor_inet_ntop(AF_INET, &t1.sa.sin_addr, buf, sizeof(buf)); printf("\nv4 address: %s (family=%d)", buf, IN_FAMILY(&t1)); tor_inet_ntop(AF_INET6, &t2.sa6.sin6_addr, buf, sizeof(buf)); printf("\nv6 address: %s (family=%d)", buf, IN_FAMILY(&t2)); #endif TT_BLATHER(("v4 address: %s (family=%d)", fmt_addr(&t1), tor_addr_family(&t1))); TT_BLATHER(("v6 address: %s (family=%d)", fmt_addr(&t2), tor_addr_family(&t2))); done: ; Loading