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