diff options
Diffstat (limited to 'pr/src/misc/prnetdb.c')
-rw-r--r-- | pr/src/misc/prnetdb.c | 319 |
1 files changed, 301 insertions, 18 deletions
diff --git a/pr/src/misc/prnetdb.c b/pr/src/misc/prnetdb.c index b40ca804..f6699422 100644 --- a/pr/src/misc/prnetdb.c +++ b/pr/src/misc/prnetdb.c @@ -83,6 +83,12 @@ PRLock *_pr_dnsLock = NULL; * Some return a pointer to struct protoent, others return * an int. */ +#if defined(XP_BEOS) && defined(BONE_VERSION) +#include <arpa/inet.h> /* pick up define for inet_addr */ +#include <sys/socket.h> +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_POINTER +#endif #if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT)) \ || (defined(LINUX) && defined(_REENTRANT) \ @@ -92,7 +98,7 @@ PRLock *_pr_dnsLock = NULL; #endif #if defined(OSF1) \ - || defined(AIX4_3) || (defined(AIX) && defined(_THREAD_SAFE)) \ + || defined(AIX4_3_PLUS) || (defined(AIX) && defined(_THREAD_SAFE)) \ || (defined(HPUX10_10) && defined(_REENTRANT)) \ || (defined(HPUX10_20) && defined(_REENTRANT)) #define _PR_HAVE_GETPROTO_R @@ -157,6 +163,248 @@ const PRIPv6Addr _pr_in6addr_loopback = {{{ 0, 0, 0, 0, #define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->pr_s6_addr32[3]) +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + +/* + * The _pr_QueryNetIfs() function finds out if the system has + * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if + * and _pr_have_inet6_if accordingly. + * + * We have an implementation using SIOCGIFCONF ioctl and a + * default implementation that simply sets _pr_have_inet_if + * and _pr_have_inet6_if to true. A better implementation + * would be to use the routing sockets (see Chapter 17 of + * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.) + */ + +static PRBool _pr_have_inet_if = PR_FALSE; +static PRBool _pr_have_inet6_if = PR_FALSE; + +#undef DEBUG_QUERY_IFS + +#if defined(AIX) \ + || (defined(DARWIN) && (!defined(HAVE_GETIFADDRS) \ + || (defined(MACOS_DEPLOYMENT_TARGET) \ + && MACOS_DEPLOYMENT_TARGET < 100200))) + +/* + * Use SIOCGIFCONF ioctl on platforms that don't have routing + * sockets. Warning: whether SIOCGIFCONF ioctl returns AF_INET6 + * network interfaces is not portable. + * + * The _pr_QueryNetIfs() function is derived from the code in + * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in + * Section 16.6 of W. Richard Stevens' Unix Network Programming, + * Vol. 1, 2nd. Ed. + */ + +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <net/if.h> + +#ifdef DEBUG_QUERY_IFS +static void +_pr_PrintIfreq(struct ifreq *ifr) +{ + PRNetAddr addr; + struct sockaddr *sa; + const char* family; + char addrstr[64]; + + sa = &ifr->ifr_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + family = "inet"; + memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr)); + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + family = "inet6"; + memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); + } else { + return; /* skip if not AF_INET or AF_INET6 */ + } + addr.raw.family = sa->sa_family; + PR_NetAddrToString(&addr, addrstr, sizeof(addrstr)); + printf("%s: %s %s\n", ifr->ifr_name, family, addrstr); +} +#endif + +static void +_pr_QueryNetIfs(void) +{ + int sock; + int rv; + struct ifconf ifc; + struct ifreq *ifr; + struct ifreq *lifr; + PRUint32 len, lastlen; + char *buf; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + return; + } + + /* Issue SIOCGIFCONF request in a loop. */ + lastlen = 0; + len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ + for (;;) { + buf = (char *)PR_Malloc(len); + if (NULL == buf) { + close(sock); + return; + } + ifc.ifc_buf = buf; + ifc.ifc_len = len; + rv = ioctl(sock, SIOCGIFCONF, &ifc); + if (rv < 0) { + if (errno != EINVAL || lastlen != 0) { + close(sock); + PR_Free(buf); + return; + } + } else { + if (ifc.ifc_len == lastlen) + break; /* success, len has not changed */ + lastlen = ifc.ifc_len; + } + len += 10 * sizeof(struct ifreq); /* increment */ + PR_Free(buf); + } + close(sock); + + ifr = ifc.ifc_req; + lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; + + while (ifr < lifr) { + struct sockaddr *sa; + int sa_len; + +#ifdef DEBUG_QUERY_IFS + _pr_PrintIfreq(ifr); +#endif + sa = &ifr->ifr_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + _pr_have_inet_if = PR_TRUE; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + _pr_have_inet6_if = PR_TRUE; + } + } + +#ifdef _PR_HAVE_SOCKADDR_LEN + sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr)); +#else + switch (sa->sa_family) { +#ifdef AF_LINK + case AF_LINK: + sa_len = sizeof(struct sockaddr_dl); + break; +#endif + case AF_INET6: + sa_len = sizeof(struct sockaddr_in6); + break; + default: + sa_len = sizeof(struct sockaddr); + break; + } +#endif + ifr = (struct ifreq *)(((char *)sa) + sa_len); + } + PR_Free(buf); +} + +#elif (defined(DARWIN) && defined(HAVE_GETIFADDRS)) + +/* + * Use the BSD getifaddrs function. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <ifaddrs.h> +#include <netinet/in.h> + +#ifdef DEBUG_QUERY_IFS +static void +_pr_PrintIfaddrs(struct ifaddrs *ifa) +{ + struct sockaddr *sa; + const char* family; + void *addrp; + char addrstr[64]; + + sa = ifa->ifa_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + family = "inet"; + addrp = &sin->sin_addr; + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + family = "inet6"; + addrp = &sin6->sin6_addr; + } else { + return; /* skip if not AF_INET or AF_INET6 */ + } + inet_ntop(sa->sa_family, addrp, addrstr, sizeof(addrstr)); + printf("%s: %s %s\n", ifa->ifa_name, family, addrstr); +} +#endif + +static void +_pr_QueryNetIfs(void) +{ + struct ifaddrs *ifp; + struct ifaddrs *ifa; + + if (getifaddrs(&ifp) == -1) { + return; + } + for (ifa = ifp; ifa; ifa = ifa->ifa_next) { + struct sockaddr *sa; + +#ifdef DEBUG_QUERY_IFS + _pr_PrintIfaddrs(ifa); +#endif + sa = ifa->ifa_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + _pr_have_inet_if = 1; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + _pr_have_inet6_if = 1; + } + } + } + freeifaddrs(ifp); +} + +#else /* default */ + +/* + * Emulate the code in NSPR 4.2 or older. PR_GetIPNodeByName behaves + * as if the system had both IPv4 and IPv6 source addresses configured. + */ +static void +_pr_QueryNetIfs(void) +{ + _pr_have_inet_if = PR_TRUE; + _pr_have_inet6_if = PR_TRUE; +} + +#endif + +#endif /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */ + void _PR_InitNet(void) { #if defined(XP_UNIX) @@ -174,6 +422,31 @@ void _PR_InitNet(void) #if !defined(_PR_HAVE_GETPROTO_R) _getproto_lock = PR_NewLock(); #endif +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + _pr_QueryNetIfs(); +#ifdef DEBUG_QUERY_IFS + if (_pr_have_inet_if) + printf("Have IPv4 source address\n"); + if (_pr_have_inet6_if) + printf("Have IPv6 source address\n"); +#endif +#endif +} + +void _PR_CleanupNet(void) +{ +#if !defined(_PR_NO_DNS_LOCK) + if (_pr_dnsLock) { + PR_DestroyLock(_pr_dnsLock); + _pr_dnsLock = NULL; + } +#endif +#if !defined(_PR_HAVE_GETPROTO_R) + if (_getproto_lock) { + PR_DestroyLock(_getproto_lock); + _getproto_lock = NULL; + } +#endif } /* @@ -215,7 +488,6 @@ static void MakeIPv4MappedAddr(const char *v4, char *v6) memset(v6, 0, 10); memset(v6 + 10, 0xff, 2); memcpy(v6 + 12, v4, 4); - PR_ASSERT(_PR_IN6_IS_ADDR_V4MAPPED(((PRIPv6Addr *) v6))); } /* @@ -225,7 +497,6 @@ static void MakeIPv4CompatAddr(const char *v4, char *v6) { memset(v6, 0, 12); memcpy(v6 + 12, v4, 4); - PR_ASSERT(_PR_IN6_IS_ADDR_V4COMPAT(((PRIPv6Addr *) v6))); } /* @@ -406,7 +677,7 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByName( tmpbuf = localbuf; if (bufsize > sizeof(localbuf)) { - tmpbuf = PR_Malloc(bufsize); + tmpbuf = (char *)PR_Malloc(bufsize); if (NULL == tmpbuf) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); @@ -538,7 +809,7 @@ PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName( tmpbuf = localbuf; if (bufsize > sizeof(localbuf)) { - tmpbuf = PR_Malloc(bufsize); + tmpbuf = (char *)PR_Malloc(bufsize); if (NULL == tmpbuf) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); @@ -553,11 +824,15 @@ PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName( LOCK_DNS(); if (af == PR_AF_INET6) { + if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet6_if) + { #ifdef _PR_INET6_PROBE - if (_pr_ipv6_is_present == PR_TRUE) + if (_pr_ipv6_is_present == PR_TRUE) #endif - h = GETHOSTBYNAME2(name, AF_INET6); - if ((NULL == h) && (flags & PR_AI_V4MAPPED)) + h = GETHOSTBYNAME2(name, AF_INET6); + } + if ((NULL == h) && (flags & PR_AI_V4MAPPED) + && ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if)) { did_af_inet = PR_TRUE; h = GETHOSTBYNAME2(name, AF_INET); @@ -565,8 +840,11 @@ PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName( } else { - did_af_inet = PR_TRUE; - h = GETHOSTBYNAME2(name, af); + if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if) + { + did_af_inet = PR_TRUE; + h = GETHOSTBYNAME2(name, af); + } } #elif defined(_PR_HAVE_GETIPNODEBYNAME) h = getipnodebyname(name, md_af, tmp_flags, &error_num); @@ -619,7 +897,8 @@ PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName( #endif #if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) if ((PR_SUCCESS == rv) && (flags & PR_AI_V4MAPPED) - && (flags & (PR_AI_ALL|PR_AI_ADDRCONFIG)) + && ((flags & PR_AI_ALL) + || ((flags & PR_AI_ADDRCONFIG) && _pr_have_inet_if)) && !did_af_inet && (h = GETHOSTBYNAME2(name, AF_INET)) != 0) { rv = AppendV4AddrsToHostent(h, &buf, &bufsize, hp); if (PR_SUCCESS != rv) @@ -681,6 +960,10 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByAddr( #else af = AF_INET; #endif +#if defined(_PR_GHBA_DISALLOW_V4MAPPED) + if (_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) + af = AF_INET; +#endif } else { @@ -717,7 +1000,7 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByAddr( tmpbuf = localbuf; if (bufsize > sizeof(localbuf)) { - tmpbuf = PR_Malloc(bufsize); + tmpbuf = (char *)PR_Malloc(bufsize); if (NULL == tmpbuf) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); @@ -1164,7 +1447,7 @@ PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val) return PR_FALSE; } -#ifndef _PR_INET6 +#ifndef _PR_HAVE_INET_NTOP #define XX 127 static const unsigned char index_hex[256] = { XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, @@ -1404,14 +1687,14 @@ static const char *V6AddrToString( #undef STUFF } -#endif /* !_PR_INET6 */ +#endif /* !_PR_HAVE_INET_NTOP */ PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr) { PRStatus status = PR_SUCCESS; PRIntn rv; -#if defined(_PR_INET6) +#if defined(_PR_HAVE_INET_NTOP) rv = inet_pton(AF_INET6, string, &addr->ipv6.ip); if (1 == rv) { @@ -1434,7 +1717,7 @@ PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr) status = PR_FAILURE; } } -#else /* _PR_INET6 */ +#else /* _PR_HAVE_INET_NTOP */ rv = StringToV6Addr(string, &addr->ipv6.ip); if (1 == rv) { addr->raw.family = PR_AF_INET6; @@ -1458,7 +1741,7 @@ PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); status = PR_FAILURE; } -#endif /* _PR_INET6 */ +#endif /* _PR_HAVE_INET_NTOP */ return status; } @@ -1468,7 +1751,7 @@ PR_IMPLEMENT(PRStatus) PR_NetAddrToString( { if (PR_AF_INET6 == addr->raw.family) { -#if defined(_PR_INET6) +#if defined(_PR_HAVE_INET_NTOP) if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size)) #else if (NULL == V6AddrToString(&addr->ipv6.ip, string, size)) |