mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-01 17:30:07 +00:00
* include/ifaddrs.c (struct in6addrinfo): Add prefixlen field.
* sysdeps/unix/sysv/linux/check_pf.c (make_request): Always return list of interfaces. Also store prefix length. * sysdeps/posix/getaddrinfo.c (sort_result): Add prefixlen element. (rfc3484_sort): In rule 9, for IPv4 addresses count only matching prefix if source and destination address are in the same subnet. (getaddrinfo): Always call __check_pf. Fill in prefixlen field. Always look for matching record in in6ai list. Correct source_addr_len value for IPv6->IPv4 converted records.
This commit is contained in:
parent
c1600ce36d
commit
6f3914d5a3
12
ChangeLog
12
ChangeLog
@ -1,3 +1,15 @@
|
|||||||
|
2007-11-12 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
|
* include/ifaddrs.c (struct in6addrinfo): Add prefixlen field.
|
||||||
|
* sysdeps/unix/sysv/linux/check_pf.c (make_request): Always return
|
||||||
|
list of interfaces. Also store prefix length.
|
||||||
|
* sysdeps/posix/getaddrinfo.c (sort_result): Add prefixlen element.
|
||||||
|
(rfc3484_sort): In rule 9, for IPv4 addresses count only matching
|
||||||
|
prefix if source and destination address are in the same subnet.
|
||||||
|
(getaddrinfo): Always call __check_pf. Fill in prefixlen field.
|
||||||
|
Always look for matching record in in6ai list.
|
||||||
|
Correct source_addr_len value for IPv6->IPv4 converted records.
|
||||||
|
|
||||||
2007-11-11 Roland McGrath <roland@frob.com>
|
2007-11-11 Roland McGrath <roland@frob.com>
|
||||||
|
|
||||||
* include/kernel-features.h: New file.
|
* include/kernel-features.h: New file.
|
||||||
|
@ -1006,6 +1006,7 @@ struct sort_result
|
|||||||
uint8_t source_addr_len;
|
uint8_t source_addr_len;
|
||||||
bool got_source_addr;
|
bool got_source_addr;
|
||||||
uint8_t source_addr_flags;
|
uint8_t source_addr_flags;
|
||||||
|
uint8_t prefixlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1223,7 +1224,7 @@ static int
|
|||||||
fls (uint32_t a)
|
fls (uint32_t a)
|
||||||
{
|
{
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
int n = 0;
|
int n;
|
||||||
for (n = 0, mask = 1 << 31; n < 32; mask >>= 1, ++n)
|
for (n = 0, mask = 1 << 31; n < 32; mask >>= 1, ++n)
|
||||||
if ((a & mask) != 0)
|
if ((a & mask) != 0)
|
||||||
break;
|
break;
|
||||||
@ -1350,20 +1351,31 @@ rfc3484_sort (const void *p1, const void *p2)
|
|||||||
assert (a1->source_addr.ss_family == PF_INET);
|
assert (a1->source_addr.ss_family == PF_INET);
|
||||||
assert (a2->source_addr.ss_family == PF_INET);
|
assert (a2->source_addr.ss_family == PF_INET);
|
||||||
|
|
||||||
struct sockaddr_in *in1_dst;
|
/* Outside of subnets, as defined by the network masks,
|
||||||
struct sockaddr_in *in1_src;
|
common address prefixes for IPv4 addresses make no sense.
|
||||||
struct sockaddr_in *in2_dst;
|
So, define a non-zero value only if source and
|
||||||
struct sockaddr_in *in2_src;
|
destination address are on the same subnet. */
|
||||||
|
struct sockaddr_in *in1_dst
|
||||||
|
= (struct sockaddr_in *) a1->dest_addr->ai_addr;
|
||||||
|
in_addr_t in1_dst_addr = ntohl (in1_dst->sin_addr.s_addr);
|
||||||
|
struct sockaddr_in *in1_src
|
||||||
|
= (struct sockaddr_in *) &a1->source_addr;
|
||||||
|
in_addr_t in1_src_addr = ntohl (in1_src->sin_addr.s_addr);
|
||||||
|
in_addr_t netmask1 = 0xffffffffu << (32 - a1->prefixlen);
|
||||||
|
|
||||||
in1_dst = (struct sockaddr_in *) a1->dest_addr->ai_addr;
|
if ((in1_src_addr & netmask1) == (in1_dst_addr & netmask1))
|
||||||
in1_src = (struct sockaddr_in *) &a1->source_addr;
|
bit1 = fls (in1_dst_addr ^ in1_src_addr);
|
||||||
in2_dst = (struct sockaddr_in *) a2->dest_addr->ai_addr;
|
|
||||||
in2_src = (struct sockaddr_in *) &a2->source_addr;
|
|
||||||
|
|
||||||
bit1 = fls (ntohl (in1_dst->sin_addr.s_addr
|
struct sockaddr_in *in2_dst
|
||||||
^ in1_src->sin_addr.s_addr));
|
= (struct sockaddr_in *) a2->dest_addr->ai_addr;
|
||||||
bit2 = fls (ntohl (in2_dst->sin_addr.s_addr
|
in_addr_t in2_dst_addr = ntohl (in2_dst->sin_addr.s_addr);
|
||||||
^ in2_src->sin_addr.s_addr));
|
struct sockaddr_in *in2_src
|
||||||
|
= (struct sockaddr_in *) &a2->source_addr;
|
||||||
|
in_addr_t in2_src_addr = ntohl (in2_src->sin_addr.s_addr);
|
||||||
|
in_addr_t netmask2 = 0xffffffffu << (32 - a2->prefixlen);
|
||||||
|
|
||||||
|
if ((in2_src_addr & netmask2) == (in2_dst_addr & netmask2))
|
||||||
|
bit2 = fls (in2_dst_addr ^ in2_src_addr);
|
||||||
}
|
}
|
||||||
else if (a1->dest_addr->ai_family == PF_INET6)
|
else if (a1->dest_addr->ai_family == PF_INET6)
|
||||||
{
|
{
|
||||||
@ -1799,14 +1811,8 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
int sockfd = -1;
|
int sockfd = -1;
|
||||||
pid_t nl_pid;
|
pid_t nl_pid;
|
||||||
#endif
|
#endif
|
||||||
/* We might need information about what kind of interfaces are available.
|
/* We might need information about what interfaces are available.
|
||||||
But even if AI_ADDRCONFIG is not used, if the user requested IPv6
|
Also determine whether we have IPv4 or IPv6 interfaces or both. We
|
||||||
addresses we have to know whether an address is deprecated or
|
|
||||||
temporary. */
|
|
||||||
if ((hints->ai_flags & AI_ADDRCONFIG) || hints->ai_family == PF_UNSPEC
|
|
||||||
|| hints->ai_family == PF_INET6)
|
|
||||||
{
|
|
||||||
/* Determine whether we have IPv4 or IPv6 interfaces or both. We
|
|
||||||
cannot cache the results since new interfaces could be added at
|
cannot cache the results since new interfaces could be added at
|
||||||
any time. */
|
any time. */
|
||||||
__check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
|
__check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
|
||||||
@ -1836,26 +1842,11 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
if (sockfd >= 0)
|
if (sockfd >= 0)
|
||||||
close_not_cancel_no_status (sockfd);
|
close_not_cancel_no_status (sockfd);
|
||||||
|
|
||||||
#if __ASSUME_NETLINK_SUPPORT == 0
|
|
||||||
/* Remember that there is no netlink support. */
|
/* Remember that there is no netlink support. */
|
||||||
if (errno != EMFILE && errno != ENFILE)
|
if (errno != EMFILE && errno != ENFILE)
|
||||||
__no_netlink_support = 1;
|
__no_netlink_support = 1;
|
||||||
#else
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (errno != EMFILE && errno != ENFILE)
|
|
||||||
sockfd = -2;
|
|
||||||
|
|
||||||
/* We cannot determine what interfaces are available. Be
|
|
||||||
pessimistic. */
|
|
||||||
seen_ipv4 = true;
|
|
||||||
seen_ipv6 = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_NETLINK_ROUTE
|
#ifdef HAVE_NETLINK_ROUTE
|
||||||
got_netlink_socket:
|
got_netlink_socket:
|
||||||
@ -1958,7 +1949,6 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
|
for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
|
||||||
{
|
{
|
||||||
results[i].dest_addr = q;
|
results[i].dest_addr = q;
|
||||||
results[i].got_source_addr = false;
|
|
||||||
results[i].service_order = i;
|
results[i].service_order = i;
|
||||||
|
|
||||||
/* If we just looked up the address for a different
|
/* If we just looked up the address for a different
|
||||||
@ -1971,10 +1961,13 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
results[i].source_addr_len = results[i - 1].source_addr_len;
|
results[i].source_addr_len = results[i - 1].source_addr_len;
|
||||||
results[i].got_source_addr = results[i - 1].got_source_addr;
|
results[i].got_source_addr = results[i - 1].got_source_addr;
|
||||||
results[i].source_addr_flags = results[i - 1].source_addr_flags;
|
results[i].source_addr_flags = results[i - 1].source_addr_flags;
|
||||||
|
results[i].prefixlen = results[i - 1].prefixlen;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
results[i].got_source_addr = false;
|
||||||
results[i].source_addr_flags = 0;
|
results[i].source_addr_flags = 0;
|
||||||
|
results[i].prefixlen = 0;
|
||||||
|
|
||||||
/* We overwrite the type with SOCK_DGRAM since we do not
|
/* We overwrite the type with SOCK_DGRAM since we do not
|
||||||
want connect() to connect to the other side. If we
|
want connect() to connect to the other side. If we
|
||||||
@ -2005,22 +1998,39 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
results[i].source_addr_len = sl;
|
results[i].source_addr_len = sl;
|
||||||
results[i].got_source_addr = true;
|
results[i].got_source_addr = true;
|
||||||
|
|
||||||
if (q->ai_family == AF_INET6 && in6ai != NULL)
|
if (in6ai != NULL)
|
||||||
{
|
{
|
||||||
/* See whether the source address is on the list of
|
/* See whether the source address is on the list of
|
||||||
deprecated or temporary addresses. */
|
deprecated or temporary addresses. */
|
||||||
struct in6addrinfo tmp;
|
struct in6addrinfo tmp;
|
||||||
|
|
||||||
|
if (q->ai_family == AF_INET && af == AF_INET)
|
||||||
|
{
|
||||||
|
struct sockaddr_in *sinp
|
||||||
|
= (struct sockaddr_in *) &results[i].source_addr;
|
||||||
|
tmp.addr[0] = 0;
|
||||||
|
tmp.addr[1] = 0;
|
||||||
|
tmp.addr[2] = htonl (0xffff);
|
||||||
|
tmp.addr[3] = sinp->sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
struct sockaddr_in6 *sin6p
|
struct sockaddr_in6 *sin6p
|
||||||
= (struct sockaddr_in6 *) &results[i].source_addr;
|
= (struct sockaddr_in6 *) &results[i].source_addr;
|
||||||
memcpy (tmp.addr, &sin6p->sin6_addr, IN6ADDRSZ);
|
memcpy (tmp.addr, &sin6p->sin6_addr, IN6ADDRSZ);
|
||||||
|
}
|
||||||
|
|
||||||
struct in6addrinfo *found
|
struct in6addrinfo *found
|
||||||
= bsearch (&tmp, in6ai, in6ailen, sizeof (*in6ai),
|
= bsearch (&tmp, in6ai, in6ailen, sizeof (*in6ai),
|
||||||
in6aicmp);
|
in6aicmp);
|
||||||
if (found != NULL)
|
if (found != NULL)
|
||||||
|
{
|
||||||
results[i].source_addr_flags = found->flags;
|
results[i].source_addr_flags = found->flags;
|
||||||
|
results[i].prefixlen = found->prefixlen;
|
||||||
}
|
}
|
||||||
else if (q->ai_family == AF_INET && af == AF_INET6)
|
}
|
||||||
|
|
||||||
|
if (q->ai_family == AF_INET && af == AF_INET6)
|
||||||
{
|
{
|
||||||
/* We have to convert the address. The socket is
|
/* We have to convert the address. The socket is
|
||||||
IPv6 and the request is for IPv4. */
|
IPv6 and the request is for IPv4. */
|
||||||
@ -2029,10 +2039,17 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
struct sockaddr_in *sin
|
struct sockaddr_in *sin
|
||||||
= (struct sockaddr_in *) &results[i].source_addr;
|
= (struct sockaddr_in *) &results[i].source_addr;
|
||||||
assert (IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32));
|
assert (IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32));
|
||||||
|
sin->sin_family = AF_INET;
|
||||||
|
/* We do not have to initialize sin_port since this
|
||||||
|
fields has the same position and size in the IPv6
|
||||||
|
structure. */
|
||||||
|
assert (offsetof (struct sockaddr_in, sin_port)
|
||||||
|
== offsetof (struct sockaddr_in6, sin6_port));
|
||||||
|
assert (sizeof (sin->sin_port)
|
||||||
|
== sizeof (sin6->sin6_port));
|
||||||
memcpy (&sin->sin_addr,
|
memcpy (&sin->sin_addr,
|
||||||
&sin6->sin6_addr.s6_addr32[3], INADDRSZ);
|
&sin6->sin6_addr.s6_addr32[3], INADDRSZ);
|
||||||
results[i].source_addr_len = INADDRSZ;
|
results[i].source_addr_len = sizeof (struct sockaddr_in);
|
||||||
sin->sin_family = AF_INET;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (errno == EAFNOSUPPORT && af == AF_INET6
|
else if (errno == EAFNOSUPPORT && af == AF_INET6
|
||||||
|
@ -145,14 +145,12 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
|||||||
struct rtattr *rta = IFA_RTA (ifam);
|
struct rtattr *rta = IFA_RTA (ifam);
|
||||||
size_t len = nlmh->nlmsg_len - NLMSG_LENGTH (sizeof (*ifam));
|
size_t len = nlmh->nlmsg_len - NLMSG_LENGTH (sizeof (*ifam));
|
||||||
|
|
||||||
switch (ifam->ifa_family)
|
if (ifam->ifa_family != AF_INET
|
||||||
{
|
&& ifam->ifa_family != AF_INET6)
|
||||||
const void *local;
|
continue;
|
||||||
const void *address;
|
|
||||||
|
|
||||||
case AF_INET:
|
const void *local = NULL;
|
||||||
local = NULL;
|
const void *address = NULL;
|
||||||
address = NULL;
|
|
||||||
while (RTA_OK (rta, len))
|
while (RTA_OK (rta, len))
|
||||||
{
|
{
|
||||||
switch (rta->rta_type)
|
switch (rta->rta_type)
|
||||||
@ -163,7 +161,7 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
|||||||
|
|
||||||
case IFA_ADDRESS:
|
case IFA_ADDRESS:
|
||||||
address = RTA_DATA (rta);
|
address = RTA_DATA (rta);
|
||||||
goto out_v4;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rta = RTA_NEXT (rta, len);
|
rta = RTA_NEXT (rta, len);
|
||||||
@ -171,44 +169,21 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
|||||||
|
|
||||||
if (local != NULL)
|
if (local != NULL)
|
||||||
{
|
{
|
||||||
out_v4:
|
address = local;
|
||||||
if (*(const in_addr_t *) (address ?: local)
|
out:
|
||||||
|
if (ifam->ifa_family != AF_INET)
|
||||||
|
{
|
||||||
|
if (*(const in_addr_t *) address
|
||||||
!= htonl (INADDR_LOOPBACK))
|
!= htonl (INADDR_LOOPBACK))
|
||||||
*seen_ipv4 = true;
|
*seen_ipv4 = true;
|
||||||
}
|
}
|
||||||
break;
|
else
|
||||||
|
|
||||||
case AF_INET6:
|
|
||||||
local = NULL;
|
|
||||||
address = NULL;
|
|
||||||
while (RTA_OK (rta, len))
|
|
||||||
{
|
{
|
||||||
switch (rta->rta_type)
|
if (!IN6_IS_ADDR_LOOPBACK (address))
|
||||||
{
|
|
||||||
case IFA_LOCAL:
|
|
||||||
local = RTA_DATA (rta);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IFA_ADDRESS:
|
|
||||||
address = RTA_DATA (rta);
|
|
||||||
goto out_v6;
|
|
||||||
}
|
|
||||||
|
|
||||||
rta = RTA_NEXT (rta, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (local != NULL)
|
|
||||||
{
|
|
||||||
out_v6:
|
|
||||||
if (!IN6_IS_ADDR_LOOPBACK (address ?: local))
|
|
||||||
*seen_ipv6 = true;
|
*seen_ipv6 = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ifam->ifa_flags & (IFA_F_DEPRECATED
|
|
||||||
| IFA_F_TEMPORARY
|
|
||||||
| IFA_F_HOMEADDRESS
|
|
||||||
| IFA_F_OPTIMISTIC))
|
|
||||||
{
|
|
||||||
struct in6ailist *newp = alloca (sizeof (*newp));
|
struct in6ailist *newp = alloca (sizeof (*newp));
|
||||||
newp->info.flags = (((ifam->ifa_flags
|
newp->info.flags = (((ifam->ifa_flags
|
||||||
& (IFA_F_DEPRECATED
|
& (IFA_F_DEPRECATED
|
||||||
@ -220,18 +195,20 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
|||||||
| ((ifam->ifa_flags
|
| ((ifam->ifa_flags
|
||||||
& IFA_F_HOMEADDRESS)
|
& IFA_F_HOMEADDRESS)
|
||||||
? in6ai_homeaddress : 0));
|
? in6ai_homeaddress : 0));
|
||||||
memcpy (newp->info.addr, address ?: local,
|
newp->info.prefixlen = ifam->ifa_prefixlen;
|
||||||
sizeof (newp->info.addr));
|
if (ifam->ifa_family == AF_INET)
|
||||||
|
{
|
||||||
|
newp->info.addr[0] = 0;
|
||||||
|
newp->info.addr[1] = 0;
|
||||||
|
newp->info.addr[2] = htonl (0xffff);
|
||||||
|
newp->info.addr[3] = *(const in_addr_t *) address;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (newp->info.addr, address, sizeof (newp->info.addr));
|
||||||
newp->next = in6ailist;
|
newp->next = in6ailist;
|
||||||
in6ailist = newp;
|
in6ailist = newp;
|
||||||
++in6ailistlen;
|
++in6ailistlen;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Ignore. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (nlmh->nlmsg_type == NLMSG_DONE)
|
else if (nlmh->nlmsg_type == NLMSG_DONE)
|
||||||
/* We found the end, leave the loop. */
|
/* We found the end, leave the loop. */
|
||||||
done = true;
|
done = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user