From: Dave Hart Date: Mon, 6 Dec 2010 02:14:03 +0000 (+0000) Subject: Add GetAdaptersAddress()-based interface enumeration to libisc Windows code, X-Git-Tag: NTP_4_2_7P90~3^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c434378d4c958e90388d006a6b333ea14886f882;p=thirdparty%2Fntp.git Add GetAdaptersAddress()-based interface enumeration to libisc Windows code, runtime linked on Windows XP SP1 and later only, which provides correct interface name with each address. bk: 4cfc46ebxn6A2PB8dxfQmzMM1vugWw --- diff --git a/include/isc/mem.h b/include/isc/mem.h index a7df351f9..e6b0e2236 100644 --- a/include/isc/mem.h +++ b/include/isc/mem.h @@ -42,14 +42,26 @@ #include -#define isc_mem_get(c, cnt) emalloc((cnt)) -#define isc_mem_allocate(c, cnt) emalloc((cnt)) -#define isc_mem_reallocate(c, mem, cnt) erealloc((mem), (cnt)) -#define isc_mem_put(c, mem, cnt) free((mem)) -#define isc_mem_free(c, mem) free((mem)) -#define isc_mem_strdup(c, str) estrdup((str)) +#define ISC_MEM_UNUSED_ARG(ctx) ((void)(ctx)) + +#define isc_mem_get(c, cnt) \ + (ISC_MEM_UNUSED_ARG(c), emalloc((cnt))) +#define isc_mem_allocate(c, cnt) isc_mem_get(c, cnt) + +#define isc_mem_reallocate(c, mem, cnt) \ + (ISC_MEM_UNUSED_ARG(c), erealloc((mem), (cnt))) + +#define isc_mem_put(c, mem, cnt) \ + (ISC_MEM_UNUSED_ARG(cnt), isc_mem_free(c, (mem))) +#define isc_mem_free(c, mem) \ + (ISC_MEM_UNUSED_ARG(c), free((mem))) + +#define isc_mem_strdup(c, str) \ + (ISC_MEM_UNUSED_ARG(c), estrdup((str))) + #define isc_mem_attach(src, ptgt) do { *(ptgt) = (src); } while (0) #define isc_mem_detach(c) ((void)(c)) -#define isc_mem_printallactive(s) fprintf(s, "isc_mem_printallactive() stubbed.\n") +#define isc_mem_printallactive(s) fprintf((s), \ + "isc_mem_printallactive() stubbed.\n") #endif /* ISC_MEM_H */ diff --git a/lib/isc/inet_pton.c b/lib/isc/inet_pton.c index 6bada239e..cd5bb79b5 100644 --- a/lib/isc/inet_pton.c +++ b/lib/isc/inet_pton.c @@ -91,13 +91,13 @@ inet_pton4(const char *src, unsigned char *dst) { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { - unsigned int new = *tp * 10 + (pch - digits); + unsigned int newv = *tp * 10 + (pch - digits); if (saw_digit && *tp == 0) return (0); - if (new > 255) + if (newv > 255) return (0); - *tp = new; + *tp = (unsigned char)newv; if (!saw_digit) { if (++octets > 4) return (0); diff --git a/lib/isc/netaddr.c b/lib/isc/netaddr.c index 85dd53e03..2d745feb8 100644 --- a/lib/isc/netaddr.c +++ b/lib/isc/netaddr.c @@ -211,7 +211,7 @@ isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) { isc_result_t isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) { - static const unsigned char zeros[16]; + static const unsigned char zeros[16] = { 0 }; unsigned int nbits, nbytes, ipbytes; const unsigned char *p; diff --git a/lib/isc/win32/include/isc/once.h b/lib/isc/win32/include/isc/once.h index 32af1bdf4..0dc1686e4 100644 --- a/lib/isc/win32/include/isc/once.h +++ b/lib/isc/win32/include/isc/once.h @@ -27,7 +27,7 @@ ISC_LANG_BEGINDECLS typedef struct { int status; - int counter; + LONG counter; } isc_once_t; #define ISC_ONCE_INIT_NEEDED 0 diff --git a/lib/isc/win32/interfaceiter.c b/lib/isc/win32/interfaceiter.c index a6cd7229b..8eb7f466d 100644 --- a/lib/isc/win32/interfaceiter.c +++ b/lib/isc/win32/interfaceiter.c @@ -17,14 +17,10 @@ /* $Id: interfaceiter.c,v 1.13.110.2 2009/01/18 23:47:41 tbox Exp $ */ -/* - * Note that this code will need to be revisited to support IPv6 Interfaces. - * For now we just iterate through IPv4 interfaces. - */ - #include #include #include +#include #include #include @@ -33,32 +29,34 @@ #include #include +//#include #include #include #include #include #include +#include void InitSockets(void); -/* Common utility functions */ - -/* - * Extract the network address part from a "struct sockaddr". - * - * The address family is given explicitly - * instead of using src->sa_family, because the latter does not work - * for copying a network mask obtained by SIOCGIFNETMASK (it does - * not have a valid address family). - */ - #define IFITER_MAGIC 0x49464954U /* IFIT. */ #define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC) struct isc_interfaceiter { unsigned int magic; /* Magic number. */ + /* common fields */ isc_mem_t *mctx; + struct in6_addr loop__1; /* ::1 node-scope localhost */ + struct in6_addr loopfe80__1; /* fe80::1 link-scope localhost */ + isc_interface_t current; /* Current interface data. */ + isc_result_t result; /* Last result code. */ + /* fields used if GetAdaptersAddresses is available at runtime */ + IP_ADAPTER_ADDRESSES * ipaa; /* GAA() result buffer */ + ULONG ipaasize; /* Bytes allocated */ + IP_ADAPTER_ADDRESSES * ipaaCur; /* enumeration position */ + IP_ADAPTER_UNICAST_ADDRESS *ipuaCur; /* enumeration subposition */ + /* fields used for the older address enumeration ioctls */ int socket; INTERFACE_INFO IFData; /* Current Interface Info */ int numIF; /* Current Interface count */ @@ -69,12 +67,21 @@ struct isc_interfaceiter { SOCKET_ADDRESS_LIST *buf6; unsigned int buf6size; /* Bytes allocated. */ unsigned int pos6; /* buf6 index, counts down */ - struct in6_addr loop__1; /* ::1 node-scope localhost */ - struct in6_addr loopfe80__1; /* fe80::1 link-scope localhost */ - isc_interface_t current; /* Current interface data. */ - isc_result_t result; /* Last result code. */ }; +typedef ULONG (WINAPI *PGETADAPTERSADDRESSES)( + ULONG Family, + ULONG Flags, + PVOID Reserved, + PIP_ADAPTER_ADDRESSES AdapterAddresses, + PULONG SizePointer +); + +/* static */ isc_boolean_t use_GAA; +static isc_boolean_t use_GAA_determined; +static HMODULE hmod_iphlpapi; +static PGETADAPTERSADDRESSES pGAA; + /* * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces. @@ -85,28 +92,8 @@ struct isc_interfaceiter { #define IFCONF_SIZE_INCREMENT 64 #define IFCONF_SIZE_MAX 1040 -static void -get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) { - dst->family = family; - switch (family) { - case AF_INET: - memcpy(&dst->type.in, - &((struct sockaddr_in *) src)->sin_addr, - sizeof(struct in_addr)); - break; - case AF_INET6: - memcpy(&dst->type.in6, - &((struct sockaddr_in6 *) src)->sin6_addr, - sizeof(struct in6_addr)); -#ifdef ISC_PLATFORM_HAVESCOPEID - dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id; -#endif - break; - default: - INSIST(0); - break; - } -} + +/* Common utility functions */ /* * Windows always provides 255.255.255.255 as the the broadcast @@ -132,6 +119,11 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { char strbuf[ISC_STRERRORSIZE]; isc_interfaceiter_t *iter; isc_result_t result; + unsigned int major; + unsigned int minor; + unsigned int spmajor; + ULONG err; + int tries; int error; unsigned long bytesReturned = 0; @@ -146,9 +138,13 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { InitSockets(); iter->mctx = mctx; + iter->ipaa = NULL; iter->buf4 = NULL; iter->buf6 = NULL; iter->pos4 = NULL; + iter->ipaaCur = NULL; + iter->ipuaCur = NULL; + iter->ipaasize = 0; iter->pos6 = 0; iter->buf6size = 0; iter->buf4size = 0; @@ -156,6 +152,66 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { iter->numIF = 0; iter->v4IF = 0; + /* + * Use GetAdaptersAddresses in preference to ioctls when running + * on Windows XP SP1 or later. Earlier GetAdaptersAddresses do + * not appear to provide enough information to associate unicast + * addresses with their prefixes. + */ + if (!use_GAA_determined) { + major = isc_win32os_majorversion(); + minor = isc_win32os_minorversion(); + spmajor = isc_win32os_servicepackmajor(); + if (major > 5 || (5 == major && + (minor > 1 || (1 == minor && spmajor >= 1)))) { + if (NULL == hmod_iphlpapi) + hmod_iphlpapi = LoadLibrary("iphlpapi"); + if (NULL != hmod_iphlpapi) + pGAA = (PGETADAPTERSADDRESSES) + GetProcAddress( + hmod_iphlpapi, + "GetAdaptersAddresses"); + if (NULL != pGAA) + use_GAA = ISC_TRUE; + } + use_GAA_determined = ISC_TRUE; + } + + if (!use_GAA) + goto use_ioctls; + + iter->ipaasize = 16 * 1024; + + for (tries = 0; tries < 5; tries++) { + iter->ipaa = isc_mem_reallocate(mctx, iter->ipaa, + iter->ipaasize); + if (NULL == iter->ipaa) { + result = ISC_R_NOMEMORY; + goto put_iter; + } + err = (*pGAA)( + AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST, + NULL, + iter->ipaa, + &iter->ipaasize); + if (NO_ERROR == err || ERROR_BUFFER_OVERFLOW == !err) + break; + } + + if (NO_ERROR != err) { + isc__strerror(err, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "GetAdaptersAddresses: %s", + strbuf); + result = ISC_R_UNEXPECTED; + goto gaa_failure; + } + + iter->ipaaCur = iter->ipaa; + goto success; + + use_ioctls: /* * Create an unbound datagram socket to do the * SIO_GET_INTERFACE_LIST WSAIoctl on. @@ -169,7 +225,7 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { "making interface scan socket: %s", strbuf); result = ISC_R_UNEXPECTED; - goto socket_failure; + goto put_iter; } /* @@ -243,13 +299,13 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { error = WSAGetLastError(); if (error == WSAEAFNOSUPPORT) - goto inet_only; + goto success; isc__strerror(error, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "making interface scan socket: %s", strbuf); result = ISC_R_UNEXPECTED; - goto ioctl_failure; + goto put_iter; } /* @@ -312,11 +368,15 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { closesocket(iter->socket); - inet_only: + success: iter->magic = IFITER_MAGIC; *iterp = iter; return (ISC_R_SUCCESS); + gaa_failure: + isc_mem_put(mctx, iter->ipaa, iter->ipaasize); + goto put_iter; + ioctl6_failure: isc_mem_put(mctx, iter->buf6, iter->buf6size); @@ -328,11 +388,107 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { if (iter->socket >= 0) (void) closesocket(iter->socket); - socket_failure: + put_iter: isc_mem_put(mctx, iter, sizeof(*iter)); return (result); } +static unsigned char +GAA_find_prefix(isc_interfaceiter_t *iter) { + IP_ADAPTER_PREFIX * ipap; + IP_ADAPTER_PREFIX * ipap_match; + int match_len; + int max_len; + isc_netaddr_t target; + u_short af; + isc_netaddr_t pfx; + int pfx_len; + size_t nbytes; + unsigned char nbits; + unsigned char * pbits; + unsigned int octets; + + match_len = 0; + ipap_match = NULL; + isc_netaddr_fromsockaddr(&target, + (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr); + af = (u_short)target.family; + INSIST(AF_INET == af || AF_INET6 == af); + max_len = (AF_INET6 == af) ? 128 : 32; + iter->current.netmask.family = af; + for (ipap = iter->ipaaCur->FirstPrefix; + ipap != NULL; + ipap = ipap->Next) { + if (ipap->Address.lpSockaddr->sa_family != af) + continue; + isc_netaddr_fromsockaddr(&pfx, + (isc_sockaddr_t *)ipap->Address.lpSockaddr); + pfx_len = ipap->PrefixLength; + INSIST(0 <= pfx_len && pfx_len <= max_len); + if (pfx_len > match_len && pfx_len < max_len && + isc_netaddr_eqprefix(&target, &pfx, pfx_len)) { + ipap_match = ipap; + match_len = pfx_len; + } + } + if (NULL == ipap_match) { + /* presume all-ones mask */ + if (AF_INET6 == af) + octets = sizeof(iter->current.netmask.type.in6); + else + octets = sizeof(iter->current.netmask.type.in); + memset(&iter->current.netmask.type.in6, 0xFF, octets); + return (8 * (unsigned char)octets); + } + nbytes = match_len / 8; + nbits = match_len % 8; + memset(&iter->current.netmask.type.in6, 0xFF, nbytes); + pbits = (void *)&iter->current.netmask.type.in6; + pbits += nbytes; + *pbits |= 0xFF << (8 - nbits); + return ((unsigned char)match_len); +} + +static isc_result_t +internal_current_GAA(isc_interfaceiter_t *iter) { + unsigned char prefix_len; + + REQUIRE(iter->ipuaCur != NULL); + memset(&iter->current, 0, sizeof(iter->current)); + iter->current.af = iter->ipuaCur->Address.lpSockaddr->sa_family; + isc_netaddr_fromsockaddr(&iter->current.address, + (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr); + iter->current.name[0] = '\0'; + WideCharToMultiByte( + CP_ACP, + 0, + iter->ipaaCur->FriendlyName, + -1, + iter->current.name, + sizeof(iter->current.name), + NULL, + NULL); + iter->current.name[sizeof(iter->current.name) - 1] = '\0'; + if (IfOperStatusUp == iter->ipaaCur->OperStatus) + iter->current.flags |= INTERFACE_F_UP; + if ((IP_ADAPTER_NO_MULTICAST & iter->ipaaCur->Flags) == 0) + iter->current.flags |= INTERFACE_F_MULTICAST; + if (IF_TYPE_PPP == iter->ipaaCur->IfType) + iter->current.flags |= INTERFACE_F_POINTTOPOINT; + else if (IF_TYPE_SOFTWARE_LOOPBACK == iter->ipaaCur->IfType) + iter->current.flags |= INTERFACE_F_LOOPBACK; + prefix_len = GAA_find_prefix(iter); + /* I'm failing to see a broadcast flag via GAA */ + if (AF_INET == iter->current.af && prefix_len < 32 && + (INTERFACE_F_LOOPBACK & iter->current.flags) == 0) { + iter->current.flags |= INTERFACE_F_BROADCAST; + get_broadcastaddr(&iter->current.broadcast, + &iter->current.address, + &iter->current.netmask); + } + return (ISC_R_SUCCESS); +} + /* * Get information about the current interface to iter->current. * If successful, return ISC_R_SUCCESS. @@ -352,8 +508,8 @@ internal_current(isc_interfaceiter_t *iter) { memset(&iter->current, 0, sizeof(iter->current)); iter->current.af = AF_INET; - get_addr(AF_INET, &iter->current.address, - (struct sockaddr *)&(iter->IFData.iiAddress)); + isc_netaddr_fromsockaddr(&iter->current.address, + (isc_sockaddr_t *)&(iter->IFData.iiAddress)); /* * Get interface flags. @@ -388,16 +544,15 @@ internal_current(isc_interfaceiter_t *iter) { /* * If the interface is point-to-point, get the destination address. */ - if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { - get_addr(AF_INET, &iter->current.dstaddress, - (struct sockaddr *)&(iter->IFData.iiBroadcastAddress)); - } + if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) + isc_netaddr_fromsockaddr(&iter->current.dstaddress, + (isc_sockaddr_t *)&(iter->IFData.iiBroadcastAddress)); /* * Get the network mask. */ - get_addr(AF_INET, &iter->current.netmask, - (struct sockaddr *)&(iter->IFData.iiNetmask)); + isc_netaddr_fromsockaddr(&iter->current.netmask, + (isc_sockaddr_t *)&(iter->IFData.iiNetmask)); /* * If the interface is broadcast, get the broadcast address, @@ -448,10 +603,10 @@ internal_current6(isc_interfaceiter_t *iter) { iter->pos6 = iter->buf6->iAddressCount - 1; } - if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) - get_addr(AF_INET6, &iter->current.address, - iter->buf6->Address[iter->pos6].lpSockaddr); - else { + if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) { + isc_netaddr_fromsockaddr(&iter->current.address, + (isc_sockaddr_t *)iter->buf6->Address[iter->pos6].lpSockaddr); + } else { iter->current.address.family = AF_INET6; memcpy(&iter->current.address.type.in6, &iter->loop__1, sizeof(iter->current.address.type.in6)); @@ -486,6 +641,24 @@ internal_current6(isc_interfaceiter_t *iter) { return (ISC_R_SUCCESS); } +static isc_result_t +internal_next_GAA(isc_interfaceiter_t *iter) { + REQUIRE(use_GAA); + if (NULL == iter->ipaaCur) + return (ISC_R_NOMORE); + if (NULL == iter->ipuaCur) + iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; + else + iter->ipuaCur = iter->ipuaCur->Next; + while (NULL == iter->ipuaCur) { + iter->ipaaCur = iter->ipaaCur->Next; + if (NULL == iter->ipaaCur) + return (ISC_R_NOMORE); + iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; + } + return (ISC_R_SUCCESS); +} + /* * Step the iterator to the next interface. Unlike * isc_interfaceiter_next(), this may leave the iterator @@ -537,21 +710,22 @@ isc_interfaceiter_current(isc_interfaceiter_t *iter, isc_result_t isc_interfaceiter_first(isc_interfaceiter_t *iter) { - REQUIRE(VALID_IFITER(iter)); - + REQUIRE(use_GAA_determined); /* * SIO_ADDRESS_LIST_QUERY (used to query IPv6 addresses) - * intentionally omits localhost addresses ::1 and ::fe80 in - * some cases. ntpd depends on enumerating ::1 to listen on + * intentionally omits localhost addresses [::1] and [::fe80] in + * some cases. ntpd depends on enumerating [::1] to listen on * it, and ntpq and ntpdc default to "localhost" as the target, * so they will attempt to talk to [::1]:123 and fail. This * means we need to synthesize ::1, which we will do first, - * hence + 1. + * hence iAddressCount + 1. internal_next6() will decrement + * it before the first use as an index, and internal_current6() + * will treat pos6 == iAddressCount as a sign to synthesize + * [::1] if needed. */ - if (iter->buf6 != NULL) + if (!use_GAA && iter->buf6 != NULL) iter->pos6 = iter->buf6->iAddressCount + 1; - iter->result = ISC_R_SUCCESS; return (isc_interfaceiter_next(iter)); } @@ -562,6 +736,15 @@ isc_interfaceiter_next(isc_interfaceiter_t *iter) { REQUIRE(VALID_IFITER(iter)); REQUIRE(iter->result == ISC_R_SUCCESS); + REQUIRE(use_GAA_determined); + + if (use_GAA) { + result = internal_next_GAA(iter); + if (ISC_R_NOMORE == result) + goto set_result; + result = internal_current_GAA(iter); + goto set_result; + } for (;;) { result = internal_next(iter); @@ -578,6 +761,7 @@ isc_interfaceiter_next(isc_interfaceiter_t *iter) { if (result != ISC_R_IGNORE) break; } + set_result: iter->result = result; return (result); } @@ -585,14 +769,24 @@ isc_interfaceiter_next(isc_interfaceiter_t *iter) { void isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) { isc_interfaceiter_t *iter; + REQUIRE(iterp != NULL); iter = *iterp; REQUIRE(VALID_IFITER(iter)); - - if (iter->buf4 != NULL) - isc_mem_put(iter->mctx, iter->buf4, iter->buf4size); - if (iter->buf6 != NULL) - isc_mem_put(iter->mctx, iter->buf6, iter->buf6size); + REQUIRE(use_GAA_determined); + + if (use_GAA) { + REQUIRE(NULL == iter->buf4); + REQUIRE(NULL == iter->buf4); + if (iter->ipaa != NULL) + isc_mem_put(iter->mctx, iter->ipaa, iter->ipaasize); + } else { + REQUIRE(NULL == iter->ipaa); + if (iter->buf4 != NULL) + isc_mem_put(iter->mctx, iter->buf4, iter->buf4size); + if (iter->buf6 != NULL) + isc_mem_put(iter->mctx, iter->buf6, iter->buf6size); + } iter->magic = 0; isc_mem_put(iter->mctx, iter, sizeof(*iter)); diff --git a/lib/isc/win32/net.c b/lib/isc/win32/net.c index 784364d50..240c78336 100644 --- a/lib/isc/win32/net.c +++ b/lib/isc/win32/net.c @@ -69,7 +69,6 @@ void InitSockets(void); static isc_result_t try_proto(int domain) { SOCKET s; - isc_result_t result = ISC_R_SUCCESS; char strbuf[ISC_STRERRORSIZE]; int errval; diff --git a/lib/isc/win32/stdtime.c b/lib/isc/win32/stdtime.c index 574297efe..ca462513c 100644 --- a/lib/isc/win32/stdtime.c +++ b/lib/isc/win32/stdtime.c @@ -33,5 +33,5 @@ isc_stdtime_get(isc_stdtime_t *t) { REQUIRE(t != NULL); - (void)time(t); + (void)time((time_t *)t); }