mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-29 00:01:12 +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>
|
2006-04-15 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
* sysdeps/posix/getaddrinfo.c: Fix precedence for IP V4-to-V6
|
* 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.
|
Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
|
||||||
See the end for copying conditions.
|
See the end for copying conditions.
|
||||||
|
|
||||||
Please send GNU C library bug reports via <http://sources.redhat.com/bugzilla/>
|
Please send GNU C library bug reports via <http://sources.redhat.com/bugzilla/>
|
||||||
using `glibc' in the "product" field.
|
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
|
Version 2.4
|
||||||
|
|
||||||
|
@ -5,6 +5,17 @@
|
|||||||
libc_hidden_proto (getifaddrs)
|
libc_hidden_proto (getifaddrs)
|
||||||
libc_hidden_proto (freeifaddrs)
|
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 */
|
#endif /* ifaddrs.h */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Determine protocol families for which interfaces exist. Generic version.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -23,8 +23,14 @@
|
|||||||
|
|
||||||
void
|
void
|
||||||
attribute_hidden
|
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. */
|
/* Get the interface list via getifaddrs. */
|
||||||
struct ifaddrs *ifa = NULL;
|
struct ifaddrs *ifa = NULL;
|
||||||
if (getifaddrs (&ifa) != 0)
|
if (getifaddrs (&ifa) != 0)
|
||||||
|
@ -68,7 +68,7 @@ extern int __idna_to_unicode_lzlz (const char *input, char **output,
|
|||||||
#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
|
#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
|
||||||
|
|
||||||
#ifndef UNIX_PATH_MAX
|
#ifndef UNIX_PATH_MAX
|
||||||
#define UNIX_PATH_MAX 108
|
# define UNIX_PATH_MAX 108
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct gaih_service
|
struct gaih_service
|
||||||
@ -177,9 +177,9 @@ gaih_local (const char *name, const struct gaih_service *service,
|
|||||||
if (! tp->name[0])
|
if (! tp->name[0])
|
||||||
{
|
{
|
||||||
if (req->ai_socktype)
|
if (req->ai_socktype)
|
||||||
return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
|
return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
|
||||||
else
|
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 */
|
#endif /* 0 */
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
|
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;
|
struct servent *s;
|
||||||
size_t tmpbuflen = 1024;
|
size_t tmpbuflen = 1024;
|
||||||
@ -362,6 +363,7 @@ typedef enum nss_status (*nss_getcanonname_r)
|
|||||||
int *errnop, int *h_errnop);
|
int *errnop, int *h_errnop);
|
||||||
extern service_user *__nss_hosts_database attribute_hidden;
|
extern service_user *__nss_hosts_database attribute_hidden;
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gaih_inet (const char *name, const struct gaih_service *service,
|
gaih_inet (const char *name, const struct gaih_service *service,
|
||||||
const struct addrinfo *req, struct addrinfo **pai,
|
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 (! tp->name[0])
|
||||||
{
|
{
|
||||||
if (req->ai_socktype)
|
if (req->ai_socktype)
|
||||||
return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
|
return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
|
||||||
else
|
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 (service != NULL)
|
||||||
{
|
{
|
||||||
if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
|
if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
|
||||||
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
|
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
|
||||||
|
|
||||||
if (service->num < 0)
|
if (service->num < 0)
|
||||||
{
|
{
|
||||||
@ -443,7 +445,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|||||||
pst = &(newp->next);
|
pst = &(newp->next);
|
||||||
}
|
}
|
||||||
if (st == (struct gaih_servtuple *) &nullserv)
|
if (st == (struct gaih_servtuple *) &nullserv)
|
||||||
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
|
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -684,7 +686,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|||||||
}
|
}
|
||||||
/* We made requests but they turned out no data.
|
/* We made requests but they turned out no data.
|
||||||
The name is known, though. */
|
The name is known, though. */
|
||||||
return (GAIH_OKIFUNSPEC | -EAI_NODATA);
|
return GAIH_OKIFUNSPEC | -EAI_NODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
goto process_list;
|
goto process_list;
|
||||||
@ -751,7 +753,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|||||||
free (air);
|
free (air);
|
||||||
|
|
||||||
if (at->family == AF_UNSPEC)
|
if (at->family == AF_UNSPEC)
|
||||||
return (GAIH_OKIFUNSPEC | -EAI_NONAME);
|
return GAIH_OKIFUNSPEC | -EAI_NONAME;
|
||||||
|
|
||||||
goto process_list;
|
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
|
/* We made requests but they turned out no data. The name
|
||||||
is known, though. */
|
is known, though. */
|
||||||
return (GAIH_OKIFUNSPEC | -EAI_NODATA);
|
return GAIH_OKIFUNSPEC | -EAI_NODATA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
process_list:
|
process_list:
|
||||||
if (at->family == AF_UNSPEC)
|
if (at->family == AF_UNSPEC)
|
||||||
return (GAIH_OKIFUNSPEC | -EAI_NONAME);
|
return GAIH_OKIFUNSPEC | -EAI_NONAME;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1109,6 +1111,7 @@ struct sort_result
|
|||||||
struct sockaddr_storage source_addr;
|
struct sockaddr_storage source_addr;
|
||||||
uint8_t source_addr_len;
|
uint8_t source_addr_len;
|
||||||
bool got_source_addr;
|
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.
|
/* Rule 3: Avoid deprecated addresses. */
|
||||||
That's something only the kernel could decide. */
|
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.
|
/* Rule 4: Prefer home addresses.
|
||||||
Another thing only the kernel can decide. */
|
Another thing only the kernel can decide. */
|
||||||
@ -1367,8 +1378,18 @@ rfc3484_sort (const void *p1, const void *p2)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
||||||
/* Rule 7: Prefer native transport.
|
/* Rule 7: Prefer native transport. */
|
||||||
XXX How to recognize tunnels? */
|
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. */
|
/* 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
|
int
|
||||||
getaddrinfo (const char *name, const char *service,
|
getaddrinfo (const char *name, const char *service,
|
||||||
const struct addrinfo *hints, struct addrinfo **pai)
|
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)
|
if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
|
||||||
return EAI_BADFLAGS;
|
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)
|
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. */
|
/* Now make a decision on what we return, if anything. */
|
||||||
if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
|
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)
|
else if ((hints->ai_family == PF_INET && ! seen_ipv4)
|
||||||
|| (hints->ai_family == PF_INET6 && ! seen_ipv6))
|
|| (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])
|
if (service && service[0])
|
||||||
@ -1520,7 +1562,10 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
if (*c != '\0')
|
if (*c != '\0')
|
||||||
{
|
{
|
||||||
if (hints->ai_flags & AI_NUMERICSERV)
|
if (hints->ai_flags & AI_NUMERICSERV)
|
||||||
return EAI_NONAME;
|
{
|
||||||
|
free (in6ai);
|
||||||
|
return EAI_NONAME;
|
||||||
|
}
|
||||||
|
|
||||||
gaih_service.num = -1;
|
gaih_service.num = -1;
|
||||||
}
|
}
|
||||||
@ -1559,6 +1604,7 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo (p);
|
freeaddrinfo (p);
|
||||||
|
free (in6ai);
|
||||||
|
|
||||||
return -(i & GAIH_EAI);
|
return -(i & GAIH_EAI);
|
||||||
}
|
}
|
||||||
@ -1574,7 +1620,10 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (j == 0)
|
if (j == 0)
|
||||||
return EAI_FAMILY;
|
{
|
||||||
|
free (in6ai);
|
||||||
|
return EAI_FAMILY;
|
||||||
|
}
|
||||||
|
|
||||||
if (naddrs > 1)
|
if (naddrs > 1)
|
||||||
{
|
{
|
||||||
@ -1584,6 +1633,11 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
struct addrinfo *last = NULL;
|
struct addrinfo *last = NULL;
|
||||||
char *canonname = 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)
|
for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
|
||||||
{
|
{
|
||||||
results[i].dest_addr = q;
|
results[i].dest_addr = q;
|
||||||
@ -1598,9 +1652,12 @@ getaddrinfo (const char *name, const char *service,
|
|||||||
results[i - 1].source_addr_len);
|
results[i - 1].source_addr_len);
|
||||||
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;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
results[i].source_addr_flags = 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
|
||||||
cannot determine the source address remember this
|
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].source_addr_len = sl;
|
||||||
results[i].got_source_addr = true;
|
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
|
else
|
||||||
/* Just make sure that if we have to process the same
|
/* 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;
|
p->ai_canonname = canonname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free (in6ai);
|
||||||
|
|
||||||
if (p)
|
if (p)
|
||||||
{
|
{
|
||||||
*pai = p;
|
*pai = p;
|
||||||
|
@ -29,11 +29,18 @@
|
|||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
#include <not-cancel.h>
|
||||||
#include <kernel-features.h>
|
#include <kernel-features.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef IFA_F_TEMPORARY
|
||||||
|
# define IFA_F_TEMPORARY IFA_F_SECONDARY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int
|
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
|
struct
|
||||||
{
|
{
|
||||||
@ -63,6 +70,12 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
|
|||||||
bool done = false;
|
bool done = false;
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
struct iovec iov = { buf, sizeof (buf) };
|
struct iovec iov = { buf, sizeof (buf) };
|
||||||
|
struct in6ailist
|
||||||
|
{
|
||||||
|
struct in6addrinfo info;
|
||||||
|
struct in6ailist *next;
|
||||||
|
} *in6ailist = NULL;
|
||||||
|
size_t in6ailistlen = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -101,6 +114,42 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
|
|||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
*seen_ipv6 = true;
|
*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;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Ignore. */
|
/* 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)
|
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;
|
||||||
else ;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (! done);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -133,8 +197,12 @@ extern int __no_netlink_support attribute_hidden;
|
|||||||
|
|
||||||
void
|
void
|
||||||
attribute_hidden
|
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)
|
if (! __no_netlink_support)
|
||||||
{
|
{
|
||||||
int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||||
@ -148,7 +216,8 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6)
|
|||||||
if (fd >= 0
|
if (fd >= 0
|
||||||
&& __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) == 0
|
&& __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) == 0
|
||||||
&& __getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) == 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. */
|
/* It worked. */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -178,9 +247,6 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*seen_ipv4 = false;
|
|
||||||
*seen_ipv6 = false;
|
|
||||||
|
|
||||||
struct ifaddrs *runp;
|
struct ifaddrs *runp;
|
||||||
for (runp = ifa; runp != NULL; runp = runp->ifa_next)
|
for (runp = ifa; runp != NULL; runp = runp->ifa_next)
|
||||||
if (runp->ifa_addr->sa_family == PF_INET)
|
if (runp->ifa_addr->sa_family == PF_INET)
|
||||||
|
Loading…
Reference in New Issue
Block a user