Greenbone Vulnerability Management Libraries  22.8.0
networking.c
Go to the documentation of this file.
1 /* SPDX-FileCopyrightText: 2013-2023 Greenbone AG
2  *
3  * SPDX-License-Identifier: GPL-2.0-or-later
4  */
5 
11 #include "networking.h"
12 
13 #include <arpa/inet.h> /* for inet_ntop */
14 #include <assert.h> /* for assert */
15 #include <ctype.h> /* for isblank */
16 #include <errno.h> /* for errno, EAFNOSUPPORT */
17 #include <glib/gstdio.h>
18 #include <ifaddrs.h> /* for ifaddrs, freeifaddrs, getifaddrs */
19 #include <net/if.h> /* for IFNAMSIZ */
20 #include <stdint.h> /* for uint32_t, uint8_t */
21 #include <stdlib.h> /* for atoi, strtol */
22 #include <string.h> /* for memcpy, bzero, strchr, strlen, strcmp, strncpy */
23 #include <sys/socket.h> /* for AF_INET, AF_INET6, AF_UNSPEC, sockaddr_storage */
24 #include <unistd.h> /* for close */
25 
26 #ifdef __FreeBSD__
27 #include <netinet/in.h>
28 #define s6_addr32 __u6_addr.__u6_addr32
29 #endif
30 
31 #undef G_LOG_DOMAIN
32 
35 #define G_LOG_DOMAIN "libgvm base"
36 
37 #if GLIB_CHECK_VERSION(2, 67, 3)
38 #define memdup g_memdup2
39 #else
40 #define memdup g_memdup
41 #endif
42 
43 /* Global variables */
44 
45 /* Source interface name eg. eth1. */
46 char global_source_iface[IFNAMSIZ] = {'\0'};
47 
48 /* Source IPv4 address. */
49 struct in_addr global_source_addr = {.s_addr = 0};
50 
51 /* Source IPv6 address. */
52 struct in6_addr global_source_addr6 = {.s6_addr32 = {0, 0, 0, 0}};
53 
54 /* Source Interface/Address related functions. */
55 
63 int
64 gvm_source_iface_init (const char *iface)
65 {
66  struct ifaddrs *ifaddr, *ifa;
67  int ret = 1;
68 
69  bzero (global_source_iface, sizeof (global_source_iface));
70  global_source_addr.s_addr = INADDR_ANY;
71  global_source_addr6 = in6addr_any;
72 
73  if (iface == NULL)
74  return ret;
75 
76  if (strlen (iface) >= sizeof (global_source_iface))
77  return ret;
78 
79  if (getifaddrs (&ifaddr) == -1)
80  return ret;
81 
82  /* Search for the adequate interface/family. */
83  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
84  {
85  if (ifa->ifa_addr && strcmp (iface, ifa->ifa_name) == 0)
86  {
87  if (ifa->ifa_addr->sa_family == AF_INET)
88  {
89  struct in_addr *addr =
90  &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
91 
92  memcpy (&global_source_addr, addr, sizeof (global_source_addr));
93  ret = 0;
94  }
95  else if (ifa->ifa_addr->sa_family == AF_INET6)
96  {
97  struct sockaddr_in6 *addr;
98 
99  addr = (struct sockaddr_in6 *) ifa->ifa_addr;
100  memcpy (&global_source_addr6.s6_addr, &addr->sin6_addr,
101  sizeof (struct in6_addr));
102  ret = 0;
103  }
104  }
105  }
106 
107  /* At least one address for the interface was found. */
108  if (ret == 0)
109  memcpy (global_source_iface, iface, strlen (iface));
110 
111  freeifaddrs (ifaddr);
112  return ret;
113 }
114 
120 int
122 {
123  return *global_source_iface != '\0';
124 }
125 
135 int
136 gvm_source_set_socket (int socket, int port, int family)
137 {
138  if (family == AF_INET)
139  {
140  struct sockaddr_in addr;
141 
142  bzero (&addr, sizeof (addr));
143  gvm_source_addr (&addr.sin_addr);
144  addr.sin_port = htons (port);
145  addr.sin_family = AF_INET;
146 
147  if (bind (socket, (struct sockaddr *) &addr, sizeof (addr)) < 0)
148  return -1;
149  }
150  else if (family == AF_INET6)
151  {
152  struct sockaddr_in6 addr6;
153 
154  bzero (&addr6, sizeof (addr6));
155  gvm_source_addr6 (&addr6.sin6_addr);
156  addr6.sin6_port = htons (port);
157  addr6.sin6_family = AF_INET6;
158 
159  if (bind (socket, (struct sockaddr *) &addr6, sizeof (addr6)) < 0)
160  return -1;
161  }
162  else
163  return -1;
164 
165  return 0;
166 }
167 
173 void
174 gvm_source_addr (void *addr)
175 {
176  if (addr)
177  memcpy (addr, &global_source_addr.s_addr, 4);
178 }
179 
185 void
186 gvm_source_addr6 (void *addr6)
187 {
188  if (addr6)
189  memcpy (addr6, &global_source_addr6.s6_addr, 16);
190 }
191 
198 void
199 gvm_source_addr_as_addr6 (struct in6_addr *addr6)
200 {
201  if (addr6)
203 }
204 
210 char *
212 {
213  char *str = g_malloc0 (INET_ADDRSTRLEN);
214 
215  inet_ntop (AF_INET, &global_source_addr.s_addr, str, INET_ADDRSTRLEN);
216  return str;
217 }
218 
224 char *
226 {
227  char *str = g_malloc0 (INET6_ADDRSTRLEN);
228 
229  inet_ntop (AF_INET6, &global_source_addr6, str, INET6_ADDRSTRLEN);
230  return str;
231 }
232 
233 /* Miscellaneous functions. */
234 
242 void
243 ipv4_as_ipv6 (const struct in_addr *ip4, struct in6_addr *ip6)
244 {
245  if (ip4 == NULL || ip6 == NULL)
246  return;
247 
248  ip6->s6_addr32[0] = 0;
249  ip6->s6_addr32[1] = 0;
250  ip6->s6_addr32[2] = htonl (0xffff);
251  memcpy (&ip6->s6_addr32[3], ip4, sizeof (struct in_addr));
252 }
253 
260 void
261 addr6_to_str (const struct in6_addr *addr6, char *str)
262 {
263  if (!addr6)
264  return;
265  if (IN6_IS_ADDR_V4MAPPED (addr6))
266  inet_ntop (AF_INET, &addr6->s6_addr32[3], str, INET6_ADDRSTRLEN);
267  else
268  inet_ntop (AF_INET6, addr6, str, INET6_ADDRSTRLEN);
269 }
270 
278 char *
279 addr6_as_str (const struct in6_addr *addr6)
280 {
281  char *str;
282 
283  if (!addr6)
284  return NULL;
285 
286  str = g_malloc0 (INET6_ADDRSTRLEN);
287  addr6_to_str (addr6, str);
288  return str;
289 }
290 
297 void
298 sockaddr_as_str (const struct sockaddr_storage *addr, char *str)
299 {
300  if (!addr || !str)
301  return;
302 
303  if (addr->ss_family == AF_INET)
304  {
305  struct sockaddr_in *saddr = (struct sockaddr_in *) addr;
306  inet_ntop (AF_INET, &saddr->sin_addr, str, INET6_ADDRSTRLEN);
307  }
308  else if (addr->ss_family == AF_INET6)
309  {
310  struct sockaddr_in6 *s6addr = (struct sockaddr_in6 *) addr;
311  if (IN6_IS_ADDR_V4MAPPED (&s6addr->sin6_addr))
312  inet_ntop (AF_INET, &s6addr->sin6_addr.s6_addr[12], str,
313  INET6_ADDRSTRLEN);
314  else
315  inet_ntop (AF_INET6, &s6addr->sin6_addr, str, INET6_ADDRSTRLEN);
316  }
317  else if (addr->ss_family == AF_UNIX)
318  {
319  g_snprintf (str, INET6_ADDRSTRLEN, "unix_socket");
320  }
321  else if (addr->ss_family == AF_UNSPEC)
322  {
323  g_snprintf (str, INET6_ADDRSTRLEN, "unknown_socket");
324  }
325  else
326  {
327  g_snprintf (str, INET6_ADDRSTRLEN, "type_%d_socket", addr->ss_family);
328  }
329 }
330 
338 GSList *
339 gvm_resolve_list (const char *name)
340 {
341  struct addrinfo hints, *info, *p;
342  GSList *list = NULL;
343 
344  if (name == NULL)
345  return NULL;
346 
347  bzero (&hints, sizeof (hints));
348  hints.ai_family = AF_UNSPEC;
349  hints.ai_socktype = SOCK_STREAM;
350  hints.ai_protocol = 0;
351  if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
352  return NULL;
353 
354  p = info;
355  while (p)
356  {
357  struct in6_addr dst;
358 
359  if (p->ai_family == AF_INET)
360  {
361  struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
362  ipv4_as_ipv6 (&(addrin->sin_addr), &dst);
363  list = g_slist_prepend (list, memdup (&dst, sizeof (dst)));
364  }
365  else if (p->ai_family == AF_INET6)
366  {
367  struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
368  memcpy (&dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
369  list = g_slist_prepend (list, memdup (&dst, sizeof (dst)));
370  }
371  p = p->ai_next;
372  }
373 
374  freeaddrinfo (info);
375  return list;
376 }
377 
388 int
389 gvm_resolve (const char *name, void *dst, int family)
390 {
391  struct addrinfo hints, *info, *p;
392 
393  if (name == NULL || dst == NULL
394  || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
395  return -1;
396 
397  bzero (&hints, sizeof (hints));
398  hints.ai_family = family;
399  hints.ai_socktype = SOCK_STREAM;
400  hints.ai_protocol = 0;
401  if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
402  return -1;
403 
404  p = info;
405  while (p)
406  {
407  if (p->ai_family == family || family == AF_UNSPEC)
408  {
409  if (p->ai_family == AF_INET && family == AF_UNSPEC)
410  {
411  struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
412  ipv4_as_ipv6 (&(addrin->sin_addr), dst);
413  }
414  else if (p->ai_family == AF_INET)
415  {
416  struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
417  memcpy (dst, &(addrin->sin_addr), sizeof (struct in_addr));
418  }
419  else if (p->ai_family == AF_INET6)
420  {
421  struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
422  memcpy (dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
423  }
424  break;
425  }
426 
427  p = p->ai_next;
428  }
429 
430  freeaddrinfo (info);
431  return 0;
432 }
433 
442 int
443 gvm_resolve_as_addr6 (const char *name, struct in6_addr *ip6)
444 {
445  return gvm_resolve (name, ip6, AF_UNSPEC);
446 }
447 
448 /* Ports related. */
449 
459 int
460 validate_port_range (const char *port_range)
461 {
462  gchar **split, **point, *range, *range_start;
463 
464  if (!port_range)
465  return 1;
466 
467  while (*port_range && isblank (*port_range))
468  port_range++;
469  if (*port_range == '\0')
470  return 1;
471 
472  /* Treat newlines like commas. */
473  range = range_start = g_strdup (port_range);
474  while (*range)
475  {
476  if (*range == '\n')
477  *range = ',';
478  range++;
479  }
480 
481  split = g_strsplit (range_start, ",", 0);
482  g_free (range_start);
483  point = split;
484 
485  while (*point)
486  {
487  gchar *hyphen, *element;
488 
489  /* Strip off any outer whitespace. */
490 
491  element = g_strstrip (*point);
492 
493  /* Strip off any leading type specifier and following whitespace. */
494 
495  if ((strlen (element) >= 2)
496  && ((element[0] == 'T') || (element[0] == 'U')))
497  {
498  element++;
499  while (*element && isblank (*element))
500  element++;
501  if (*element == ':')
502  element++;
503  }
504 
505  /* Look for a hyphen. */
506 
507  hyphen = strchr (element, '-');
508  if (hyphen)
509  {
510  long int number1, number2;
511  const char *first;
512  char *end;
513 
514  hyphen++;
515 
516  /* Check the first number. */
517 
518  first = element;
519  while (*first && isblank (*first))
520  first++;
521  if (*first == '-')
522  goto fail;
523 
524  errno = 0;
525  number1 = strtol (first, &end, 10);
526  while (*end && isblank (*end))
527  end++;
528  if (errno || (*end != '-'))
529  goto fail;
530  if (number1 == 0)
531  goto fail;
532  if (number1 > 65535)
533  goto fail;
534 
535  /* Check the second number. */
536 
537  while (*hyphen && isblank (*hyphen))
538  hyphen++;
539  if (*hyphen == '\0')
540  goto fail;
541 
542  errno = 0;
543  number2 = strtol (hyphen, &end, 10);
544  while (*end && isblank (*end))
545  end++;
546  if (errno || *end)
547  goto fail;
548  if (number2 == 0)
549  goto fail;
550  if (number2 > 65535)
551  goto fail;
552 
553  if (number1 > number2)
554  goto fail;
555  }
556  else
557  {
558  long int number;
559  const char *only;
560  char *end;
561 
562  /* Check the single number. */
563 
564  only = element;
565  while (*only && isblank (*only))
566  only++;
567  /* Empty ranges are OK. */
568  if (*only)
569  {
570  errno = 0;
571  number = strtol (only, &end, 10);
572  while (*end && isblank (*end))
573  end++;
574  if (errno || *end)
575  goto fail;
576  if (number == 0)
577  goto fail;
578  if (number > 65535)
579  goto fail;
580  }
581  }
582  point += 1;
583  }
584 
585  g_strfreev (split);
586  return 0;
587 
588 fail:
589  g_strfreev (split);
590  return 1;
591 }
592 
600 array_t *
601 port_range_ranges (const char *port_range)
602 {
603  gchar **split, **point, *range_start, *current;
604  array_t *ranges;
605  int tcp, err;
606 
607  if (!port_range)
608  return NULL;
609 
610  /* port_range needs to be a valid port_range string. */
611  err = validate_port_range (port_range);
612  if (err)
613  return NULL;
614 
615  ranges = make_array ();
616 
617  while (*port_range && isblank (*port_range))
618  port_range++;
619 
620  /* Accepts T: and U: before any of the ranges. This toggles the remaining
621  * ranges, as in nmap. Treats a leading naked range as TCP, whereas nmap
622  * treats it as TCP and UDP. */
623 
624  /* Treat newlines like commas. */
625  range_start = current = g_strdup (port_range);
626  while (*current)
627  {
628  if (*current == '\n')
629  *current = ',';
630  current++;
631  }
632 
633  tcp = 1;
634  split = g_strsplit (range_start, ",", 0);
635  g_free (range_start);
636  point = split;
637 
638  while (*point)
639  {
640  gchar *hyphen, *element;
641  range_t *range;
642  int element_strlen;
643 
644  element = g_strstrip (*point);
645  element_strlen = strlen (element);
646 
647  if (element_strlen >= 2)
648  {
649  if (element[0] == 'T')
650  {
651  element++;
652  while (*element && isblank (*element))
653  element++;
654  if (*element == ':')
655  {
656  element++;
657  tcp = 1;
658  }
659  }
660  else if (element[0] == 'U')
661  {
662  element++;
663  while (*element && isblank (*element))
664  element++;
665  if (*element == ':')
666  {
667  element++;
668  tcp = 0;
669  }
670  }
671  /* Else tcp stays as it is. */
672  }
673 
674  /* Skip any space that followed the type specifier. */
675  while (*element && isblank (*element))
676  element++;
677 
678  hyphen = strchr (element, '-');
679  if (hyphen)
680  {
681  *hyphen = '\0';
682  hyphen++;
683  while (*hyphen && isblank (*hyphen))
684  hyphen++;
685  assert (*hyphen); /* Validation checks this. */
686 
687  /* A range. */
688 
689  range = (range_t *) g_malloc0 (sizeof (range_t));
690 
691  range->start = atoi (element);
692  range->end = atoi (hyphen);
694  range->exclude = 0;
695 
696  array_add (ranges, range);
697  }
698  else if (*element)
699  {
700  /* A single port. */
701 
702  range = (range_t *) g_malloc0 (sizeof (range_t));
703 
704  range->start = atoi (element);
705  range->end = range->start;
707  range->exclude = 0;
708 
709  array_add (ranges, range);
710  }
711  /* Else skip over empty range. */
712  point += 1;
713  }
714  g_strfreev (split);
715  return ranges;
716 }
717 
727 int
728 port_in_port_ranges (int pnum, port_protocol_t ptype, array_t *pranges)
729 {
730  unsigned int i;
731 
732  if (pranges == NULL || pnum < 0 || pnum > 65536)
733  return 0;
734 
735  for (i = 0; i < pranges->len; i++)
736  {
737  range_t *range = (range_t *) g_ptr_array_index (pranges, i);
738  if (range->type != ptype)
739  continue;
740  if (range->start <= pnum && pnum <= range->end)
741  return 1;
742  }
743  return 0;
744 }
745 
751 int
753 {
754  int sock = socket (PF_INET6, SOCK_STREAM, 0);
755 
756  if (sock < 0)
757  {
758  if (errno == EAFNOSUPPORT)
759  return 0;
760  }
761  else
762  close (sock);
763 
764  return 1;
765 }
766 
767 /* Functions used by alive detection module (Boreas). */
768 
774 static gboolean
775 ip_islocalhost (struct sockaddr_storage *storage)
776 {
777  struct in_addr addr;
778  struct in_addr *addr_p;
779  struct in6_addr addr6 = IN6ADDR_ANY_INIT;
780  struct in6_addr *addr6_p;
781  struct sockaddr_in *sin_p;
782  struct sockaddr_in6 *sin6_p;
783  struct ifaddrs *ifaddr, *ifa;
784  int family;
785 
786  family = storage->ss_family;
787  addr6_p = &addr6;
788  addr_p = &addr;
789  addr.s_addr = 0;
790 
791  if (family == AF_INET)
792  {
793  sin_p = (struct sockaddr_in *) storage;
794  addr = sin_p->sin_addr;
795 
796  if (addr_p == NULL)
797  return FALSE;
798  /* addr is 0.0.0.0 */
799  if ((addr_p)->s_addr == 0)
800  return TRUE;
801  /* addr starts with 127.0.0.1 */
802  if (((addr_p)->s_addr & htonl (0xFF000000)) == htonl (0x7F000000))
803  return TRUE;
804  }
805  if (family == AF_INET6)
806  {
807  sin6_p = (struct sockaddr_in6 *) storage;
808  addr6 = sin6_p->sin6_addr;
809 
810  if (IN6_IS_ADDR_V4MAPPED (&addr6))
811  {
812  /* addr is 0.0.0.0 */
813  if (addr6_p->s6_addr32[3] == 0)
814  return 1;
815 
816  /* addr starts with 127.0.0.1 */
817  if ((addr6_p->s6_addr32[3] & htonl (0xFF000000))
818  == htonl (0x7F000000))
819  return 1;
820  }
821  if (IN6_IS_ADDR_LOOPBACK (addr6_p))
822  return 1;
823  }
824 
825  if (getifaddrs (&ifaddr) == -1)
826  {
827  g_debug ("%s: getifaddr failed: %s", __func__, strerror (errno));
828  return FALSE;
829  }
830  else
831  {
832  struct sockaddr_in *sin;
833  struct sockaddr_in6 *sin6;
834 
835  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
836  {
837  if (ifa->ifa_addr == NULL)
838  continue;
839  if (ifa->ifa_addr->sa_family == AF_INET)
840  {
841  sin = (struct sockaddr_in *) (ifa->ifa_addr);
842  /* Check if same address as local interface. */
843  if (addr_p->s_addr == sin->sin_addr.s_addr)
844  return TRUE;
845  }
846  if (ifa->ifa_addr->sa_family == AF_INET6)
847  {
848  sin6 = (struct sockaddr_in6 *) (ifa->ifa_addr);
849 
850  /* Check if same address as local interface. */
851  if (family == AF_INET6
852  && IN6_ARE_ADDR_EQUAL (&(sin6->sin6_addr), addr6_p))
853  return TRUE;
854  }
855  }
856  freeifaddrs (ifaddr);
857  }
858 
859  return FALSE;
860 }
861 
862 typedef struct route_entry route_entry_t;
863 
866 {
867  gchar *interface;
868  unsigned long mask;
869  unsigned long dest;
870 };
871 
877 static GSList *
879 {
880  GSList *routes;
881  GError *err;
882  GIOChannel *file_channel;
883  gchar *line;
884  gchar **items_in_line;
885  int status;
886  route_entry_t *entry;
887 
888  err = NULL;
889  routes = NULL;
890  line = NULL;
891 
892  /* Open "/proc/net/route". */
893  file_channel = g_io_channel_new_file ("/proc/net/route", "r", &err);
894  if (file_channel == NULL)
895  {
896  g_warning ("%s: %s. ", __func__,
897  err ? err->message : "Error opening /proc/net/ipv6_route");
898  err = NULL;
899  return NULL;
900  }
901 
902  /* Skip first first line of file. */
903  status = g_io_channel_read_line (file_channel, &line, NULL, NULL, &err);
904  if (status != G_IO_STATUS_NORMAL || !line || err)
905  {
906  g_warning ("%s: %s", __func__,
907  err ? err->message
908  : "g_io_channel_read_line() status != G_IO_STATUS_NORMAL");
909  err = NULL;
910  }
911  g_free (line);
912 
913  /* Until EOF or err we go through lines of file and extract Iface, Mask and
914  * Destination and put it into the to be returned list of routes.*/
915  while (1)
916  {
917  gchar *interface, *char_p;
918  unsigned long mask, dest;
919  int count;
920 
921  /* Get new line. */
922  line = NULL;
923  status = g_io_channel_read_line (file_channel, &line, NULL, NULL, &err);
924  if ((status != G_IO_STATUS_NORMAL) || !line || err)
925  {
926  if (status == G_IO_STATUS_AGAIN)
927  g_warning ("%s: /proc/net/route unavailable.", __func__);
928  if (err || status == G_IO_STATUS_ERROR)
929  g_warning (
930  "%s: %s", __func__,
931  err ? err->message
932  : "g_io_channel_read_line() status == G_IO_STATUS_ERROR");
933  err = NULL;
934  g_free (line);
935  break;
936  }
937 
938  /* Get items in line. */
939  items_in_line = g_strsplit (line, "\t", -1);
940  /* Check for missing entries in line of "/proc/net/route". */
941  for (count = 0; items_in_line[count]; count++)
942  ;
943  if (11 != count)
944  {
945  g_strfreev (items_in_line);
946  g_free (line);
947  continue;
948  }
949 
950  interface = g_strndup (items_in_line[0], 64);
951  /* Cut interface str after ":" if IP aliasing is used. */
952  if ((char_p = strchr (interface, ':')))
953  {
954  *char_p = '\0';
955  }
956  dest = strtoul (items_in_line[1], NULL, 16);
957  mask = strtoul (items_in_line[7], NULL, 16);
958 
959  /* Fill GSList entry. */
960  entry = g_malloc0 (sizeof (route_entry_t));
961  entry->interface = interface;
962  entry->dest = dest;
963  entry->mask = mask;
964  routes = g_slist_append (routes, entry);
965 
966  g_strfreev (items_in_line);
967  g_free (line);
968  }
969 
970  status = g_io_channel_shutdown (file_channel, TRUE, &err);
971  if ((G_IO_STATUS_NORMAL != status) || err)
972  g_warning ("%s: %s", __func__,
973  err ? err->message
974  : "g_io_channel_shutdown() was not successful");
975 
976  return routes;
977 }
978 
993 gchar *
994 gvm_routethrough (struct sockaddr_storage *storage_dest,
995  struct sockaddr_storage *storage_source)
996 {
997  struct ifaddrs *ifaddr, *ifa;
998  gchar *interface_out;
999 
1000  interface_out = NULL;
1001 
1002  if (!storage_dest)
1003  return NULL;
1004 
1005  if (getifaddrs (&ifaddr) == -1)
1006  {
1007  g_debug ("%s: getifaddr failed: %s", __func__, strerror (errno));
1008  return NULL;
1009  }
1010 
1011  /* IPv4. */
1012  if (storage_dest->ss_family == AF_INET)
1013  {
1014  GSList *routes;
1015  GSList *routes_p;
1016 
1017  routes = get_routes ();
1018 
1019  /* Set storage_source to localhost if storage_source was supplied and
1020  * return name of loopback interface. */
1021  if (ip_islocalhost (storage_dest))
1022  {
1023  // TODO: check for (storage_source->ss_family == AF_INET)
1024  if (storage_source)
1025  {
1026  struct sockaddr_in *sin_p = (struct sockaddr_in *) storage_source;
1027  sin_p->sin_addr.s_addr = htonl (0x7F000001);
1028  }
1029 
1030  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1031  {
1032  if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_INET)
1033  && (ifa->ifa_flags & (IFF_LOOPBACK)))
1034  {
1035  interface_out = g_strdup (ifa->ifa_name);
1036  break;
1037  }
1038  }
1039  }
1040  else
1041  {
1042  struct sockaddr_in *sin_dest_p, *sin_src_p;
1043  struct in_addr global_src;
1044  unsigned long best_match;
1045 
1046  /* Check if global_source_addr in use. */
1047  gvm_source_addr (&global_src);
1048 
1049  sin_dest_p = (struct sockaddr_in *) storage_dest;
1050  sin_src_p = (struct sockaddr_in *) storage_source;
1051  /* Check routes for matching address. Get interface name and set
1052  * storage_source*/
1053  for (best_match = 0, routes_p = routes; routes_p;
1054  routes_p = routes_p->next)
1055  {
1056  if (((sin_dest_p->sin_addr.s_addr
1057  & ((route_entry_t *) (routes_p->data))->mask)
1058  == ((route_entry_t *) (routes_p->data))->dest)
1059  && (((route_entry_t *) (routes_p->data))->mask >= best_match))
1060  {
1061  /* Interface of matching route.*/
1062  g_free (interface_out);
1063  interface_out =
1064  g_strdup (((route_entry_t *) (routes_p->data))->interface);
1065  best_match = ((route_entry_t *) (routes_p->data))->mask;
1066 
1067  if (!storage_source)
1068  continue;
1069 
1070  /* Set storage_source to global source if global source
1071  * present.*/
1072  if (global_src.s_addr != INADDR_ANY)
1073  sin_src_p->sin_addr.s_addr = global_src.s_addr;
1074  /* Set storage_source to addr of matching interface if no
1075  * global source present.*/
1076  else
1077  {
1078  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1079  {
1080  if (ifa->ifa_addr
1081  && (ifa->ifa_addr->sa_family == AF_INET)
1082  && (g_strcmp0 (interface_out, ifa->ifa_name)
1083  == 0))
1084  {
1085  sin_src_p->sin_addr.s_addr =
1086  ((struct sockaddr_in *) (ifa->ifa_addr))
1087  ->sin_addr.s_addr;
1088  break;
1089  }
1090  }
1091  }
1092  }
1093  }
1094  }
1095  /* Free GSList. */
1096  if (routes)
1097  {
1098  for (routes_p = routes; routes_p; routes_p = routes_p->next)
1099  {
1100  if (((route_entry_t *) (routes_p->data))->interface)
1101  g_free (((route_entry_t *) (routes_p->data))->interface);
1102  }
1103  g_slist_free (routes);
1104  }
1105  }
1106  else if (storage_dest->ss_family == AF_INET6)
1107  {
1108  g_warning ("%s: IPv6 not yet implemented for this function. Will be "
1109  "implemented soon. Thanks for your patience.",
1110  __func__);
1111  }
1112 
1113  return interface_out != NULL ? interface_out : NULL;
1114 }
1115 
1123 static int
1124 get_connected_udp_sock (struct sockaddr_storage *target_addr)
1125 {
1126  int family = target_addr->ss_family;
1127  int sockfd = -1;
1128  if (family == AF_INET)
1129  {
1130  sockfd = socket (AF_INET, SOCK_DGRAM, 0);
1131  if (sockfd < 0)
1132  {
1133  g_warning ("Socket error: %s", strerror (errno));
1134  return -1;
1135  }
1136 
1137  ((struct sockaddr_in *) target_addr)->sin_port = htons (9877);
1138  if (connect (sockfd, (struct sockaddr *) target_addr,
1139  sizeof (struct sockaddr_in))
1140  < 0)
1141  {
1142  g_warning ("Connect error: %s", strerror (errno));
1143  close (sockfd);
1144  return -1;
1145  }
1146  }
1147  else if (family == AF_INET6)
1148  {
1149  sockfd = socket (AF_INET6, SOCK_DGRAM, 0);
1150  if (sockfd < 0)
1151  {
1152  g_warning ("Socket error: %s", strerror (errno));
1153  return -1;
1154  }
1155  ((struct sockaddr_in6 *) target_addr)->sin6_port = htons (9877);
1156  if (connect (sockfd, (struct sockaddr *) target_addr,
1157  sizeof (struct sockaddr_in6))
1158  < 0)
1159  {
1160  g_warning ("Connect error: %s", strerror (errno));
1161  close (sockfd);
1162  return -1;
1163  }
1164  }
1165  return sockfd;
1166 }
1167 
1176 static int
1177 get_sock_addr (int sockfd, struct sockaddr_storage *sock_addr)
1178 {
1179  socklen_t len;
1180  int family = sock_addr->ss_family;
1181  if (family == AF_INET)
1182  {
1183  len = sizeof (struct sockaddr_in);
1184  if (getsockname (sockfd, (struct sockaddr *) sock_addr, &len) < 0)
1185  {
1186  g_warning ("getsockname error: %s", strerror (errno));
1187  close (sockfd);
1188  return -1;
1189  }
1190  }
1191  else if (family == AF_INET6)
1192  {
1193  len = sizeof (struct sockaddr_in6);
1194  if (getsockname (sockfd, (struct sockaddr *) sock_addr, &len) < 0)
1195  {
1196  g_warning ("getsockname error:%s", strerror (errno));
1197  close (sockfd);
1198  return -1;
1199  }
1200  }
1201  return 0;
1202 }
1203 
1212 static char *
1213 get_ifname_from_ifaddr (struct sockaddr_storage *target_addr)
1214 {
1215  struct ifaddrs *ifaddr, *ifa;
1216  int family = target_addr->ss_family;
1217  char *interface_out = NULL;
1218 
1219  if (getifaddrs (&ifaddr) == -1)
1220  {
1221  g_warning ("%s: getifaddr failed: %s", __func__, strerror (errno));
1222  return NULL;
1223  }
1224  if (family == AF_INET)
1225  {
1226  struct sockaddr_in *sin;
1227  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1228  {
1229  if (!(ifa->ifa_flags & IFF_UP))
1230  continue;
1231  if (ifa->ifa_addr == NULL)
1232  continue;
1233  if (ifa->ifa_addr->sa_family == AF_INET)
1234  {
1235  sin = (struct sockaddr_in *) (ifa->ifa_addr);
1236  if (((struct sockaddr_in *) target_addr)->sin_addr.s_addr
1237  == sin->sin_addr.s_addr)
1238  interface_out = g_strdup (ifa->ifa_name);
1239  }
1240  }
1241  }
1242  else if (family == AF_INET6)
1243  {
1244  struct sockaddr_in6 *sin6;
1245  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1246  {
1247  if (!(ifa->ifa_flags & IFF_UP))
1248  continue;
1249  if (ifa->ifa_addr == NULL)
1250  continue;
1251  if (ifa->ifa_addr->sa_family == AF_INET6)
1252  {
1253  sin6 = (struct sockaddr_in6 *) (ifa->ifa_addr);
1254  if (IN6_ARE_ADDR_EQUAL (
1255  &(sin6->sin6_addr),
1256  &((struct sockaddr_in6 *) target_addr)->sin6_addr))
1257  interface_out = g_strdup (ifa->ifa_name);
1258  }
1259  }
1260  }
1261  freeifaddrs (ifaddr);
1262  return interface_out;
1263 }
1264 
1281 char *
1282 gvm_get_outgoing_iface (struct sockaddr_storage *target_addr)
1283 {
1284  int family, sockfd;
1285  struct sockaddr_storage out_iface_addr;
1286  char *out_iface_str;
1287 
1288  out_iface_str = NULL;
1289  family = target_addr->ss_family;
1290 
1291  if (!target_addr)
1292  return NULL;
1293 
1294  // get a connected udp socket
1295  if ((sockfd = get_connected_udp_sock (target_addr)) < 0)
1296  return NULL;
1297  // get socked address which is the addr of the interface we want to get
1298  out_iface_addr.ss_family = family;
1299  if (get_sock_addr (sockfd, &out_iface_addr) < 0)
1300  return NULL;
1301  // get interface name form interface address
1302  out_iface_str = get_ifname_from_ifaddr (&out_iface_addr);
1303  return out_iface_str;
1304 }
global_source_iface
char global_source_iface[IFNAMSIZ]
Definition: networking.c:46
addr6_to_str
void addr6_to_str(const struct in6_addr *addr6, char *str)
Stringifies an IP address.
Definition: networking.c:261
networking.h
GVM Networking related API.
port_range_ranges
array_t * port_range_ranges(const char *port_range)
Create a range array from a port_range string.
Definition: networking.c:601
port_in_port_ranges
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:728
memdup
#define memdup
Definition: networking.c:40
get_sock_addr
static int get_sock_addr(int sockfd, struct sockaddr_storage *sock_addr)
Get address from socket.
Definition: networking.c:1177
get_connected_udp_sock
static int get_connected_udp_sock(struct sockaddr_storage *target_addr)
Get a connected UDP socket.
Definition: networking.c:1124
array_t
GPtrArray array_t
Definition: array.h:16
gvm_resolve_list
GSList * gvm_resolve_list(const char *name)
Returns a list of addresses that a hostname resolves to.
Definition: networking.c:339
gvm_source_addr_str
char * gvm_source_addr_str(void)
Gives the source IPv4 address in string format.
Definition: networking.c:211
route_entry::mask
unsigned long mask
Definition: networking.c:868
route_entry::dest
unsigned long dest
Definition: networking.c:869
ipv4_as_ipv6
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:243
range::type
port_protocol_t type
Definition: networking.h:41
port_protocol_t
port_protocol_t
Possible port types.
Definition: networking.h:25
route_entry
Definition: networking.c:866
gvm_resolve
int gvm_resolve(const char *name, void *dst, int family)
Resolves a hostname to an IPv4 or IPv6 address.
Definition: networking.c:389
make_array
GPtrArray * make_array(void)
Make a global array.
Definition: array.c:25
ip_islocalhost
static gboolean ip_islocalhost(struct sockaddr_storage *storage)
Determine if IP is localhost.
Definition: networking.c:775
PORT_PROTOCOL_UDP
@ PORT_PROTOCOL_UDP
Definition: networking.h:27
array_add
void array_add(array_t *array, gpointer pointer)
Push a generic pointer onto an array.
Definition: array.c:68
global_source_addr
struct in_addr global_source_addr
Definition: networking.c:49
range::exclude
int exclude
Definition: networking.h:39
gvm_source_addr6_str
char * gvm_source_addr6_str(void)
Gives the source IPv6 address in string format.
Definition: networking.c:225
get_routes
static GSList * get_routes(void)
Get the entries of /proc/net/route as list of route_entry structs.
Definition: networking.c:878
get_ifname_from_ifaddr
static char * get_ifname_from_ifaddr(struct sockaddr_storage *target_addr)
Get iface name of iface matching the given interface address.
Definition: networking.c:1213
gvm_source_addr
void gvm_source_addr(void *addr)
Gives the source IPv4 address.
Definition: networking.c:174
ipv6_is_enabled
int ipv6_is_enabled(void)
Checks if IPv6 support is enabled.
Definition: networking.c:752
validate_port_range
int validate_port_range(const char *port_range)
Validate a port range string.
Definition: networking.c:460
PORT_PROTOCOL_TCP
@ PORT_PROTOCOL_TCP
Definition: networking.h:26
gvm_source_iface_init
int gvm_source_iface_init(const char *iface)
Initializes the source network interface name and related information.
Definition: networking.c:64
range::end
int end
Definition: networking.h:38
global_source_addr6
struct in6_addr global_source_addr6
Definition: networking.c:52
range
A port range.
Definition: networking.h:35
gvm_source_addr6
void gvm_source_addr6(void *addr6)
Gives the source IPv6 address.
Definition: networking.c:186
range::start
int start
Definition: networking.h:40
gvm_source_addr_as_addr6
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:199
gvm_source_iface_is_set
int gvm_source_iface_is_set(void)
Check if global_source global_source_iface is set.
Definition: networking.c:121
gvm_get_outgoing_iface
char * gvm_get_outgoing_iface(struct sockaddr_storage *target_addr)
Get the outgoing interface name for a given destination addr.
Definition: networking.c:1282
gvm_resolve_as_addr6
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:443
sockaddr_as_str
void sockaddr_as_str(const struct sockaddr_storage *addr, char *str)
Convert an IP address to string format.
Definition: networking.c:298
addr6_as_str
char * addr6_as_str(const struct in6_addr *addr6)
Stringifies an IP address.
Definition: networking.c:279
gvm_routethrough
gchar * gvm_routethrough(struct sockaddr_storage *storage_dest, struct sockaddr_storage *storage_source)
Get Interface which should be used for routing to destination addr.
Definition: networking.c:994
route_entry::interface
gchar * interface
Definition: networking.c:867
gvm_source_set_socket
int gvm_source_set_socket(int socket, int port, int family)
Binds a socket to use the global source address.
Definition: networking.c:136