зеркало из https://github.com/mozilla/pjs.git
Bug 144886: On platforms with gethostbyname2, add the infrastructure for
PR_GetIPNodeByName to implement PR_AI_ADDRCONFIG correctly. Right now only AIX implements the function to determine if the system has any IPv4 or IPv6 source address configured. On other platforms PR_GetIPNodeByName still behaves as if the system had both IPv4 and IPv6 source addresses configured.
This commit is contained in:
Родитель
bd3ae1eb74
Коммит
ef6de7f68e
|
@ -163,6 +163,175 @@ 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)
|
||||
|
||||
/*
|
||||
* 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 = 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)) {
|
||||
_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);
|
||||
}
|
||||
|
||||
#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)
|
||||
|
@ -180,6 +349,15 @@ 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)
|
||||
|
@ -573,11 +751,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);
|
||||
|
@ -585,8 +767,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);
|
||||
|
@ -639,7 +824,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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче