1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-28 00:21:52 +03:00
This commit is contained in:
Jakub Jelinek
2007-07-12 18:26:36 +00:00
parent 7d58530341
commit 0ecb606cb6
6215 changed files with 494638 additions and 305010 deletions

View File

@ -1,5 +1,5 @@
/* Determine protocol families for which interfaces exist. Linux version.
Copyright (C) 2003 Free Software Foundation, Inc.
Copyright (C) 2003, 2006, 2007 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
@ -17,9 +17,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <assert.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
@ -29,16 +31,30 @@
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "kernel-features.h"
#include <not-cancel.h>
#include <kernel-features.h>
#ifndef IFA_F_TEMPORARY
# define IFA_F_TEMPORARY IFA_F_SECONDARY
#endif
#ifndef IFA_F_HOMEADDRESS
# define IFA_F_HOMEADDRESS 0
#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
struct req
{
struct nlmsghdr nlh;
struct rtgenmsg g;
/* struct rtgenmsg consists of a single byte. This means there
are three bytes of padding included in the REQ definition.
We make them explicit here. */
char pad[3];
} req;
struct sockaddr_nl nladdr;
@ -49,20 +65,50 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
req.nlh.nlmsg_seq = time (NULL);
req.g.rtgen_family = AF_UNSPEC;
assert (sizeof (req) - offsetof (struct req, pad) == 3);
memset (req.pad, '\0', sizeof (req.pad));
memset (&nladdr, '\0', sizeof (nladdr));
nladdr.nl_family = AF_NETLINK;
#ifdef PAGE_SIZE
/* Help the compiler optimize out the malloc call if PAGE_SIZE
is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
const size_t buf_size = PAGE_SIZE;
#else
const size_t buf_size = __getpagesize ();
#endif
bool use_malloc = false;
char *buf;
if (__libc_use_alloca (buf_size))
buf = alloca (buf_size);
else
{
buf = malloc (buf_size);
if (buf != NULL)
use_malloc = true;
else
goto out_fail;
}
struct iovec iov = { buf, buf_size };
if (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0,
(struct sockaddr *) &nladdr,
sizeof (nladdr))) < 0)
return -1;
goto out_fail;
*seen_ipv4 = false;
*seen_ipv6 = false;
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
{
@ -76,10 +122,10 @@ make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
if (read_len < 0)
return -1;
goto out_fail;
if (msg.msg_flags & MSG_TRUNC)
return -1;
goto out_fail;
struct nlmsghdr *nlmh;
for (nlmh = (struct nlmsghdr *) buf;
@ -101,6 +147,47 @@ 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
| IFA_F_HOMEADDRESS))
{
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 (rta);
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)
| ((ifam->ifa_flags
& IFA_F_HOMEADDRESS)
? in6ai_homeaddress : 0));
memcpy (newp->info.addr, address ?: local,
sizeof (newp->info.addr));
newp->next = in6ailist;
in6ailist = newp;
++in6ailistlen;
}
break;
default:
/* Ignore. */
@ -110,14 +197,36 @@ 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)
goto out_fail;
*in6ailen = in6ailistlen;
do
{
(*in6ai)[--in6ailistlen] = in6ailist->info;
in6ailist = in6ailist->next;
}
while (in6ailist != NULL);
}
if (use_malloc)
free (buf);
return 0;
out_fail:
if (use_malloc)
free (buf);
return -1;
}
@ -133,8 +242,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 +261,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 +292,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)