mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
* include/ifaddrs.h: Define struct in6addrinfo.
Add two more parameters to __check_pf. * sysdeps/unix/sysv/linux/check_pf.c: When using the netlink interface, determine whether IPv6 addresses are deprecated or temporary. Create array of those addresses. * inet/check_pf.c: Always tell caller there are no depracated and temporary addresses. * sysdeps/posix/getaddrinfo.c: Pretty printing. (struct sort_result): Add source_addr_flags field. (rfc3484_sort): Implement rule 3 and 7. (in6aicmp): New function. (getaddrinfo): Call __check_pf also when we need info about IPv6 source addresses. When creating array for sorting addresses, look up deprecated and temporary addresses returned by __check_pf and add flag if necessary.
This commit is contained in:
parent
a238728234
commit
3af48b5b31
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
||||
2006-04-16 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* include/ifaddrs.h: Define struct in6addrinfo.
|
||||
Add two more parameters to __check_pf.
|
||||
* sysdeps/unix/sysv/linux/check_pf.c: When using the netlink
|
||||
interface, determine whether IPv6 addresses are deprecated or
|
||||
temporary. Create array of those addresses.
|
||||
* inet/check_pf.c: Always tell caller there are no depracated
|
||||
and temporary addresses.
|
||||
* sysdeps/posix/getaddrinfo.c: Pretty printing.
|
||||
(struct sort_result): Add source_addr_flags field.
|
||||
(rfc3484_sort): Implement rule 3 and 7.
|
||||
(in6aicmp): New function.
|
||||
(getaddrinfo): Call __check_pf also when we need info about IPv6
|
||||
source addresses. When creating array for sorting addresses,
|
||||
look up deprecated and temporary addresses returned by __check_pf
|
||||
and add flag if necessary.
|
||||
|
||||
2006-04-15 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/posix/getaddrinfo.c: Fix precedence for IP V4-to-V6
|
||||
|
10
NEWS
10
NEWS
@ -1,9 +1,17 @@
|
||||
GNU C Library NEWS -- history of user-visible changes. 2006-03-01
|
||||
GNU C Library NEWS -- history of user-visible changes. 2006-04-16
|
||||
Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
|
||||
See the end for copying conditions.
|
||||
|
||||
Please send GNU C library bug reports via <http://sources.redhat.com/bugzilla/>
|
||||
using `glibc' in the "product" field.
|
||||
|
||||
Version 2.5
|
||||
|
||||
* For Linux, the sorting of addresses returned by getaddrinfo now also
|
||||
handles rules 3 and 7 from RFC 3484. Implemented by Ulrich Drepper.
|
||||
|
||||
* New Linux interfaces: splice, tee, sync_file_range.
|
||||
|
||||
|
||||
Version 2.4
|
||||
|
||||
|
@ -5,6 +5,17 @@
|
||||
libc_hidden_proto (getifaddrs)
|
||||
libc_hidden_proto (freeifaddrs)
|
||||
|
||||
extern void __check_pf (bool *seen_ipv4, bool *seen_ipv6) attribute_hidden;
|
||||
struct in6addrinfo
|
||||
{
|
||||
enum {
|
||||
in6ai_deprecated = 1,
|
||||
in6ai_temporary = 2
|
||||
} flags;
|
||||
uint32_t addr[4];
|
||||
};
|
||||
|
||||
extern void __check_pf (bool *seen_ipv4, bool *seen_ipv6,
|
||||
struct in6addrinfo **in6ai, size_t *in6ailen)
|
||||
attribute_hidden;
|
||||
|
||||
#endif /* ifaddrs.h */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Determine protocol families for which interfaces exist. Generic version.
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 2003, 2006 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@ -23,8 +23,14 @@
|
||||
|
||||
void
|
||||
attribute_hidden
|
||||
__check_pf (bool *seen_ipv4, bool *seen_ipv6)
|
||||
__check_pf (bool *seen_ipv4, bool *seen_ipv6,
|
||||
struct in6addrinfo **in6ai, size_t *in6ailen)
|
||||
{
|
||||
/* By default we have no way to determine information about
|
||||
deprecated and temporary addresses. */
|
||||
*in6ai = NULL;
|
||||
*in6ailen = 0;
|
||||
|
||||
/* Get the interface list via getifaddrs. */
|
||||
struct ifaddrs *ifa = NULL;
|
||||
if (getifaddrs (&ifa) != 0)
|
||||
|
@ -68,7 +68,7 @@ extern int __idna_to_unicode_lzlz (const char *input, char **output,
|
||||
#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
|
||||
|
||||
#ifndef UNIX_PATH_MAX
|
||||
#define UNIX_PATH_MAX 108
|
||||
# define UNIX_PATH_MAX 108
|
||||
#endif
|
||||
|
||||
struct gaih_service
|
||||
@ -177,9 +177,9 @@ gaih_local (const char *name, const struct gaih_service *service,
|
||||
if (! tp->name[0])
|
||||
{
|
||||
if (req->ai_socktype)
|
||||
return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
|
||||
return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
|
||||
else
|
||||
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
|
||||
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,9 +249,10 @@ gaih_local (const char *name, const struct gaih_service *service,
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
static int
|
||||
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
|
||||
const struct addrinfo *req, struct gaih_servtuple *st)
|
||||
const struct addrinfo *req, struct gaih_servtuple *st)
|
||||
{
|
||||
struct servent *s;
|
||||
size_t tmpbuflen = 1024;
|
||||
@ -362,6 +363,7 @@ typedef enum nss_status (*nss_getcanonname_r)
|
||||
int *errnop, int *h_errnop);
|
||||
extern service_user *__nss_hosts_database attribute_hidden;
|
||||
|
||||
|
||||
static int
|
||||
gaih_inet (const char *name, const struct gaih_service *service,
|
||||
const struct addrinfo *req, struct addrinfo **pai,
|
||||
@ -389,9 +391,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
||||
if (! tp->name[0])
|
||||
{
|
||||
if (req->ai_socktype)
|
||||
return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
|
||||
return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
|
||||
else
|
||||
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
|
||||
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,7 +401,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
||||
if (service != NULL)
|
||||
{
|
||||
if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
|
||||
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
|
||||
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
|
||||
|
||||
if (service->num < 0)
|
||||
{
|
||||
@ -443,7 +445,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
||||
pst = &(newp->next);
|
||||
}
|
||||
if (st == (struct gaih_servtuple *) &nullserv)
|
||||
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
|
||||
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -684,7 +686,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
||||
}
|
||||
/* We made requests but they turned out no data.
|
||||
The name is known, though. */
|
||||
return (GAIH_OKIFUNSPEC | -EAI_NODATA);
|
||||
return GAIH_OKIFUNSPEC | -EAI_NODATA;
|
||||
}
|
||||
|
||||
goto process_list;
|
||||
@ -751,7 +753,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
||||
free (air);
|
||||
|
||||
if (at->family == AF_UNSPEC)
|
||||
return (GAIH_OKIFUNSPEC | -EAI_NONAME);
|
||||
return GAIH_OKIFUNSPEC | -EAI_NONAME;
|
||||
|
||||
goto process_list;
|
||||
}
|
||||
@ -893,13 +895,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
||||
|
||||
/* We made requests but they turned out no data. The name
|
||||
is known, though. */
|
||||
return (GAIH_OKIFUNSPEC | -EAI_NODATA);
|
||||
return GAIH_OKIFUNSPEC | -EAI_NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
process_list:
|
||||
if (at->family == AF_UNSPEC)
|
||||
return (GAIH_OKIFUNSPEC | -EAI_NONAME);
|
||||
return GAIH_OKIFUNSPEC | -EAI_NONAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1109,6 +1111,7 @@ struct sort_result
|
||||
struct sockaddr_storage source_addr;
|
||||
uint8_t source_addr_len;
|
||||
bool got_source_addr;
|
||||
uint8_t source_addr_flags;
|
||||
};
|
||||
|
||||
|
||||
@ -1331,8 +1334,16 @@ rfc3484_sort (const void *p1, const void *p2)
|
||||
}
|
||||
|
||||
|
||||
/* Rule 3: Avoid deprecated addresses.
|
||||
That's something only the kernel could decide. */
|
||||
/* Rule 3: Avoid deprecated addresses. */
|
||||
if (a1->got_source_addr)
|
||||
{
|
||||
if (!(a1->source_addr_flags & in6ai_deprecated)
|
||||
&& (a2->source_addr_flags & in6ai_deprecated))
|
||||
return -1;
|
||||
if ((a1->source_addr_flags & in6ai_deprecated)
|
||||
&& !(a2->source_addr_flags & in6ai_deprecated))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Rule 4: Prefer home addresses.
|
||||
Another thing only the kernel can decide. */
|
||||
@ -1367,8 +1378,18 @@ rfc3484_sort (const void *p1, const void *p2)
|
||||
return 1;
|
||||
|
||||
|
||||
/* Rule 7: Prefer native transport.
|
||||
XXX How to recognize tunnels? */
|
||||
/* Rule 7: Prefer native transport. */
|
||||
if (a1->got_source_addr)
|
||||
{
|
||||
if (!(a1->source_addr_flags & in6ai_temporary)
|
||||
&& (a1->source_addr_flags & in6ai_temporary))
|
||||
return -1;
|
||||
if ((a1->source_addr_flags & in6ai_temporary)
|
||||
&& !(a1->source_addr_flags & in6ai_temporary))
|
||||
return -1;
|
||||
|
||||
/* XXX Do we need to check anything beside temporary addresses? */
|
||||
}
|
||||
|
||||
|
||||
/* Rule 8: Prefer smaller scope. */
|
||||
@ -1449,6 +1470,16 @@ rfc3484_sort (const void *p1, const void *p2)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
in6aicmp (const void *p1, const void *p2)
|
||||
{
|
||||
struct in6addrinfo *a1 = (struct in6addrinfo *) p1;
|
||||
struct in6addrinfo *a2 = (struct in6addrinfo *) p2;
|
||||
|
||||
return memcmp (a1->addr, a2->addr, sizeof (a1->addr));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
getaddrinfo (const char *name, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **pai)
|
||||
@ -1485,15 +1516,23 @@ getaddrinfo (const char *name, const char *service,
|
||||
if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
|
||||
return EAI_BADFLAGS;
|
||||
|
||||
struct in6addrinfo *in6ai;
|
||||
size_t in6ailen;
|
||||
bool seen_ipv4 = false;
|
||||
bool seen_ipv6 = false;
|
||||
/* We might need information about what kind of interfaces are available.
|
||||
But even if AI_ADDRCONFIG is not used, if the user requested IPv6
|
||||
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
|
||||
any time. */
|
||||
__check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
|
||||
|
||||
if (hints->ai_flags & AI_ADDRCONFIG)
|
||||
{
|
||||
/* Determine whether we have IPv4 or IPv6 interfaces or both.
|
||||
We cannot cache the results since new interfaces could be
|
||||
added at any time. */
|
||||
bool seen_ipv4;
|
||||
bool seen_ipv6;
|
||||
__check_pf (&seen_ipv4, &seen_ipv6);
|
||||
|
||||
/* Now make a decision on what we return, if anything. */
|
||||
if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
|
||||
{
|
||||
@ -1508,8 +1547,11 @@ getaddrinfo (const char *name, const char *service,
|
||||
}
|
||||
else if ((hints->ai_family == PF_INET && ! seen_ipv4)
|
||||
|| (hints->ai_family == PF_INET6 && ! seen_ipv6))
|
||||
/* We cannot possibly return a valid answer. */
|
||||
return EAI_NONAME;
|
||||
{
|
||||
/* We cannot possibly return a valid answer. */
|
||||
free (in6ai);
|
||||
return EAI_NONAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (service && service[0])
|
||||
@ -1520,7 +1562,10 @@ getaddrinfo (const char *name, const char *service,
|
||||
if (*c != '\0')
|
||||
{
|
||||
if (hints->ai_flags & AI_NUMERICSERV)
|
||||
return EAI_NONAME;
|
||||
{
|
||||
free (in6ai);
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
gaih_service.num = -1;
|
||||
}
|
||||
@ -1559,6 +1604,7 @@ getaddrinfo (const char *name, const char *service,
|
||||
}
|
||||
|
||||
freeaddrinfo (p);
|
||||
free (in6ai);
|
||||
|
||||
return -(i & GAIH_EAI);
|
||||
}
|
||||
@ -1574,7 +1620,10 @@ getaddrinfo (const char *name, const char *service,
|
||||
}
|
||||
|
||||
if (j == 0)
|
||||
return EAI_FAMILY;
|
||||
{
|
||||
free (in6ai);
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if (naddrs > 1)
|
||||
{
|
||||
@ -1584,6 +1633,11 @@ getaddrinfo (const char *name, const char *service,
|
||||
struct addrinfo *last = NULL;
|
||||
char *canonname = NULL;
|
||||
|
||||
/* If we have information about deprecated and temporary address
|
||||
sort the array now. */
|
||||
if (in6ai != NULL)
|
||||
qsort (in6ai, in6ailen, sizeof (*in6ai), in6aicmp);
|
||||
|
||||
for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
|
||||
{
|
||||
results[i].dest_addr = q;
|
||||
@ -1598,9 +1652,12 @@ getaddrinfo (const char *name, const char *service,
|
||||
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].source_addr_flags = results[i - 1].source_addr_flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
results[i].source_addr_flags = 0;
|
||||
|
||||
/* We overwrite the type with SOCK_DGRAM since we do not
|
||||
want connect() to connect to the other side. If we
|
||||
cannot determine the source address remember this
|
||||
@ -1615,6 +1672,20 @@ getaddrinfo (const char *name, const char *service,
|
||||
{
|
||||
results[i].source_addr_len = sl;
|
||||
results[i].got_source_addr = true;
|
||||
|
||||
if (q->ai_family == PF_INET6 && in6ai != NULL)
|
||||
{
|
||||
/* See whether the address is the list of deprecated
|
||||
or temporary addresses. */
|
||||
struct in6addrinfo tmp;
|
||||
memcpy (tmp.addr, q->ai_addr, IN6ADDRSZ);
|
||||
|
||||
struct in6addrinfo *found
|
||||
= bsearch (&tmp, in6ai, in6ailen, sizeof (*in6ai),
|
||||
in6aicmp);
|
||||
if (found != NULL)
|
||||
results[i].source_addr_flags = found->flags;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Just make sure that if we have to process the same
|
||||
@ -1648,6 +1719,8 @@ getaddrinfo (const char *name, const char *service,
|
||||
p->ai_canonname = canonname;
|
||||
}
|
||||
|
||||
free (in6ai);
|
||||
|
||||
if (p)
|
||||
{
|
||||
*pai = p;
|
||||
|
@ -29,11 +29,18 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include <not-cancel.h>
|
||||
#include <kernel-features.h>
|
||||
|
||||
|
||||
#ifndef IFA_F_TEMPORARY
|
||||
# define IFA_F_TEMPORARY IFA_F_SECONDARY
|
||||
#endif
|
||||
|
||||
|
||||
static int
|
||||
make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
|
||||
make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
|
||||
struct in6addrinfo **in6ai, size_t *in6ailen)
|
||||
{
|
||||
struct
|
||||
{
|
||||
@ -63,6 +70,12 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
|
||||
bool done = false;
|
||||
char buf[4096];
|
||||
struct iovec iov = { buf, sizeof (buf) };
|
||||
struct in6ailist
|
||||
{
|
||||
struct in6addrinfo info;
|
||||
struct in6ailist *next;
|
||||
} *in6ailist = NULL;
|
||||
size_t in6ailistlen = 0;
|
||||
|
||||
do
|
||||
{
|
||||
@ -101,6 +114,42 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
|
||||
break;
|
||||
case AF_INET6:
|
||||
*seen_ipv6 = true;
|
||||
|
||||
if (ifam->ifa_flags & (IFA_F_DEPRECATED | IFA_F_TEMPORARY))
|
||||
{
|
||||
struct rtattr *rta = IFA_RTA (ifam);
|
||||
size_t len = (nlmh->nlmsg_len
|
||||
- NLMSG_LENGTH (sizeof (*ifam)));
|
||||
void *local = NULL;
|
||||
void *address = NULL;
|
||||
while (RTA_OK (rta, len))
|
||||
{
|
||||
switch (rta->rta_type)
|
||||
{
|
||||
case IFA_LOCAL:
|
||||
local = RTA_DATA (rta);
|
||||
break;
|
||||
|
||||
case IFA_ADDRESS:
|
||||
address = RTA_DATA (ta);
|
||||
break;
|
||||
}
|
||||
|
||||
rta = RTA_NEXT (rta, len);
|
||||
}
|
||||
|
||||
struct in6ailist *newp = alloca (sizeof (*newp));
|
||||
newp->info.flags = (((ifam->ifa_flags & IFA_F_DEPRECATED)
|
||||
? in6ai_deprecated : 0)
|
||||
| ((ifam->ifa_flags
|
||||
& IFA_F_TEMPORARY)
|
||||
? in6ai_temporary : 0));
|
||||
memcpy (newp->info.addr, address ?: local,
|
||||
sizeof (newp->info.addr));
|
||||
newp->next = in6ailist;
|
||||
in6ailsit = newp;
|
||||
++in6ailistlen;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Ignore. */
|
||||
@ -110,12 +159,27 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
|
||||
else if (nlmh->nlmsg_type == NLMSG_DONE)
|
||||
/* We found the end, leave the loop. */
|
||||
done = true;
|
||||
else ;
|
||||
}
|
||||
}
|
||||
while (! done);
|
||||
|
||||
__close (fd);
|
||||
close_not_cancel_no_status (fd);
|
||||
|
||||
if (in6ailist != NULL)
|
||||
{
|
||||
*in6ai = malloc (in6ailistlen * sizeof (**in6ai));
|
||||
if (*in6ai == NULL)
|
||||
return -1;
|
||||
|
||||
*in6ailen = in6ailistlen;
|
||||
|
||||
do
|
||||
{
|
||||
(*in6ai)[--in6ailistlen] = in6ailist->info;
|
||||
in6ailist = in6ailist->next;
|
||||
}
|
||||
while (in6ailist != NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -133,8 +197,12 @@ extern int __no_netlink_support attribute_hidden;
|
||||
|
||||
void
|
||||
attribute_hidden
|
||||
__check_pf (bool *seen_ipv4, bool *seen_ipv6)
|
||||
__check_pf (bool *seen_ipv4, bool *seen_ipv6,
|
||||
struct in6addrinfo **in6ai, size_t *in6ailen)
|
||||
{
|
||||
*in6ai = NULL;
|
||||
*in6ailen = 0;
|
||||
|
||||
if (! __no_netlink_support)
|
||||
{
|
||||
int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
@ -148,7 +216,8 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6)
|
||||
if (fd >= 0
|
||||
&& __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) == 0
|
||||
&& __getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) == 0
|
||||
&& make_request (fd, nladdr.nl_pid, seen_ipv4, seen_ipv6) == 0)
|
||||
&& make_request (fd, nladdr.nl_pid, seen_ipv4, seen_ipv6,
|
||||
in6ai, in6ailen) == 0)
|
||||
/* It worked. */
|
||||
return;
|
||||
|
||||
@ -178,9 +247,6 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6)
|
||||
return;
|
||||
}
|
||||
|
||||
*seen_ipv4 = false;
|
||||
*seen_ipv6 = false;
|
||||
|
||||
struct ifaddrs *runp;
|
||||
for (runp = ifa; runp != NULL; runp = runp->ifa_next)
|
||||
if (runp->ifa_addr->sa_family == PF_INET)
|
||||
|
Loading…
Reference in New Issue
Block a user