source: trunk/libs/newlib/src/newlib/libc/sys/linux/net/check_pf.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 4.8 KB
Line 
1/* Determine protocol families for which interfaces exist.  Linux version.
2   Copyright (C) 2003 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, write to the Free
17   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18   02111-1307 USA.  */
19
20#include <errno.h>
21#include <stdint.h>
22#include <ifaddrs.h>
23#include <netdb.h>
24#include <string.h>
25#include <time.h>
26#include <unistd.h>
27#include <sys/socket.h>
28
29#include <asm/types.h>
30#include <linux/netlink.h>
31#include <linux/rtnetlink.h>
32
33#include <stdbool.h>
34#include <sys/uio.h>
35
36#include "config.h"
37#include "local.h"
38
39#define __ASSUME_NETLINK_SUPPORT 1
40
41static int
42make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
43{
44  struct
45  {
46    struct nlmsghdr nlh;
47    struct rtgenmsg g;
48  } req;
49  struct sockaddr_nl nladdr;
50
51  req.nlh.nlmsg_len = sizeof (req);
52  req.nlh.nlmsg_type = RTM_GETADDR;
53  req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
54  req.nlh.nlmsg_pid = 0;
55  req.nlh.nlmsg_seq = time (NULL);
56  req.g.rtgen_family = AF_UNSPEC;
57
58  memset (&nladdr, '\0', sizeof (nladdr));
59  nladdr.nl_family = AF_NETLINK;
60
61  if (TEMP_FAILURE_RETRY (sendto (fd, (void *) &req, sizeof (req), 0,
62                                    (struct sockaddr *) &nladdr,
63                                    sizeof (nladdr))) < 0)
64    return -1;
65
66  *seen_ipv4 = false;
67  *seen_ipv6 = false;
68
69  bool done = false;
70  char buf[4096];
71  struct iovec iov = { buf, sizeof (buf) };
72
73  do
74    {
75      struct msghdr msg =
76        {
77          (void *) &nladdr, sizeof (nladdr),
78          &iov, 1,
79          NULL, 0,
80          0
81        };
82
83      ssize_t read_len = TEMP_FAILURE_RETRY (recvmsg (fd, &msg, 0));
84      if (read_len < 0)
85        return -1;
86
87      if (msg.msg_flags & MSG_TRUNC)
88        return -1;
89
90      struct nlmsghdr *nlmh;
91      for (nlmh = (struct nlmsghdr *) buf;
92           NLMSG_OK (nlmh, (size_t) read_len);
93           nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, read_len))
94        {
95          if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != pid
96              || nlmh->nlmsg_seq != req.nlh.nlmsg_seq)
97            continue;
98
99          if (nlmh->nlmsg_type == RTM_NEWADDR)
100            {
101              struct ifaddrmsg *ifam = (struct ifaddrmsg *) NLMSG_DATA (nlmh);
102
103              switch (ifam->ifa_family)
104                {
105                case AF_INET:
106                  *seen_ipv4 = true;
107                  break;
108                case AF_INET6:
109                  *seen_ipv6 = true;
110                  break;
111                default:
112                  /* Ignore.  */
113                  break;
114                }
115            }
116          else if (nlmh->nlmsg_type == NLMSG_DONE)
117            /* We found the end, leave the loop.  */
118            done = true;
119          else ;
120        }
121    }
122  while (! done);
123
124  close (fd);
125
126  return 0;
127}
128
129
130/* We don't know if we have NETLINK support compiled in in our
131   Kernel.  */
132#if __ASSUME_NETLINK_SUPPORT == 0
133/* Define in ifaddrs.h.  */
134extern int __no_netlink_support attribute_hidden;
135#else
136# define __no_netlink_support 0
137#endif
138
139
140void
141attribute_hidden
142__check_pf (bool *seen_ipv4, bool *seen_ipv6)
143{
144  if (! __no_netlink_support)
145    {
146      int fd = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
147
148      struct sockaddr_nl nladdr;
149      memset (&nladdr, '\0', sizeof (nladdr));
150      nladdr.nl_family = AF_NETLINK;
151
152      socklen_t addr_len = sizeof (nladdr);
153
154      if (fd >= 0
155          && bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) == 0
156          && getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) == 0
157          && make_request (fd, nladdr.nl_pid, seen_ipv4, seen_ipv6) == 0)
158        /* It worked.  */
159        return;
160
161      if (fd >= 0)
162        close (fd);
163
164#if __ASSUME_NETLINK_SUPPORT == 0
165      /* Remember that there is no netlink support.  */
166      __no_netlink_support = 1;
167#else
168      /* We cannot determine what interfaces are available.  Be
169         pessimistic.  */
170      *seen_ipv4 = true;
171      *seen_ipv6 = true;
172#endif
173    }
174
175#if __ASSUME_NETLINK_SUPPORT == 0
176  /* No netlink.  Get the interface list via getifaddrs.  */
177  struct ifaddrs *ifa = NULL;
178  if (getifaddrs (&ifa) != 0)
179    {
180      /* We cannot determine what interfaces are available.  Be
181         pessimistic.  */
182      *seen_ipv4 = true;
183      *seen_ipv6 = true;
184      return;
185    }
186
187  *seen_ipv4 = false;
188  *seen_ipv6 = false;
189
190  struct ifaddrs *runp;
191  for (runp = ifa; runp != NULL; runp = runp->ifa_next)
192    if (runp->ifa_addr->sa_family == PF_INET)
193      *seen_ipv4 = true;
194    else if (runp->ifa_addr->sa_family == PF_INET6)
195      *seen_ipv6 = true;
196
197  (void) freeifaddrs (ifa);
198#endif
199}
Note: See TracBrowser for help on using the repository browser.