Greenbone Vulnerability Management Libraries: base/networking.c Source File

Greenbone Vulnerability Management Libraries 23.7.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
10
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
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
63int
64gvm_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
120int
121gvm_source_iface_is_set (void)
122{
123 return *global_source_iface != '\0';
124}
125
135int
136gvm_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
173void
174gvm_source_addr (void *addr)
175{
176 if (addr)
177 memcpy (addr, &global_source_addr.s_addr, 4);
178}
179
185void
186gvm_source_addr6 (void *addr6)
187{
188 if (addr6)
189 memcpy (addr6, &global_source_addr6.s6_addr, 16);
190}
191
198void
199gvm_source_addr_as_addr6 (struct in6_addr *addr6)
200{
201 if (addr6)
202 ipv4_as_ipv6 (&global_source_addr, addr6);
203}
204
210char *
211gvm_source_addr_str (void)
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
224char *
225gvm_source_addr6_str (void)
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
242void
243ipv4_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
260void
261addr6_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
278char *
279addr6_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
297void
298sockaddr_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
338GSList *
339gvm_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
388int
389gvm_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
442int
443gvm_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
459int
460validate_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
588fail:
589 g_strfreev (split);
590 return 1;
591}
592
600 array_t *
601port_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);
693 range->type = tcp ? PORT_PROTOCOL_TCP : PORT_PROTOCOL_UDP;
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;
706 range->type = tcp ? PORT_PROTOCOL_TCP : PORT_PROTOCOL_UDP;
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
727int
728port_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
751int
752ipv6_is_enabled (void)
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
774static gboolean
775ip_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
865 struct route_entry
866{
867 gchar *interface;
868 unsigned long mask;
869 unsigned long dest;
870};
871
877static GSList *
878get_routes (void)
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 char_p = strchr (interface, ':');
953 if (char_p)
954 {
955 *char_p = '\0';
956 }
957 dest = strtoul (items_in_line[1], NULL, 16);
958 mask = strtoul (items_in_line[7], NULL, 16);
959
960 /* Fill GSList entry. */
961 entry = g_malloc0 (sizeof (route_entry_t));
962 entry->interface = interface;
963 entry->dest = dest;
964 entry->mask = mask;
965 routes = g_slist_append (routes, entry);
966
967 g_strfreev (items_in_line);
968 g_free (line);
969 }
970
971 status = g_io_channel_shutdown (file_channel, TRUE, &err);
972 g_io_channel_unref (file_channel);
973 if ((G_IO_STATUS_NORMAL != status) || err)
974 g_warning ("%s: %s", __func__,
975 err ? err->message
976 : "g_io_channel_shutdown() was not successful");
977
978 return routes;
979}
980
986static void
987free_routes (GSList *routes)
988{
989 if (routes)
990 {
991 GSList *routes_p;
992
993 for (routes_p = routes; routes_p; routes_p = routes_p->next)
994 {
995 g_free (((route_entry_t *) (routes_p->data))->interface);
996 g_free (routes_p->data);
997 }
998 g_slist_free (routes);
999 }
1000}
1001
1016gchar *
1017gvm_routethrough (struct sockaddr_storage *storage_dest,
1018 struct sockaddr_storage *storage_source)
1019{
1020 struct ifaddrs *ifaddr, *ifa;
1021 gchar *interface_out;
1022
1023 interface_out = NULL;
1024
1025 if (!storage_dest)
1026 return NULL;
1027
1028 if (getifaddrs (&ifaddr) == -1)
1029 {
1030 g_debug ("%s: getifaddr failed: %s", __func__, strerror (errno));
1031 return NULL;
1032 }
1033
1034 /* IPv4. */
1035 if (storage_dest->ss_family == AF_INET)
1036 {
1037 GSList *routes;
1038
1039 routes = get_routes ();
1040
1041 /* Set storage_source to localhost if storage_source was supplied and
1042 * return name of loopback interface. */
1043 if (ip_islocalhost (storage_dest))
1044 {
1045 // TODO: check for (storage_source->ss_family == AF_INET)
1046 if (storage_source)
1047 {
1048 struct sockaddr_in *sin_p = (struct sockaddr_in *) storage_source;
1049 sin_p->sin_addr.s_addr = htonl (0x7F000001);
1050 }
1051
1052 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1053 {
1054 if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_INET)
1055 && (ifa->ifa_flags & (IFF_LOOPBACK)))
1056 {
1057 interface_out = g_strdup (ifa->ifa_name);
1058 break;
1059 }
1060 }
1061 }
1062 else
1063 {
1064 struct sockaddr_in *sin_dest_p, *sin_src_p;
1065 struct in_addr global_src;
1066 unsigned long best_match;
1067 GSList *routes_p;
1068
1069 /* Check if global_source_addr in use. */
1070 gvm_source_addr (&global_src);
1071
1072 sin_dest_p = (struct sockaddr_in *) storage_dest;
1073 sin_src_p = (struct sockaddr_in *) storage_source;
1074 /* Check routes for matching address. Get interface name and set
1075 * storage_source*/
1076 for (best_match = 0, routes_p = routes; routes_p;
1077 routes_p = routes_p->next)
1078 {
1079 if (((sin_dest_p->sin_addr.s_addr
1080 & ((route_entry_t *) (routes_p->data))->mask)
1081 == ((route_entry_t *) (routes_p->data))->dest)
1082 && (((route_entry_t *) (routes_p->data))->mask >= best_match))
1083 {
1084 /* Interface of matching route.*/
1085 g_free (interface_out);
1086 interface_out =
1087 g_strdup (((route_entry_t *) (routes_p->data))->interface);
1088 best_match = ((route_entry_t *) (routes_p->data))->mask;
1089
1090 if (!storage_source)
1091 continue;
1092
1093 /* Set storage_source to global source if global source
1094 * present.*/
1095 if (global_src.s_addr != INADDR_ANY)
1096 sin_src_p->sin_addr.s_addr = global_src.s_addr;
1097 /* Set storage_source to addr of matching interface if no
1098 * global source present.*/
1099 else
1100 {
1101 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1102 {
1103 if (ifa->ifa_addr
1104 && (ifa->ifa_addr->sa_family == AF_INET)
1105 && (g_strcmp0 (interface_out, ifa->ifa_name)
1106 == 0))
1107 {
1108 sin_src_p->sin_addr.s_addr =
1109 ((struct sockaddr_in *) (ifa->ifa_addr))
1110 ->sin_addr.s_addr;
1111 break;
1112 }
1113 }
1114 }
1115 }
1116 }
1117 }
1118 free_routes (routes);
1119 }
1120 else if (storage_dest->ss_family == AF_INET6)
1121 {
1122 g_warning ("%s: IPv6 not yet implemented for this function. Will be "
1123 "implemented soon. Thanks for your patience.",
1124 __func__);
1125 }
1126
1127 freeifaddrs (ifaddr);
1128 return interface_out != NULL ? interface_out : NULL;
1129}
1130
1138static int
1139get_connected_udp_sock (struct sockaddr_storage *target_addr)
1140{
1141 int family = target_addr->ss_family;
1142 int sockfd = -1;
1143 if (family == AF_INET)
1144 {
1145 sockfd = socket (AF_INET, SOCK_DGRAM, 0);
1146 if (sockfd < 0)
1147 {
1148 g_warning ("Socket error: %s", strerror (errno));
1149 return -1;
1150 }
1151
1152 ((struct sockaddr_in *) target_addr)->sin_port = htons (9877);
1153 if (connect (sockfd, (struct sockaddr *) target_addr,
1154 sizeof (struct sockaddr_in))
1155 < 0)
1156 {
1157 g_warning ("Connect error: %s", strerror (errno));
1158 close (sockfd);
1159 return -1;
1160 }
1161 }
1162 else if (family == AF_INET6)
1163 {
1164 sockfd = socket (AF_INET6, SOCK_DGRAM, 0);
1165 if (sockfd < 0)
1166 {
1167 g_warning ("Socket error: %s", strerror (errno));
1168 return -1;
1169 }
1170 ((struct sockaddr_in6 *) target_addr)->sin6_port = htons (9877);
1171 if (connect (sockfd, (struct sockaddr *) target_addr,
1172 sizeof (struct sockaddr_in6))
1173 < 0)
1174 {
1175 g_warning ("Connect error: %s", strerror (errno));
1176 close (sockfd);
1177 return -1;
1178 }
1179 }
1180 return sockfd;
1181}
1182
1191static int
1192get_sock_addr (int sockfd, struct sockaddr_storage *sock_addr)
1193{
1194 socklen_t len;
1195 int family = sock_addr->ss_family;
1196 if (family == AF_INET)
1197 {
1198 len = sizeof (struct sockaddr_in);
1199 if (getsockname (sockfd, (struct sockaddr *) sock_addr, &len) < 0)
1200 {
1201 g_warning ("getsockname error: %s", strerror (errno));
1202 close (sockfd);
1203 return -1;
1204 }
1205 }
1206 else if (family == AF_INET6)
1207 {
1208 len = sizeof (struct sockaddr_in6);
1209 if (getsockname (sockfd, (struct sockaddr *) sock_addr, &len) < 0)
1210 {
1211 g_warning ("getsockname error:%s", strerror (errno));
1212 close (sockfd);
1213 return -1;
1214 }
1215 }
1216 return 0;
1217}
1218
1227static char *
1228get_ifname_from_ifaddr (struct sockaddr_storage *target_addr)
1229{
1230 struct ifaddrs *ifaddr, *ifa;
1231 int family = target_addr->ss_family;
1232 char *interface_out = NULL;
1233
1234 if (getifaddrs (&ifaddr) == -1)
1235 {
1236 g_warning ("%s: getifaddr failed: %s", __func__, strerror (errno));
1237 return NULL;
1238 }
1239 if (family == AF_INET)
1240 {
1241 struct sockaddr_in *sin;
1242 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1243 {
1244 if (!(ifa->ifa_flags & IFF_UP))
1245 continue;
1246 if (ifa->ifa_addr == NULL)
1247 continue;
1248 if (ifa->ifa_addr->sa_family == AF_INET)
1249 {
1250 sin = (struct sockaddr_in *) (ifa->ifa_addr);
1251 if (((struct sockaddr_in *) target_addr)->sin_addr.s_addr
1252 == sin->sin_addr.s_addr)
1253 interface_out = g_strdup (ifa->ifa_name);
1254 }
1255 }
1256 }
1257 else if (family == AF_INET6)
1258 {
1259 struct sockaddr_in6 *sin6;
1260 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1261 {
1262 if (!(ifa->ifa_flags & IFF_UP))
1263 continue;
1264 if (ifa->ifa_addr == NULL)
1265 continue;
1266 if (ifa->ifa_addr->sa_family == AF_INET6)
1267 {
1268 sin6 = (struct sockaddr_in6 *) (ifa->ifa_addr);
1269 if (IN6_ARE_ADDR_EQUAL (
1270 &(sin6->sin6_addr),
1271 &((struct sockaddr_in6 *) target_addr)->sin6_addr))
1272 interface_out = g_strdup (ifa->ifa_name);
1273 }
1274 }
1275 }
1276 freeifaddrs (ifaddr);
1277 return interface_out;
1278}
1279
1296char *
1297gvm_get_outgoing_iface (struct sockaddr_storage *target_addr)
1298{
1299 int family, sockfd;
1300 struct sockaddr_storage out_iface_addr;
1301 char *out_iface_str;
1302
1303 out_iface_str = NULL;
1304 family = target_addr->ss_family;
1305
1306 if (!target_addr)
1307 return NULL;
1308
1309 // get a connected udp socket
1310 sockfd = get_connected_udp_sock (target_addr);
1311 if (sockfd < 0)
1312 return NULL;
1313 // get socked address which is the addr of the interface we want to get
1314 out_iface_addr.ss_family = family;
1315 if (get_sock_addr (sockfd, &out_iface_addr) < 0)
1316 return NULL;
1317 // get interface name form interface address
1318 out_iface_str = get_ifname_from_ifaddr (&out_iface_addr);
1319 return out_iface_str;
1320}
make_array
GPtrArray * make_array(void)
Make a global array.
Definition array.c:25
array_add
void array_add(array_t *array, gpointer pointer)
Push a generic pointer onto an array.
Definition array.c:68
array_t
GPtrArray array_t
Definition array.h:16
addr6_to_str
void addr6_to_str(const struct in6_addr *addr6, char *str)
Stringifies an IP address.
Definition networking.c:261
free_routes
static void free_routes(GSList *routes)
Free the list of routes.
Definition networking.c:987
ipv6_is_enabled
int ipv6_is_enabled(void)
Checks if IPv6 support is enabled.
Definition networking.c:752
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
get_connected_udp_sock
static int get_connected_udp_sock(struct sockaddr_storage *target_addr)
Get a connected UDP socket.
Definition networking.c:1139
global_source_addr6
struct in6_addr global_source_addr6
Definition networking.c:52
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:1297
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
gvm_source_addr6
void gvm_source_addr6(void *addr6)
Gives the source IPv6 address.
Definition networking.c:186
gvm_source_addr
void gvm_source_addr(void *addr)
Gives the source IPv4 address.
Definition networking.c:174
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
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
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:1192
ip_islocalhost
static gboolean ip_islocalhost(struct sockaddr_storage *storage)
Determine if IP is localhost.
Definition networking.c:775
route_entry_t
struct route_entry route_entry_t
Definition networking.c:862
global_source_iface
char global_source_iface[IFNAMSIZ]
Definition networking.c:46
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:1228
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
validate_port_range
int validate_port_range(const char *port_range)
Validate a port range string.
Definition networking.c:460
addr6_as_str
char * addr6_as_str(const struct in6_addr *addr6)
Stringifies an IP address.
Definition networking.c:279
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
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
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:1017
gvm_source_addr6_str
char * gvm_source_addr6_str(void)
Gives the source IPv6 address in string format.
Definition networking.c:225
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
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
global_source_addr
struct in_addr global_source_addr
Definition networking.c:49
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_iface_is_set
int gvm_source_iface_is_set(void)
Check if global_source global_source_iface is set.
Definition networking.c:121
gvm_source_addr_str
char * gvm_source_addr_str(void)
Gives the source IPv4 address in string format.
Definition networking.c:211
get_routes
static GSList * get_routes(void)
Get the entries of /proc/net/route as list of route_entry structs.
Definition networking.c:878
networking.h
GVM Networking related API.
port_protocol_t
port_protocol_t
Possible port types.
Definition networking.h:25
PORT_PROTOCOL_TCP
@ PORT_PROTOCOL_TCP
Definition networking.h:26
PORT_PROTOCOL_UDP
@ PORT_PROTOCOL_UDP
Definition networking.h:27
range_t
struct range range_t
Definition networking.h:43
range
A port range.
Definition networking.h:35
range::start
int start
Definition networking.h:40
range::exclude
int exclude
Definition networking.h:39
range::type
port_protocol_t type
Definition networking.h:41
range::end
int end
Definition networking.h:38
route_entry
Definition networking.c:866
route_entry::dest
unsigned long dest
Definition networking.c:869
route_entry::mask
unsigned long mask
Definition networking.c:868
route_entry::interface
gchar * interface
Definition networking.c:867