-
-
Save nikias/98e1723c7dcab771ee6627267133b28f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/common/Makefile.am b/common/Makefile.am | |
index ca8180c..8d0e889 100644 | |
--- a/common/Makefile.am | |
+++ b/common/Makefile.am | |
@@ -12,5 +12,5 @@ libinternalcommon_la_SOURCES = \ | |
collection.h | |
if WIN32 | |
-libinternalcommon_la_LIBADD += -lws2_32 | |
+libinternalcommon_la_LIBADD += -lws2_32 -lIphlpapi | |
endif | |
diff --git a/common/socket.c b/common/socket.c | |
index 47c0903..bcccbae 100644 | |
--- a/common/socket.c | |
+++ b/common/socket.c | |
@@ -34,7 +34,16 @@ | |
#include <winsock2.h> | |
#include <ws2tcpip.h> | |
#include <windows.h> | |
+#ifndef HAVE_GETIFADDRS | |
+#include <iphlpapi.h> | |
+#endif | |
static int wsa_init = 0; | |
+#ifndef IFF_RUNNING | |
+#define IFF_RUNNING IFF_UP | |
+#endif | |
+#ifndef AI_NUMERICSERV | |
+#define AI_NUMERICSERV 0 | |
+#endif | |
#else | |
#include <sys/socket.h> | |
#include <sys/un.h> | |
@@ -377,10 +386,308 @@ static uint32_t _in6_addr_scope(struct in6_addr* addr) | |
return scope; | |
} | |
+#ifndef HAVE_GETIFADDRS | |
+#ifdef WIN32 | |
+ | |
+struct ifaddrs { | |
+ struct ifaddrs *ifa_next; /* Next item in list */ | |
+ char *ifa_name; /* Name of interface */ | |
+ unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */ | |
+ struct sockaddr *ifa_addr; /* Address of interface */ | |
+ struct sockaddr *ifa_netmask; /* Netmask of interface */ | |
+ union { | |
+ struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */ | |
+ struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */ | |
+ } ifa_ifu; | |
+#define ifa_broadaddr ifa_ifu.ifu_broadaddr | |
+#define ifa_dstaddr ifa_ifu.ifu_dstaddr | |
+ void *ifa_data; /* Address-specific data */ | |
+}; | |
+ | |
+#define WORKING_BUFFER_SIZE 15000 | |
+#define MAX_TRIES 3 | |
+ | |
+static void freeifaddrs(struct ifaddrs *ifa) | |
+{ | |
+ if (!ifa) { | |
+ return; | |
+ } | |
+ free(ifa->ifa_name); | |
+ free(ifa->ifa_addr); | |
+ free(ifa->ifa_netmask); | |
+ free(ifa->ifa_dstaddr); | |
+ freeifaddrs(ifa->ifa_next); | |
+ free(ifa); | |
+} | |
+ | |
+/* | |
+ * getifaddrs() reference implementation for win32. | |
+ * Heavily based on openpgm's implementation found here: | |
+ * https://github.com/steve-o/openpgm/blob/master/openpgm/pgm/getifaddrs.c | |
+ */ | |
+static int getifaddrs(struct ifaddrs** ifap) | |
+{ | |
+ struct ifaddrs* ifa = NULL; | |
+ | |
+ DWORD dwRetVal = 0; | |
+ | |
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL; | |
+ ULONG outBufLen = 0; | |
+ ULONG Iterations = 0; | |
+ | |
+ ULONG flags = GAA_FLAG_INCLUDE_PREFIX | | |
+ GAA_FLAG_SKIP_ANYCAST | | |
+ GAA_FLAG_SKIP_DNS_SERVER | | |
+ GAA_FLAG_SKIP_FRIENDLY_NAME | | |
+ GAA_FLAG_SKIP_MULTICAST; | |
+ | |
+ PIP_ADAPTER_ADDRESSES adapter = NULL; | |
+ | |
+ if (!ifap) { | |
+ errno = EINVAL; | |
+ return -1; | |
+ } | |
+ *ifap = NULL; | |
+ | |
+ outBufLen = WORKING_BUFFER_SIZE; | |
+ do { | |
+ pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); | |
+ if (pAddresses == NULL) { | |
+ printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n"); | |
+ return -1; | |
+ } | |
+ dwRetVal = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAddresses, &outBufLen); | |
+ if (dwRetVal == ERROR_BUFFER_OVERFLOW) { | |
+ free(pAddresses); | |
+ pAddresses = NULL; | |
+ } else { | |
+ break; | |
+ } | |
+ Iterations++; | |
+ } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES)); | |
+ | |
+ if (dwRetVal != NO_ERROR) { | |
+ free(pAddresses); | |
+ return -1; | |
+ } | |
+ | |
+ for (adapter = pAddresses; adapter; adapter = adapter->Next) { | |
+ int unicastIndex = 0; | |
+ for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; unicast; unicast = unicast->Next, ++unicastIndex) { | |
+ /* ensure IP adapter */ | |
+ if (AF_INET != unicast->Address.lpSockaddr->sa_family && AF_INET6 != unicast->Address.lpSockaddr->sa_family) { | |
+ continue; | |
+ } | |
+ | |
+ if (!ifa) { | |
+ ifa = malloc(sizeof(struct ifaddrs)); | |
+ if (!ifa) { | |
+ errno = ENOMEM; | |
+ free(pAddresses); | |
+ return -1; | |
+ } | |
+ *ifap = ifa; | |
+ ifa->ifa_next = NULL; | |
+ } else { | |
+ struct ifaddrs* ifanew = malloc(sizeof(struct ifaddrs)); | |
+ if (!ifanew) { | |
+ freeifaddrs(*ifap); | |
+ free(pAddresses); | |
+ errno = ENOMEM; | |
+ return -1; | |
+ } | |
+ ifa->ifa_next = ifanew; | |
+ ifa = ifanew; | |
+ ifa->ifa_next = NULL; | |
+ } | |
+ | |
+ /* name */ | |
+ ifa->ifa_name = strdup(adapter->AdapterName); | |
+ | |
+ /* flags */ | |
+ ifa->ifa_flags = 0; | |
+ if (IfOperStatusUp == adapter->OperStatus) | |
+ ifa->ifa_flags |= IFF_UP; | |
+ if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType) | |
+ ifa->ifa_flags |= IFF_LOOPBACK; | |
+ if (!(adapter->Flags & IP_ADAPTER_NO_MULTICAST)) | |
+ ifa->ifa_flags |= IFF_MULTICAST; | |
+ | |
+ /* address */ | |
+ ifa->ifa_addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); | |
+ memcpy(ifa->ifa_addr, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength); | |
+ | |
+ /* netmask */ | |
+ ifa->ifa_netmask = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); | |
+ memset(ifa->ifa_netmask, 0, sizeof(struct sockaddr_storage)); | |
+ | |
+/* pre-Vista must hunt for matching prefix in linked list, otherwise use | |
+ * OnLinkPrefixLength from IP_ADAPTER_UNICAST_ADDRESS structure. | |
+ * FirstPrefix requires Windows XP SP1, from SP1 to pre-Vista provides a | |
+ * single adapter prefix for each IP address. Vista and later provides | |
+ * host IP address prefix, subnet IP address, and subnet broadcast IP | |
+ * address. In addition there is a multicast and broadcast address prefix. | |
+ */ | |
+ ULONG prefixLength = 0; | |
+ | |
+#if defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) | |
+/* For a unicast IPv4 address, any value greater than 32 is an illegal | |
+ * value. For a unicast IPv6 address, any value greater than 128 is an | |
+ * illegal value. A value of 255 is commonly used to represent an illegal | |
+ * value. | |
+ * | |
+ * Windows 7 SP1 returns 64 for Teredo links which is incorrect. | |
+ */ | |
+ | |
+#define IN6_IS_ADDR_TEREDO(addr) \ | |
+ (((const uint32_t *)(addr))[0] == ntohl (0x20010000)) | |
+ | |
+ if (AF_INET6 == unicast->Address.lpSockaddr->sa_family && | |
+/* TunnelType only applies to one interface on the adapter and no | |
+ * convenient method is provided to determine which. | |
+ */ | |
+ TUNNEL_TYPE_TEREDO == adapter->TunnelType && | |
+/* Test the interface with the known Teredo network prefix. | |
+ */ | |
+ IN6_IS_ADDR_TEREDO( &((struct sockaddr_in6*)(unicast->Address.lpSockaddr))->sin6_addr) && | |
+/* Test that this version is actually wrong, subsequent releases from Microsoft | |
+ * may resolve the issue. | |
+ */ | |
+ 32 != unicast->OnLinkPrefixLength) | |
+ { | |
+ prefixLength = 32; | |
+ } | |
+ else | |
+ prefixLength = unicast->OnLinkPrefixLength; | |
+#else | |
+/* The order of linked IP_ADAPTER_UNICAST_ADDRESS structures pointed to by | |
+ * the FirstUnicastAddress member does not have any relationship with the | |
+ * order of linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix | |
+ * member. | |
+ * | |
+ * Example enumeration: | |
+ * [ no subnet ] | |
+ * ::1/128 - address | |
+ * ff00::%1/8 - multicast (no IPv6 broadcast) | |
+ * 127.0.0.0/8 - subnet | |
+ * 127.0.0.1/32 - address | |
+ * 127.255.255.255/32 - subnet broadcast | |
+ * 224.0.0.0/4 - multicast | |
+ * 255.255.255.255/32 - broadcast | |
+ * | |
+ * Which differs from most adapters listing three IPv6: | |
+ * fe80::%10/64 - subnet | |
+ * fe80::51e9:5fe5:4202:325a%10/128 - address | |
+ * ff00::%10/8 - multicast | |
+ * | |
+ * !IfOperStatusUp IPv4 addresses are skipped: | |
+ * fe80::%13/64 - subnet | |
+ * fe80::d530:946d:e8df:8c91%13/128 - address | |
+ * ff00::%13/8 - multicast | |
+ * [ no subnet ] | |
+ * [ no address ] | |
+ * 224.0.0.0/4 - multicast | |
+ * 255.255.255.255/32 - broadcast | |
+ * | |
+ * On PTP links no multicast or broadcast addresses are returned: | |
+ * [ no subnet ] | |
+ * fe80::5efe:10.203.9.30/128 - address | |
+ * [ no multicast ] | |
+ * [ no multicast ] | |
+ * [ no broadcast ] | |
+ * | |
+ * Active primary IPv6 interfaces are a bit overloaded: | |
+ * ::/0 - default route | |
+ * 2001::/32 - global subnet | |
+ * 2001:0:4137:9e76:2443:d6:ba87:1a2a/128 - global address | |
+ * fe80::/64 - link-local subnet | |
+ * fe80::2443:d6:ba87:1a2a/128 - link-local address | |
+ * ff00::/8 - multicast | |
+ */ | |
+ | |
+#define IN_LINKLOCAL(a) ((((uint32_t) (a)) & 0xaffff0000) == 0xa9fe0000) | |
+ | |
+ for (IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) { | |
+ LPSOCKADDR lpSockaddr = prefix->Address.lpSockaddr; | |
+ if (lpSockaddr->sa_family != unicast->Address.lpSockaddr->sa_family) | |
+ continue; | |
+/* special cases */ | |
+/* RFC2863: IPv4 interface not up */ | |
+ if (AF_INET == lpSockaddr->sa_family && adapter->OperStatus != IfOperStatusUp) { | |
+/* RFC3927: link-local IPv4 always has 16-bit CIDR */ | |
+ if (IN_LINKLOCAL( ntohl (((struct sockaddr_in*)(unicast->Address.lpSockaddr))->sin_addr.s_addr))) { | |
+ prefixLength = 16; | |
+ } | |
+ break; | |
+ } | |
+/* default IPv6 route */ | |
+ if (AF_INET6 == lpSockaddr->sa_family && 0 == prefix->PrefixLength && IN6_IS_ADDR_UNSPECIFIED( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) { | |
+ continue; | |
+ } | |
+/* Assume unicast address for first prefix of operational adapter */ | |
+ if (AF_INET == lpSockaddr->sa_family) | |
+ if (IN_MULTICAST( ntohl (((struct sockaddr_in*)(lpSockaddr))->sin_addr.s_addr))) { | |
+ fprintf(stderr, "FATAL: first prefix is non a unicast address\n"); | |
+ break; | |
+ } | |
+ if (AF_INET6 == lpSockaddr->sa_family) | |
+ if (IN6_IS_ADDR_MULTICAST( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) { | |
+ fprintf(stderr, "FATAL: first prefix is not a unicast address\n"); | |
+ break; | |
+ } | |
+/* Assume subnet or host IP address for XP backward compatibility */ | |
+ | |
+ prefixLength = prefix->PrefixLength; | |
+ break; | |
+ } | |
+#endif /* defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) */ | |
+ | |
+/* map prefix to netmask */ | |
+ ifa->ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family; | |
+ switch (unicast->Address.lpSockaddr->sa_family) { | |
+ case AF_INET: | |
+ if (0 == prefixLength || prefixLength > 32) { | |
+ prefixLength = 32; | |
+ } | |
+#if defined( _WIN32) && ( _WIN32_WINNT >= 0x0600 ) | |
+/* Added in Vista, but no IPv6 equivalent. */ | |
+ { | |
+ ULONG Mask; | |
+ ConvertLengthToIpv4Mask (prefixLength, &Mask); | |
+ ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr = Mask; /* network order */ | |
+ } | |
+#else | |
+/* NB: left-shift of full bit-width is undefined in C standard. */ | |
+ ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr = htonl( 0xffffffffU << ( 32 - prefixLength ) ); | |
+#endif | |
+ break; | |
+ | |
+ case AF_INET6: | |
+ if (0 == prefixLength || prefixLength > 128) { | |
+ prefixLength = 128; | |
+ } | |
+ for (LONG i = prefixLength, j = 0; i > 0; i -= 8, ++j) { | |
+ ((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr.s6_addr[ j ] = i >= 8 ? 0xff : (ULONG)(( 0xffU << ( 8 - i ) ) & 0xffU ); | |
+ } | |
+ break; | |
+ default: | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ free(pAddresses); | |
+ | |
+ return 0; | |
+} | |
+#else | |
+#error No reference implementation for getifaddrs available for this platform. | |
+#endif | |
+#endif | |
+ | |
static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr) | |
{ | |
int32_t res = -1; | |
- struct ifaddrs *ifaddr, *ifa; | |
+ struct ifaddrs *ifaddr = NULL, *ifa = NULL; | |
uint32_t addr_scope; | |
/* get scope for requested address */ | |
diff --git a/configure.ac b/configure.ac | |
index 6247389..39ecbed 100644 | |
--- a/configure.ac | |
+++ b/configure.ac | |
@@ -64,7 +64,7 @@ AC_TYPE_UINT32_T | |
AC_TYPE_UINT8_T | |
# Checks for library functions. | |
-AC_CHECK_FUNCS([strcasecmp strdup strerror stpncpy sleep malloc realloc]) | |
+AC_CHECK_FUNCS([strcasecmp strdup strerror stpncpy sleep malloc realloc getifaddrs]) | |
# Check for operating system | |
AC_MSG_CHECKING([for platform-specific build settings]) | |
diff --git a/src/Makefile.am b/src/Makefile.am | |
index 227a5c0..dc9a730 100644 | |
--- a/src/Makefile.am | |
+++ b/src/Makefile.am | |
@@ -10,7 +10,7 @@ libusbmuxd_2_0_la_SOURCES = libusbmuxd.c | |
if WIN32 | |
libusbmuxd_2_0_la_LDFLAGS += -avoid-version -static-libgcc | |
-libusbmuxd_2_0_la_LIBADD += -lws2_32 | |
+libusbmuxd_2_0_la_LIBADD += -lws2_32 -lIphlpapi | |
endif | |
pkgconfigdir = $(libdir)/pkgconfig | |
diff --git a/tools/iproxy.c b/tools/iproxy.c | |
index 0a52c67..28fcb46 100644 | |
--- a/tools/iproxy.c | |
+++ b/tools/iproxy.c | |
@@ -38,8 +38,8 @@ | |
#include <errno.h> | |
#include <getopt.h> | |
#ifdef WIN32 | |
-#include <windows.h> | |
#include <winsock2.h> | |
+#include <windows.h> | |
typedef unsigned int socklen_t; | |
#else | |
#include <sys/select.h> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment