Greenbone Vulnerability Management Libraries  10.0.0
networking.c
Go to the documentation of this file.
1 /* Copyright (C) 2013-2019 Greenbone Networks GmbH
2  *
3  * SPDX-License-Identifier: GPL-2.0-or-later
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
25 #include "networking.h"
26 
27 #include <arpa/inet.h> /* for inet_ntop */
28 #include <assert.h> /* for assert */
29 #include <ctype.h> /* for isblank */
30 #include <errno.h> /* for errno, EAFNOSUPPORT */
31 #include <glib/gstdio.h>
32 #include <ifaddrs.h> /* for ifaddrs, freeifaddrs, getifaddrs */
33 #include <net/if.h> /* for IFNAMSIZ */
34 #include <stdint.h> /* for uint32_t, uint8_t */
35 #include <stdlib.h> /* for atoi, strtol */
36 #include <string.h> /* for memcpy, bzero, strchr, strlen, strcmp, strncpy */
37 #include <sys/socket.h> /* for AF_INET, AF_INET6, AF_UNSPEC, sockaddr_storage */
38 #include <unistd.h> /* for close */
39 
40 #ifdef __FreeBSD__
41 #include <netinet/in.h>
42 #define s6_addr32 __u6_addr.__u6_addr32
43 #endif
44 
45 /* Global variables */
46 
47 /* Source interface name eg. eth1. */
48 char global_source_iface[IFNAMSIZ] = {'\0'};
49 
50 /* Source IPv4 address. */
51 struct in_addr global_source_addr = {.s_addr = 0};
52 
53 /* Source IPv6 address. */
54 struct in6_addr global_source_addr6 = {.s6_addr32 = {0, 0, 0, 0}};
55 
56 /* Source Interface/Address related functions. */
57 
65 int
66 gvm_source_iface_init (const char *iface)
67 {
68  struct ifaddrs *ifaddr, *ifa;
69  int ret = 1;
70 
71  bzero (global_source_iface, sizeof (global_source_iface));
72  global_source_addr.s_addr = INADDR_ANY;
73  global_source_addr6 = in6addr_any;
74 
75  if (iface == NULL)
76  return ret;
77 
78  if (getifaddrs (&ifaddr) == -1)
79  return ret;
80 
81  /* Search for the adequate interface/family. */
82  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
83  {
84  if (ifa->ifa_addr && strcmp (iface, ifa->ifa_name) == 0)
85  {
86  if (ifa->ifa_addr->sa_family == AF_INET)
87  {
88  struct in_addr *addr =
89  &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
90 
91  memcpy (&global_source_addr, addr, sizeof (global_source_addr));
92  ret = 0;
93  }
94  else if (ifa->ifa_addr->sa_family == AF_INET6)
95  {
96  struct sockaddr_in6 *addr;
97 
98  addr = (struct sockaddr_in6 *) ifa->ifa_addr;
99  memcpy (&global_source_addr6.s6_addr, &addr->sin6_addr,
100  sizeof (struct in6_addr));
101  ret = 0;
102  }
103  }
104  }
105 
106  /* At least one address for the interface was found. */
107  if (ret == 0)
108  strncpy (global_source_iface, iface, sizeof (global_source_iface) - 1);
109 
110  freeifaddrs (ifaddr);
111  return ret;
112 }
113 
119 int
121 {
122  return *global_source_iface != '\0';
123 }
124 
134 int
135 gvm_source_set_socket (int socket, int port, int family)
136 {
137  if (family == AF_INET)
138  {
139  struct sockaddr_in addr;
140 
141  bzero (&addr, sizeof (addr));
142  gvm_source_addr (&addr.sin_addr);
143  addr.sin_port = htons (port);
144  addr.sin_family = AF_INET;
145 
146  if (bind (socket, (struct sockaddr *) &addr, sizeof (addr)) < 0)
147  return -1;
148  }
149  else if (family == AF_INET6)
150  {
151  struct sockaddr_in6 addr6;
152 
153  bzero (&addr6, sizeof (addr6));
154  gvm_source_addr6 (&addr6.sin6_addr);
155  addr6.sin6_port = htons (port);
156  addr6.sin6_family = AF_INET6;
157 
158  if (bind (socket, (struct sockaddr *) &addr6, sizeof (addr6)) < 0)
159  return -1;
160  }
161  else
162  return -1;
163 
164  return 0;
165 }
166 
172 void
173 gvm_source_addr (void *addr)
174 {
175  if (addr)
176  memcpy (addr, &global_source_addr.s_addr, 4);
177 }
178 
184 void
185 gvm_source_addr6 (void *addr6)
186 {
187  if (addr6)
188  memcpy (addr6, &global_source_addr6.s6_addr, 16);
189 }
190 
197 void
198 gvm_source_addr_as_addr6 (struct in6_addr *addr6)
199 {
200  if (addr6)
202 }
203 
209 char *
211 {
212  char *str = g_malloc0 (INET_ADDRSTRLEN);
213 
214  inet_ntop (AF_INET, &global_source_addr.s_addr, str, INET_ADDRSTRLEN);
215  return str;
216 }
217 
223 char *
225 {
226  char *str = g_malloc0 (INET6_ADDRSTRLEN);
227 
228  inet_ntop (AF_INET6, &global_source_addr6, str, INET6_ADDRSTRLEN);
229  return str;
230 }
231 
232 /* Miscellaneous functions. */
233 
241 void
242 ipv4_as_ipv6 (const struct in_addr *ip4, struct in6_addr *ip6)
243 {
244  if (ip4 == NULL || ip6 == NULL)
245  return;
246 
247  ip6->s6_addr32[0] = 0;
248  ip6->s6_addr32[1] = 0;
249  ip6->s6_addr32[2] = htonl (0xffff);
250  memcpy (&ip6->s6_addr32[3], ip4, sizeof (struct in_addr));
251 }
252 
259 void
260 addr6_to_str (const struct in6_addr *addr6, char *str)
261 {
262  if (!addr6)
263  return;
264  if (IN6_IS_ADDR_V4MAPPED (addr6))
265  inet_ntop (AF_INET, &addr6->s6_addr32[3], str, INET6_ADDRSTRLEN);
266  else
267  inet_ntop (AF_INET6, addr6, str, INET6_ADDRSTRLEN);
268 }
269 
277 char *
278 addr6_as_str (const struct in6_addr *addr6)
279 {
280  char *str;
281 
282  if (!addr6)
283  return NULL;
284 
285  str = g_malloc0 (INET6_ADDRSTRLEN);
286  addr6_to_str (addr6, str);
287  return str;
288 }
289 
296 void
297 sockaddr_as_str (const struct sockaddr_storage *addr, char *str)
298 {
299  if (!addr || !str)
300  return;
301 
302  if (addr->ss_family == AF_INET)
303  {
304  struct sockaddr_in *saddr = (struct sockaddr_in *) addr;
305  inet_ntop (AF_INET, &saddr->sin_addr, str, INET6_ADDRSTRLEN);
306  }
307  else if (addr->ss_family == AF_INET6)
308  {
309  struct sockaddr_in6 *s6addr = (struct sockaddr_in6 *) addr;
310  if (IN6_IS_ADDR_V4MAPPED (&s6addr->sin6_addr))
311  inet_ntop (AF_INET, &s6addr->sin6_addr.s6_addr[12], str,
312  INET6_ADDRSTRLEN);
313  else
314  inet_ntop (AF_INET6, &s6addr->sin6_addr, str, INET6_ADDRSTRLEN);
315  }
316  else if (addr->ss_family == AF_UNIX)
317  {
318  g_snprintf (str, INET6_ADDRSTRLEN, "unix_socket");
319  }
320  else if (addr->ss_family == AF_UNSPEC)
321  {
322  g_snprintf (str, INET6_ADDRSTRLEN, "unknown_socket");
323  }
324  else
325  {
326  g_snprintf (str, INET6_ADDRSTRLEN, "type_%d_socket", addr->ss_family);
327  }
328 }
329 
337 GSList *
338 gvm_resolve_list (const char *name)
339 {
340  struct addrinfo hints, *info, *p;
341  GSList *list = NULL;
342 
343  if (name == NULL)
344  return NULL;
345 
346  bzero (&hints, sizeof (hints));
347  hints.ai_family = AF_UNSPEC;
348  hints.ai_socktype = SOCK_STREAM;
349  hints.ai_protocol = 0;
350  if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
351  return NULL;
352 
353  p = info;
354  while (p)
355  {
356  struct in6_addr dst;
357 
358  if (p->ai_family == AF_INET)
359  {
360  struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
361  ipv4_as_ipv6 (&(addrin->sin_addr), &dst);
362  list = g_slist_prepend (list, g_memdup (&dst, sizeof (dst)));
363  }
364  else if (p->ai_family == AF_INET6)
365  {
366  struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
367  memcpy (&dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
368  list = g_slist_prepend (list, g_memdup (&dst, sizeof (dst)));
369  }
370  p = p->ai_next;
371  }
372 
373  freeaddrinfo (info);
374  return list;
375 }
376 
387 int
388 gvm_resolve (const char *name, void *dst, int family)
389 {
390  struct addrinfo hints, *info, *p;
391 
392  if (name == NULL || dst == NULL
393  || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
394  return -1;
395 
396  bzero (&hints, sizeof (hints));
397  hints.ai_family = family;
398  hints.ai_socktype = SOCK_STREAM;
399  hints.ai_protocol = 0;
400  if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
401  return -1;
402 
403  p = info;
404  while (p)
405  {
406  if (p->ai_family == family || family == AF_UNSPEC)
407  {
408  if (p->ai_family == AF_INET && family == AF_UNSPEC)
409  {
410  struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
411  ipv4_as_ipv6 (&(addrin->sin_addr), dst);
412  }
413  else if (p->ai_family == AF_INET)
414  {
415  struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
416  memcpy (dst, &(addrin->sin_addr), sizeof (struct in_addr));
417  }
418  else if (p->ai_family == AF_INET6)
419  {
420  struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
421  memcpy (dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
422  }
423  break;
424  }
425 
426  p = p->ai_next;
427  }
428 
429  freeaddrinfo (info);
430  return 0;
431 }
432 
441 int
442 gvm_resolve_as_addr6 (const char *name, struct in6_addr *ip6)
443 {
444  return gvm_resolve (name, ip6, AF_UNSPEC);
445 }
446 
447 /* Ports related. */
448 
458 int
459 validate_port_range (const char *port_range)
460 {
461  gchar **split, **point, *range, *range_start;
462 
463  if (!port_range)
464  return 1;
465 
466  while (*port_range && isblank (*port_range))
467  port_range++;
468  if (*port_range == '\0')
469  return 1;
470 
471  /* Treat newlines like commas. */
472  range = range_start = g_strdup (port_range);
473  while (*range)
474  {
475  if (*range == '\n')
476  *range = ',';
477  range++;
478  }
479 
480  split = g_strsplit (range_start, ",", 0);
481  g_free (range_start);
482  point = split;
483 
484  while (*point)
485  {
486  gchar *hyphen, *element;
487 
488  /* Strip off any outer whitespace. */
489 
490  element = g_strstrip (*point);
491 
492  /* Strip off any leading type specifier. */
493 
494  if ((strlen (element) >= 2)
495  && ((element[0] == 'T') || (element[0] == 'U'))
496  && (element[1] == ':'))
497  element = element + 2;
498 
499  /* Look for a hyphen. */
500 
501  hyphen = strchr (element, '-');
502  if (hyphen)
503  {
504  long int number1, number2;
505  const char *first;
506  char *end;
507 
508  hyphen++;
509 
510  /* Check the first number. */
511 
512  first = element;
513  while (*first && isblank (*first))
514  first++;
515  if (*first == '-')
516  goto fail;
517 
518  errno = 0;
519  number1 = strtol (first, &end, 10);
520  while (*end && isblank (*end))
521  end++;
522  if (errno || (*end != '-'))
523  goto fail;
524  if (number1 == 0)
525  goto fail;
526  if (number1 > 65535)
527  goto fail;
528 
529  /* Check the second number. */
530 
531  while (*hyphen && isblank (*hyphen))
532  hyphen++;
533  if (*hyphen == '\0')
534  goto fail;
535 
536  errno = 0;
537  number2 = strtol (hyphen, &end, 10);
538  while (*end && isblank (*end))
539  end++;
540  if (errno || *end)
541  goto fail;
542  if (number2 == 0)
543  goto fail;
544  if (number2 > 65535)
545  goto fail;
546 
547  if (number1 > number2)
548  goto fail;
549  }
550  else
551  {
552  long int number;
553  const char *only;
554  char *end;
555 
556  /* Check the single number. */
557 
558  only = element;
559  while (*only && isblank (*only))
560  only++;
561  /* Empty ranges are OK. */
562  if (*only)
563  {
564  errno = 0;
565  number = strtol (only, &end, 10);
566  while (*end && isblank (*end))
567  end++;
568  if (errno || *end)
569  goto fail;
570  if (number == 0)
571  goto fail;
572  if (number > 65535)
573  goto fail;
574  }
575  }
576  point += 1;
577  }
578 
579  g_strfreev (split);
580  return 0;
581 
582 fail:
583  g_strfreev (split);
584  return 1;
585 }
586 
594 array_t *
595 port_range_ranges (const char *port_range)
596 {
597  gchar **split, **point, *range_start, *current;
598  array_t *ranges;
599  int tcp;
600 
601  if (!port_range)
602  return NULL;
603 
604  ranges = make_array ();
605 
606  while (*port_range && isblank (*port_range))
607  port_range++;
608 
609  /* Accepts T: and U: before any of the ranges. This toggles the remaining
610  * ranges, as in nmap. Treats a leading naked range as TCP, whereas nmap
611  * treats it as TCP and UDP. */
612 
613  /* Treat newlines like commas. */
614  range_start = current = g_strdup (port_range);
615  while (*current)
616  {
617  if (*current == '\n')
618  *current = ',';
619  current++;
620  }
621 
622  tcp = 1;
623  split = g_strsplit (range_start, ",", 0);
624  g_free (range_start);
625  point = split;
626 
627  while (*point)
628  {
629  gchar *hyphen, *element;
630  range_t *range;
631 
632  element = g_strstrip (*point);
633  if (strlen (element) >= 2)
634  {
635  if ((element[0] == 'T') && (element[1] == ':'))
636  {
637  tcp = 1;
638  element = element + 2;
639  }
640  else if ((element[0] == 'U') && (element[1] == ':'))
641  {
642  tcp = 0;
643  element = element + 2;
644  }
645  /* Else tcp stays as it is. */
646  }
647 
648  /* Skip any space that followed the type specifier. */
649  while (*element && isblank (*element))
650  element++;
651 
652  hyphen = strchr (element, '-');
653  if (hyphen)
654  {
655  *hyphen = '\0';
656  hyphen++;
657  while (*hyphen && isblank (*hyphen))
658  hyphen++;
659  assert (*hyphen); /* Validation checks this. */
660 
661  /* A range. */
662 
663  range = (range_t *) g_malloc0 (sizeof (range_t));
664 
665  range->start = atoi (element);
666  range->end = atoi (hyphen);
668  range->exclude = 0;
669 
670  array_add (ranges, range);
671  }
672  else if (*element)
673  {
674  /* A single port. */
675 
676  range = (range_t *) g_malloc0 (sizeof (range_t));
677 
678  range->start = atoi (element);
679  range->end = range->start;
681  range->exclude = 0;
682 
683  array_add (ranges, range);
684  }
685  /* Else skip over empty range. */
686  point += 1;
687  }
688  g_strfreev (split);
689  return ranges;
690 }
691 
701 int
702 port_in_port_ranges (int pnum, port_protocol_t ptype, array_t *pranges)
703 {
704  unsigned int i;
705 
706  if (pranges == NULL || pnum < 0 || pnum > 65536)
707  return 0;
708 
709  for (i = 0; i < pranges->len; i++)
710  {
711  range_t *range = (range_t *) g_ptr_array_index (pranges, i);
712  if (range->type != ptype)
713  continue;
714  if (range->start <= pnum && pnum <= range->end)
715  return 1;
716  }
717  return 0;
718 }
719 
725 int
727 {
728  int sock = socket (PF_INET6, SOCK_STREAM, 0);
729 
730  if (sock < 0)
731  {
732  if (errno == EAFNOSUPPORT)
733  return 0;
734  }
735  else
736  close (sock);
737 
738  return 1;
739 }
void gvm_source_addr6(void *addr6)
Gives the source IPv6 address.
Definition: networking.c:185
void addr6_to_str(const struct in6_addr *addr6, char *str)
Stringifies an IP address.
Definition: networking.c:260
int end
Definition: networking.h:52
int validate_port_range(const char *port_range)
Validate a port range string.
Definition: networking.c:459
int gvm_source_set_socket(int socket, int port, int family)
Binds a socket to use the global source address.
Definition: networking.c:135
char * gvm_source_addr_str(void)
Gives the source IPv4 address in string format.
Definition: networking.c:210
array_t * port_range_ranges(const char *port_range)
Create a range array from a port_range string.
Definition: networking.c:595
char * gvm_source_addr6_str(void)
Gives the source IPv6 address in string format.
Definition: networking.c:224
void gvm_source_addr_as_addr6(struct in6_addr *addr6)
Gives the source IPv4 mapped as an IPv6 address. eg. 192.168.20.10 would map to ::ffff:192....
Definition: networking.c:198
int gvm_source_iface_init(const char *iface)
Initializes the source network interface name and related information.
Definition: networking.c:66
GSList * gvm_resolve_list(const char *name)
Returns a list of addresses that a hostname resolves to.
Definition: networking.c:338
GPtrArray array_t
Definition: array.h:30
int gvm_resolve_as_addr6(const char *name, struct in6_addr *ip6)
Resolves a hostname to an IPv4-mapped IPv6 or IPv6 address.
Definition: networking.c:442
GVM Networking related API.
A port range.
Definition: networking.h:48
void gvm_source_addr(void *addr)
Gives the source IPv4 address.
Definition: networking.c:173
int gvm_resolve(const char *name, void *dst, int family)
Resolves a hostname to an IPv4 or IPv6 address.
Definition: networking.c:388
int port_in_port_ranges(int pnum, port_protocol_t ptype, array_t *pranges)
Checks if a port num is in port ranges array.
Definition: networking.c:702
int start
Definition: networking.h:54
int gvm_source_iface_is_set(void)
Check if global_source global_source_iface is set.
Definition: networking.c:120
int exclude
Definition: networking.h:53
void array_add(array_t *array, gpointer pointer)
Push a generic pointer onto an array.
Definition: array.c:76
int ipv6_is_enabled()
Checks if IPv6 support is enabled.
Definition: networking.c:726
char * addr6_as_str(const struct in6_addr *addr6)
Stringifies an IP address.
Definition: networking.c:278
void ipv4_as_ipv6(const struct in_addr *ip4, struct in6_addr *ip6)
Maps an IPv4 address as an IPv6 address. eg. 192.168.10.20 would map to ::ffff:192....
Definition: networking.c:242
GPtrArray * make_array()
Make a global array.
Definition: array.c:33
struct in6_addr global_source_addr6
Definition: networking.c:54
port_protocol_t
Possible port types.
Definition: networking.h:38
void sockaddr_as_str(const struct sockaddr_storage *addr, char *str)
Convert an IP address to string format.
Definition: networking.c:297
port_protocol_t type
Definition: networking.h:55
char global_source_iface[IFNAMSIZ]
Definition: networking.c:48
struct in_addr global_source_addr
Definition: networking.c:51