GNUnet  0.20.0
os_network.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2004, 2005, 2006, 2015 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 
20  */
31 #include "platform.h"
32 #include "gnunet_util_lib.h"
33 
34 
35 #define LOG(kind, ...) GNUNET_log_from (kind, "util-os-network", __VA_ARGS__)
36 #define LOG_STRERROR_FILE(kind, syscall, \
37  filename) GNUNET_log_from_strerror_file (kind, \
38  "util-os-network", \
39  syscall, \
40  filename)
41 
42 
43 #if ! (HAVE_GETIFADDRS && HAVE_FREEIFADDRS)
51 static int
53  void *proc_cls)
54 {
55  int i;
56  char line[1024];
57  char *replace;
58  const char *start;
59  char ifc[12];
60  char addrstr[128];
61  char bcstr[128];
62  char netmaskstr[128];
63  FILE *f;
64  int have_ifc;
65  struct sockaddr_in a4;
66  struct sockaddr_in6 a6;
67  struct in_addr v4;
68  struct in6_addr v6;
69  struct sockaddr_in bcaddr;
70  struct sockaddr_in netmask;
71  struct sockaddr_in6 netmask6;
72  struct sockaddr *pass_bcaddr;
73  struct sockaddr *pass_netmask;
74  int prefixlen;
75  static char *pcall;
76 
77  if (NULL == pcall)
78  {
79  const char *sbin_ifconfig;
80 
81 #ifdef IFCONFIG
82  if (0 == access (IFCONFIG, X_OK))
83  sbin_ifconfig = IFCONFIG;
84  else
85 #endif
86  if (0 == access ("/sbin/ifconfig", X_OK))
87  sbin_ifconfig = "/sbin/ifconfig";
88  else if (0 == access ("/usr/sbin/ifconfig", X_OK))
89  sbin_ifconfig = "/usr/sbin/ifconfig";
90  else
91  sbin_ifconfig = "ifconfig";
92  GNUNET_asprintf (&pcall,
93  "%s -a 2> /dev/null",
94  sbin_ifconfig);
95  }
96  f = popen (pcall, "r");
97  if (NULL == f)
98  {
100  "popen",
101  "ifconfig");
102 
103  return GNUNET_SYSERR;
104  }
105 
106  have_ifc = GNUNET_NO;
107  ifc[11] = '\0';
108  while (NULL != fgets (line, sizeof(line), f))
109  {
110  if (strlen (line) == 0)
111  {
112  have_ifc = GNUNET_NO;
113  continue;
114  }
115  if (! isspace (line[0]))
116  {
117  have_ifc = (1 == sscanf (line, "%11s", ifc)) ? GNUNET_YES : GNUNET_NO;
118  /* would end with ':' on OSX, fix it! */
119  if (ifc[strlen (ifc) - 1] == ':')
120  ifc[strlen (ifc) - 1] = '\0';
121  continue;
122  }
123  if (! have_ifc)
124  continue; /* strange input, hope for the best */
125 
126  /* make parsing of ipv6 addresses easier */
127  for (replace = line; *replace != '\0'; replace++)
128  {
129  if (*replace == '/')
130  *replace = ' ';
131  }
132  prefixlen = -1;
133 
134  start = line;
135  while (('\0' != *start) && (isspace (*start)))
136  start++;
137 
138  /* Zero-out stack allocated values */
139  memset (addrstr, 0, 128);
140  memset (netmaskstr, 0, 128);
141  memset (bcstr, 0, 128);
142  prefixlen = 0;
143 
144  if ( /* Linux */
145  (3 == sscanf (start, "inet addr:%127s Bcast:%127s Mask:%127s", addrstr,
146  bcstr, netmaskstr)) ||
147  (2 == sscanf (start, "inet addr:%127s Mask:%127s", addrstr,
148  netmaskstr)) ||
149  (2 == sscanf (start, "inet6 addr:%127s %d", addrstr, &prefixlen)) ||
150  /* Solaris, OS X */
151  (1 == sscanf (start, "inet %127s", addrstr)) ||
152  (1 == sscanf (start, "inet6 %127s", addrstr)))
153  {
154  /* IPv4 */
155  if (1 == inet_pton (AF_INET, addrstr, &v4))
156  {
157  memset (&a4, 0, sizeof(a4));
158  a4.sin_family = AF_INET;
159 #if HAVE_SOCKADDR_IN_SIN_LEN
160  a4.sin_len = (u_char) sizeof(struct sockaddr_in);
161 #endif
162  a4.sin_addr = v4;
163 
164  pass_bcaddr = NULL;
165  pass_netmask = NULL;
166  if (1 == inet_pton (AF_INET, bcstr, &v4))
167  {
168  memset (&bcaddr, 0, sizeof(bcaddr));
169  bcaddr.sin_family = AF_INET;
170 #if HAVE_SOCKADDR_IN_SIN_LEN
171  bcaddr.sin_len = (u_char) sizeof(struct sockaddr_in);
172 #endif
173  bcaddr.sin_addr = v4;
174  pass_bcaddr = (struct sockaddr *) &bcaddr;
175  }
176  if (1 == inet_pton (AF_INET, netmaskstr, &v4))
177  {
178  memset (&netmask, 0, sizeof(netmask));
179  netmask.sin_family = AF_INET;
180 #if HAVE_SOCKADDR_IN_SIN_LEN
181  netmask.sin_len = (u_char) sizeof(struct sockaddr_in);
182 #endif
183  netmask.sin_addr = v4;
184  pass_netmask = (struct sockaddr *) &netmask;
185  }
186 
187 
188  if (GNUNET_OK !=
189  proc (proc_cls, ifc,(0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE)),
190  (const struct sockaddr *) &a4,
191  pass_bcaddr, pass_netmask, sizeof(a4)))
192  break;
193  continue;
194  }
195  /* IPv6 */
196  if (1 == inet_pton (AF_INET6, addrstr, &v6))
197  {
198  memset (&a6, 0, sizeof(a6));
199  a6.sin6_family = AF_INET6;
200 #if HAVE_SOCKADDR_IN_SIN_LEN
201  a6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
202 #endif
203  a6.sin6_addr = v6;
204 
205  pass_netmask = NULL;
206  if (prefixlen != -1)
207  {
208  memset (v6.s6_addr, 0, sizeof(v6.s6_addr));
209  for (i = 0; i < prefixlen; i++)
210  {
211  v6.s6_addr[i >> 3] |= 1 << (i & 7);
212  }
213  memset (&netmask6, 0, sizeof(netmask6));
214  netmask6.sin6_family = AF_INET6;
215 #if HAVE_SOCKADDR_IN_SIN_LEN
216  netmask6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
217 #endif
218  netmask6.sin6_addr = v6;
219 
220  pass_netmask = (struct sockaddr *) &netmask6;
221  }
222 
223  if (GNUNET_OK !=
224  proc (proc_cls, ifc,(0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE)),
225  (const struct sockaddr *) &a6,
226  NULL, pass_netmask, sizeof(a6)))
227  break;
228  continue;
229  }
230  }
231  }
232  pclose (f);
233  return GNUNET_OK;
234 }
235 
236 
244 static int
246  void *proc_cls)
247 {
248  char line[1024];
249  char *replace;
250  char ifname[64];
251  char afstr[6];
252  char addrstr[128];
253  FILE *f;
254  struct sockaddr_in a4;
255  struct sockaddr_in6 a6;
256  struct in_addr v4;
257  struct in6_addr v6;
258  struct sockaddr_in netmask;
259  struct sockaddr_in6 netmask6;
260  unsigned int i;
261  unsigned int prefixlen;
262  static char *pcall;
263 
264  if (NULL == pcall)
265  {
266  const char *sbin_ip;
267 
268 #ifdef IFCONFIG
269  if (0 == access (PATH_TO_IP, X_OK))
270  sbin_ip = PATH_TO_IP;
271  else
272 #endif
273  if (0 == access ("/sbin/ip", X_OK))
274  sbin_ip = "/sbin/ip";
275  else if (0 == access ("/usr/sbin/ip", X_OK))
276  sbin_ip = "/usr/sbin/ip";
277  else
278  sbin_ip = "if";
279  GNUNET_asprintf (&pcall,
280  "%s -o add 2> /dev/null",
281  sbin_ip);
282  }
283  f = popen (pcall, "r");
284  if (! f)
285  {
287  "popen",
288  "ip");
289  return GNUNET_SYSERR;
290  }
291 
292  while (NULL != fgets (line, sizeof(line), f))
293  {
294  /* make parsing easier */
295  for (replace = line; *replace != '\0'; replace++)
296  {
297  if (*replace == '/')
298  *replace = ' ';
299  }
300  /* Zero-out stack allocated values */
301  memset (ifname, 0, 64);
302  memset (afstr, 0, 6);
303  memset (addrstr, 0, 128);
304  if (4 != sscanf (line,
305  "%*u: %63s %5s %127s %6u",
306  ifname,
307  afstr,
308  addrstr,
309  &prefixlen))
310  continue;
311  /* IPv4 */
312  if ((0 == strcasecmp ("inet",
313  afstr)) &&
314  (1 == inet_pton (AF_INET,
315  addrstr,
316  &v4)))
317  {
318  memset (&a4, 0, sizeof(a4));
319  a4.sin_family = AF_INET;
320 #if HAVE_SOCKADDR_IN_SIN_LEN
321  a4.sin_len = (u_char) sizeof(struct sockaddr_in);
322 #endif
323  a4.sin_addr = v4;
324 
325  memset (&v4.s_addr, 0, sizeof(v4.s_addr));
326  for (i = 0; i < prefixlen; i++)
327  v4.s_addr |= 1 << (i & 7);
328  memset (&netmask, 0, sizeof(netmask));
329  netmask.sin_family = AF_INET;
330 #if HAVE_SOCKADDR_IN_SIN_LEN
331  netmask.sin_len = (u_char) sizeof(struct sockaddr_in);
332 #endif
333  netmask.sin_addr = v4;
334 
335  if (GNUNET_OK !=
336  proc (proc_cls,
337  ifname,
338  (0 == strcmp (ifname,
339  GNUNET_DEFAULT_INTERFACE)),
340  (const struct sockaddr *) &a4,
341  NULL,
342  (const struct sockaddr *) &netmask,
343  sizeof(a4)))
344  break;
345  }
346  /* IPv6 */
347  if ((0 == strcasecmp ("inet6",
348  afstr)) &&
349  (1 == inet_pton (AF_INET6,
350  addrstr,
351  &v6)))
352  {
353  memset (&a6, 0, sizeof(a6));
354  a6.sin6_family = AF_INET6;
355 #if HAVE_SOCKADDR_IN_SIN_LEN
356  a6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
357 #endif
358  a6.sin6_addr = v6;
359 
360  memset (v6.s6_addr, 0, sizeof(v6.s6_addr));
361  for (i = 0; i < prefixlen; i++)
362  v6.s6_addr[i >> 3] |= 1 << (i & 7);
363  memset (&netmask6, 0, sizeof(netmask6));
364  netmask6.sin6_family = AF_INET6;
365 #if HAVE_SOCKADDR_IN_SIN_LEN
366  netmask6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
367 #endif
368  netmask6.sin6_addr = v6;
369 
370  if (GNUNET_OK !=
371  proc (proc_cls,
372  ifname,
373  (0 == strcmp (ifname,
374  GNUNET_DEFAULT_INTERFACE)),
375  (const struct sockaddr *) &a6,
376  NULL,
377  (const struct sockaddr *) &netmask6,
378  sizeof(a6)))
379  break;
380  }
381  }
382  pclose (f);
383  return GNUNET_OK;
384 }
385 
386 
387 #endif
388 
389 
396 void
398  void *proc_cls)
399 {
400 #if HAVE_GETIFADDRS && HAVE_FREEIFADDRS
401  struct ifaddrs *ifa_first;
402  struct ifaddrs *ifa_ptr;
403  socklen_t alen;
404 
405  if (getifaddrs (&ifa_first) == 0)
406  {
407  for (ifa_ptr = ifa_first; ifa_ptr != NULL; ifa_ptr = ifa_ptr->ifa_next)
408  {
409  if ((ifa_ptr->ifa_name != NULL) && (ifa_ptr->ifa_addr != NULL) &&
410  ( (ifa_ptr->ifa_flags & IFF_UP) != 0) )
411  {
412  if ((ifa_ptr->ifa_addr->sa_family != AF_INET) &&
413  (ifa_ptr->ifa_addr->sa_family != AF_INET6))
414  continue;
415  if (ifa_ptr->ifa_addr->sa_family == AF_INET)
416  alen = sizeof(struct sockaddr_in);
417  else
418  alen = sizeof(struct sockaddr_in6);
419  if (GNUNET_OK !=
420  proc (proc_cls, ifa_ptr->ifa_name,
421  (0 == strcmp (ifa_ptr->ifa_name, GNUNET_DEFAULT_INTERFACE)),
422  ifa_ptr->ifa_addr, ifa_ptr->ifa_broadaddr,
423  ifa_ptr->ifa_netmask, alen))
424  break;
425  }
426  }
427  freeifaddrs (ifa_first);
428  }
429 #else
430  if (GNUNET_OK ==
431  try_ip (proc,
432  proc_cls))
433  return;
434  if (GNUNET_OK ==
435  try_ifconfig (proc,
436  proc_cls))
437  return;
439  "Failed to enumerate network interfaces\n");
440 #endif
441 }
442 
443 
444 /* end of os_network.c */
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:39
static char * line
Desired phone line (string to be converted to a hash).
static int replace
Replace DID Document Flag.
Definition: gnunet-did.c:56
static const char * sbin_ip
Name and full path of IPTABLES binary.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_BULK
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
void GNUNET_OS_network_interfaces_list(GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls)
Enumerate all network interfaces.
Definition: os_network.c:397
enum GNUNET_GenericReturnValue(* GNUNET_OS_NetworkInterfaceProcessor)(void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen)
Callback function invoked for each interface found.
static int try_ip(GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls)
Try to enumerate all network interfaces using 'ip'.
Definition: os_network.c:245
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition: os_network.c:36
static int try_ifconfig(GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls)
Try to enumerate all network interfaces using 'ifconfig'.
Definition: os_network.c:52
#define LOG(kind,...)
Definition: os_network.c:35