networking.c
Go to the documentation of this file.
/* SPDX-FileCopyrightText: 2013-2023 Greenbone AG
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "networking.h"
#include <arpa/inet.h> /* for inet_ntop */
#include <assert.h> /* for assert */
#include <ctype.h> /* for isblank */
#include <errno.h> /* for errno, EAFNOSUPPORT */
#include <glib/gstdio.h>
#include <ifaddrs.h> /* for ifaddrs, freeifaddrs, getifaddrs */
#include <net/if.h> /* for IFNAMSIZ */
#include <stdint.h> /* for uint32_t, uint8_t */
#include <stdlib.h> /* for atoi, strtol */
#include <string.h> /* for memcpy, bzero, strchr, strlen, strcmp, strncpy */
#include <sys/socket.h> /* for AF_INET, AF_INET6, AF_UNSPEC, sockaddr_storage */
#include <unistd.h> /* for close */
#ifdef __FreeBSD__
#include <netinet/in.h>
#define s6_addr32 __u6_addr.__u6_addr32
#endif
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "libgvm base"
#if GLIB_CHECK_VERSION(2, 67, 3)
#define memdup g_memdup2
#else
#define memdup g_memdup
#endif
/* Global variables */
/* Source interface name eg. eth1. */
char global_source_iface[IFNAMSIZ] = {'\0'};
/* Source IPv4 address. */
struct in_addr global_source_addr = {.s_addr = 0};
/* Source IPv6 address. */
struct in6_addr global_source_addr6 = {.s6_addr32 = {0, 0, 0, 0}};
/* Source Interface/Address related functions. */
int
gvm_source_iface_init (const char *iface)
{
struct ifaddrs *ifaddr, *ifa;
int ret = 1;
bzero (global_source_iface, sizeof (global_source_iface));
global_source_addr.s_addr = INADDR_ANY;
global_source_addr6 = in6addr_any;
if (iface == NULL)
return ret;
if (strlen (iface) >= sizeof (global_source_iface))
return ret;
if (getifaddrs (&ifaddr) == -1)
return ret;
/* Search for the adequate interface/family. */
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr && strcmp (iface, ifa->ifa_name) == 0)
{
if (ifa->ifa_addr->sa_family == AF_INET)
{
struct in_addr *addr =
&((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
memcpy (&global_source_addr, addr, sizeof (global_source_addr));
ret = 0;
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
struct sockaddr_in6 *addr;
addr = (struct sockaddr_in6 *) ifa->ifa_addr;
memcpy (&global_source_addr6.s6_addr, &addr->sin6_addr,
sizeof (struct in6_addr));
ret = 0;
}
}
}
/* At least one address for the interface was found. */
if (ret == 0)
memcpy (global_source_iface, iface, strlen (iface));
freeifaddrs (ifaddr);
return ret;
}
int
gvm_source_iface_is_set (void)
{
return *global_source_iface != '\0';
}
int
gvm_source_set_socket (int socket, int port, int family)
{
if (family == AF_INET)
{
struct sockaddr_in addr;
bzero (&addr, sizeof (addr));
gvm_source_addr (&addr.sin_addr);
addr.sin_port = htons (port);
addr.sin_family = AF_INET;
if (bind (socket, (struct sockaddr *) &addr, sizeof (addr)) < 0)
return -1;
}
else if (family == AF_INET6)
{
struct sockaddr_in6 addr6;
bzero (&addr6, sizeof (addr6));
gvm_source_addr6 (&addr6.sin6_addr);
addr6.sin6_port = htons (port);
addr6.sin6_family = AF_INET6;
if (bind (socket, (struct sockaddr *) &addr6, sizeof (addr6)) < 0)
return -1;
}
else
return -1;
return 0;
}
void
gvm_source_addr (void *addr)
{
if (addr)
memcpy (addr, &global_source_addr.s_addr, 4);
}
void
gvm_source_addr6 (void *addr6)
{
if (addr6)
memcpy (addr6, &global_source_addr6.s6_addr, 16);
}
void
gvm_source_addr_as_addr6 (struct in6_addr *addr6)
{
if (addr6)
ipv4_as_ipv6 (&global_source_addr, addr6);
}
char *
gvm_source_addr_str (void)
{
char *str = g_malloc0 (INET_ADDRSTRLEN);
inet_ntop (AF_INET, &global_source_addr.s_addr, str, INET_ADDRSTRLEN);
return str;
}
char *
gvm_source_addr6_str (void)
{
char *str = g_malloc0 (INET6_ADDRSTRLEN);
inet_ntop (AF_INET6, &global_source_addr6, str, INET6_ADDRSTRLEN);
return str;
}
/* Miscellaneous functions. */
void
ipv4_as_ipv6 (const struct in_addr *ip4, struct in6_addr *ip6)
{
if (ip4 == NULL || ip6 == NULL)
return;
ip6->s6_addr32[0] = 0;
ip6->s6_addr32[1] = 0;
ip6->s6_addr32[2] = htonl (0xffff);
memcpy (&ip6->s6_addr32[3], ip4, sizeof (struct in_addr));
}
void
addr6_to_str (const struct in6_addr *addr6, char *str)
{
if (!addr6)
return;
if (IN6_IS_ADDR_V4MAPPED (addr6))
inet_ntop (AF_INET, &addr6->s6_addr32[3], str, INET6_ADDRSTRLEN);
else
inet_ntop (AF_INET6, addr6, str, INET6_ADDRSTRLEN);
}
char *
addr6_as_str (const struct in6_addr *addr6)
{
char *str;
if (!addr6)
return NULL;
str = g_malloc0 (INET6_ADDRSTRLEN);
addr6_to_str (addr6, str);
return str;
}
void
sockaddr_as_str (const struct sockaddr_storage *addr, char *str)
{
if (!addr || !str)
return;
if (addr->ss_family == AF_INET)
{
struct sockaddr_in *saddr = (struct sockaddr_in *) addr;
inet_ntop (AF_INET, &saddr->sin_addr, str, INET6_ADDRSTRLEN);
}
else if (addr->ss_family == AF_INET6)
{
struct sockaddr_in6 *s6addr = (struct sockaddr_in6 *) addr;
if (IN6_IS_ADDR_V4MAPPED (&s6addr->sin6_addr))
inet_ntop (AF_INET, &s6addr->sin6_addr.s6_addr[12], str,
INET6_ADDRSTRLEN);
else
inet_ntop (AF_INET6, &s6addr->sin6_addr, str, INET6_ADDRSTRLEN);
}
else if (addr->ss_family == AF_UNIX)
{
g_snprintf (str, INET6_ADDRSTRLEN, "unix_socket");
}
else if (addr->ss_family == AF_UNSPEC)
{
g_snprintf (str, INET6_ADDRSTRLEN, "unknown_socket");
}
else
{
g_snprintf (str, INET6_ADDRSTRLEN, "type_%d_socket", addr->ss_family);
}
}
GSList *
gvm_resolve_list (const char *name)
{
struct addrinfo hints, *info, *p;
GSList *list = NULL;
if (name == NULL)
return NULL;
bzero (&hints, sizeof (hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
return NULL;
p = info;
while (p)
{
struct in6_addr dst;
if (p->ai_family == AF_INET)
{
struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
ipv4_as_ipv6 (&(addrin->sin_addr), &dst);
list = g_slist_prepend (list, memdup (&dst, sizeof (dst)));
}
else if (p->ai_family == AF_INET6)
{
struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
memcpy (&dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
list = g_slist_prepend (list, memdup (&dst, sizeof (dst)));
}
p = p->ai_next;
}
freeaddrinfo (info);
return list;
}
int
gvm_resolve (const char *name, void *dst, int family)
{
struct addrinfo hints, *info, *p;
if (name == NULL || dst == NULL
|| (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
return -1;
bzero (&hints, sizeof (hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
return -1;
p = info;
while (p)
{
if (p->ai_family == family || family == AF_UNSPEC)
{
if (p->ai_family == AF_INET && family == AF_UNSPEC)
{
struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
ipv4_as_ipv6 (&(addrin->sin_addr), dst);
}
else if (p->ai_family == AF_INET)
{
struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
memcpy (dst, &(addrin->sin_addr), sizeof (struct in_addr));
}
else if (p->ai_family == AF_INET6)
{
struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
memcpy (dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
}
break;
}
p = p->ai_next;
}
freeaddrinfo (info);
return 0;
}
int
gvm_resolve_as_addr6 (const char *name, struct in6_addr *ip6)
{
return gvm_resolve (name, ip6, AF_UNSPEC);
}
/* Ports related. */
int
validate_port_range (const char *port_range)
{
gchar **split, **point, *range, *range_start;
if (!port_range)
return 1;
while (*port_range && isblank (*port_range))
port_range++;
if (*port_range == '\0')
return 1;
/* Treat newlines like commas. */
range = range_start = g_strdup (port_range);
while (*range)
{
if (*range == '\n')
*range = ',';
range++;
}
split = g_strsplit (range_start, ",", 0);
g_free (range_start);
point = split;
while (*point)
{
gchar *hyphen, *element;
/* Strip off any outer whitespace. */
element = g_strstrip (*point);
/* Strip off any leading type specifier and following whitespace. */
if ((strlen (element) >= 2)
&& ((element[0] == 'T') || (element[0] == 'U')))
{
element++;
while (*element && isblank (*element))
element++;
if (*element == ':')
element++;
}
/* Look for a hyphen. */
hyphen = strchr (element, '-');
if (hyphen)
{
long int number1, number2;
const char *first;
char *end;
hyphen++;
/* Check the first number. */
first = element;
while (*first && isblank (*first))
first++;
if (*first == '-')
goto fail;
errno = 0;
number1 = strtol (first, &end, 10);
while (*end && isblank (*end))
end++;
if (errno || (*end != '-'))
goto fail;
if (number1 == 0)
goto fail;
if (number1 > 65535)
goto fail;
/* Check the second number. */
while (*hyphen && isblank (*hyphen))
hyphen++;
if (*hyphen == '\0')
goto fail;
errno = 0;
number2 = strtol (hyphen, &end, 10);
while (*end && isblank (*end))
end++;
if (errno || *end)
goto fail;
if (number2 == 0)
goto fail;
if (number2 > 65535)
goto fail;
if (number1 > number2)
goto fail;
}
else
{
long int number;
const char *only;
char *end;
/* Check the single number. */
only = element;
while (*only && isblank (*only))
only++;
/* Empty ranges are OK. */
if (*only)
{
errno = 0;
number = strtol (only, &end, 10);
while (*end && isblank (*end))
end++;
if (errno || *end)
goto fail;
if (number == 0)
goto fail;
if (number > 65535)
goto fail;
}
}
point += 1;
}
g_strfreev (split);
return 0;
fail:
g_strfreev (split);
return 1;
}
array_t *
port_range_ranges (const char *port_range)
{
gchar **split, **point, *range_start, *current;
array_t *ranges;
int tcp, err;
if (!port_range)
return NULL;
/* port_range needs to be a valid port_range string. */
err = validate_port_range (port_range);
if (err)
return NULL;
ranges = make_array ();
while (*port_range && isblank (*port_range))
port_range++;
/* Accepts T: and U: before any of the ranges. This toggles the remaining
* ranges, as in nmap. Treats a leading naked range as TCP, whereas nmap
* treats it as TCP and UDP. */
/* Treat newlines like commas. */
range_start = current = g_strdup (port_range);
while (*current)
{
if (*current == '\n')
*current = ',';
current++;
}
tcp = 1;
split = g_strsplit (range_start, ",", 0);
g_free (range_start);
point = split;
while (*point)
{
gchar *hyphen, *element;
range_t *range;
int element_strlen;
element = g_strstrip (*point);
element_strlen = strlen (element);
if (element_strlen >= 2)
{
if (element[0] == 'T')
{
element++;
while (*element && isblank (*element))
element++;
if (*element == ':')
{
element++;
tcp = 1;
}
}
else if (element[0] == 'U')
{
element++;
while (*element && isblank (*element))
element++;
if (*element == ':')
{
element++;
tcp = 0;
}
}
/* Else tcp stays as it is. */
}
/* Skip any space that followed the type specifier. */
while (*element && isblank (*element))
element++;
hyphen = strchr (element, '-');
if (hyphen)
{
*hyphen = '\0';
hyphen++;
while (*hyphen && isblank (*hyphen))
hyphen++;
assert (*hyphen); /* Validation checks this. */
/* A range. */
range = (range_t *) g_malloc0 (sizeof (range_t));
range->start = atoi (element);
range->end = atoi (hyphen);
range->type = tcp ? PORT_PROTOCOL_TCP : PORT_PROTOCOL_UDP;
range->exclude = 0;
array_add (ranges, range);
}
else if (*element)
{
/* A single port. */
range = (range_t *) g_malloc0 (sizeof (range_t));
range->start = atoi (element);
range->end = range->start;
range->type = tcp ? PORT_PROTOCOL_TCP : PORT_PROTOCOL_UDP;
range->exclude = 0;
array_add (ranges, range);
}
/* Else skip over empty range. */
point += 1;
}
g_strfreev (split);
return ranges;
}
int
port_in_port_ranges (int pnum, port_protocol_t ptype, array_t *pranges)
{
unsigned int i;
if (pranges == NULL || pnum < 0 || pnum > 65536)
return 0;
for (i = 0; i < pranges->len; i++)
{
range_t *range = (range_t *) g_ptr_array_index (pranges, i);
if (range->type != ptype)
continue;
if (range->start <= pnum && pnum <= range->end)
return 1;
}
return 0;
}
int
ipv6_is_enabled (void)
{
int sock = socket (PF_INET6, SOCK_STREAM, 0);
if (sock < 0)
{
if (errno == EAFNOSUPPORT)
return 0;
}
else
close (sock);
return 1;
}
/* Functions used by alive detection module (Boreas). */
static gboolean
ip_islocalhost (struct sockaddr_storage *storage)
{
struct in_addr addr;
struct in_addr *addr_p;
struct in6_addr addr6 = IN6ADDR_ANY_INIT;
struct in6_addr *addr6_p;
struct sockaddr_in *sin_p;
struct sockaddr_in6 *sin6_p;
struct ifaddrs *ifaddr, *ifa;
int family;
family = storage->ss_family;
addr6_p = &addr6;
addr_p = &addr;
addr.s_addr = 0;
if (family == AF_INET)
{
sin_p = (struct sockaddr_in *) storage;
addr = sin_p->sin_addr;
if (addr_p == NULL)
return FALSE;
/* addr is 0.0.0.0 */
if ((addr_p)->s_addr == 0)
return TRUE;
/* addr starts with 127.0.0.1 */
if (((addr_p)->s_addr & htonl (0xFF000000)) == htonl (0x7F000000))
return TRUE;
}
if (family == AF_INET6)
{
sin6_p = (struct sockaddr_in6 *) storage;
addr6 = sin6_p->sin6_addr;
if (IN6_IS_ADDR_V4MAPPED (&addr6))
{
/* addr is 0.0.0.0 */
if (addr6_p->s6_addr32[3] == 0)
return 1;
/* addr starts with 127.0.0.1 */
if ((addr6_p->s6_addr32[3] & htonl (0xFF000000))
== htonl (0x7F000000))
return 1;
}
if (IN6_IS_ADDR_LOOPBACK (addr6_p))
return 1;
}
if (getifaddrs (&ifaddr) == -1)
{
g_debug ("%s: getifaddr failed: %s", __func__, strerror (errno));
return FALSE;
}
else
{
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
sin = (struct sockaddr_in *) (ifa->ifa_addr);
/* Check if same address as local interface. */
if (addr_p->s_addr == sin->sin_addr.s_addr)
return TRUE;
}
if (ifa->ifa_addr->sa_family == AF_INET6)
{
sin6 = (struct sockaddr_in6 *) (ifa->ifa_addr);
/* Check if same address as local interface. */
if (family == AF_INET6
&& IN6_ARE_ADDR_EQUAL (&(sin6->sin6_addr), addr6_p))
return TRUE;
}
}
freeifaddrs (ifaddr);
}
return FALSE;
}
typedef struct route_entry route_entry_t;
struct route_entry
{
gchar *interface;
unsigned long mask;
unsigned long dest;
};
static GSList *
get_routes (void)
{
GSList *routes;
GError *err;
GIOChannel *file_channel;
gchar *line;
gchar **items_in_line;
int status;
route_entry_t *entry;
err = NULL;
routes = NULL;
line = NULL;
/* Open "/proc/net/route". */
file_channel = g_io_channel_new_file ("/proc/net/route", "r", &err);
if (file_channel == NULL)
{
g_warning ("%s: %s. ", __func__,
err ? err->message : "Error opening /proc/net/ipv6_route");
err = NULL;
return NULL;
}
/* Skip first first line of file. */
status = g_io_channel_read_line (file_channel, &line, NULL, NULL, &err);
if (status != G_IO_STATUS_NORMAL || !line || err)
{
g_warning ("%s: %s", __func__,
err ? err->message
: "g_io_channel_read_line() status != G_IO_STATUS_NORMAL");
err = NULL;
}
g_free (line);
/* Until EOF or err we go through lines of file and extract Iface, Mask and
* Destination and put it into the to be returned list of routes.*/
while (1)
{
gchar *interface, *char_p;
unsigned long mask, dest;
int count;
/* Get new line. */
line = NULL;
status = g_io_channel_read_line (file_channel, &line, NULL, NULL, &err);
if ((status != G_IO_STATUS_NORMAL) || !line || err)
{
if (status == G_IO_STATUS_AGAIN)
g_warning ("%s: /proc/net/route unavailable.", __func__);
if (err || status == G_IO_STATUS_ERROR)
g_warning (
"%s: %s", __func__,
err ? err->message
: "g_io_channel_read_line() status == G_IO_STATUS_ERROR");
err = NULL;
g_free (line);
break;
}
/* Get items in line. */
items_in_line = g_strsplit (line, "\t", -1);
/* Check for missing entries in line of "/proc/net/route". */
for (count = 0; items_in_line[count]; count++)
;
if (11 != count)
{
g_strfreev (items_in_line);
g_free (line);
continue;
}
interface = g_strndup (items_in_line[0], 64);
/* Cut interface str after ":" if IP aliasing is used. */
char_p = strchr (interface, ':');
if (char_p)
{
*char_p = '\0';
}
dest = strtoul (items_in_line[1], NULL, 16);
mask = strtoul (items_in_line[7], NULL, 16);
/* Fill GSList entry. */
entry = g_malloc0 (sizeof (route_entry_t));
entry->interface = interface;
entry->dest = dest;
entry->mask = mask;
routes = g_slist_append (routes, entry);
g_strfreev (items_in_line);
g_free (line);
}
status = g_io_channel_shutdown (file_channel, TRUE, &err);
if ((G_IO_STATUS_NORMAL != status) || err)
g_warning ("%s: %s", __func__,
err ? err->message
: "g_io_channel_shutdown() was not successful");
return routes;
}
gchar *
gvm_routethrough (struct sockaddr_storage *storage_dest,
struct sockaddr_storage *storage_source)
{
struct ifaddrs *ifaddr, *ifa;
gchar *interface_out;
interface_out = NULL;
if (!storage_dest)
return NULL;
if (getifaddrs (&ifaddr) == -1)
{
g_debug ("%s: getifaddr failed: %s", __func__, strerror (errno));
return NULL;
}
/* IPv4. */
if (storage_dest->ss_family == AF_INET)
{
GSList *routes;
GSList *routes_p;
routes = get_routes ();
/* Set storage_source to localhost if storage_source was supplied and
* return name of loopback interface. */
if (ip_islocalhost (storage_dest))
{
// TODO: check for (storage_source->ss_family == AF_INET)
if (storage_source)
{
struct sockaddr_in *sin_p = (struct sockaddr_in *) storage_source;
sin_p->sin_addr.s_addr = htonl (0x7F000001);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_INET)
&& (ifa->ifa_flags & (IFF_LOOPBACK)))
{
interface_out = g_strdup (ifa->ifa_name);
break;
}
}
}
else
{
struct sockaddr_in *sin_dest_p, *sin_src_p;
struct in_addr global_src;
unsigned long best_match;
/* Check if global_source_addr in use. */
gvm_source_addr (&global_src);
sin_dest_p = (struct sockaddr_in *) storage_dest;
sin_src_p = (struct sockaddr_in *) storage_source;
/* Check routes for matching address. Get interface name and set
* storage_source*/
for (best_match = 0, routes_p = routes; routes_p;
routes_p = routes_p->next)
{
if (((sin_dest_p->sin_addr.s_addr
& ((route_entry_t *) (routes_p->data))->mask)
== ((route_entry_t *) (routes_p->data))->dest)
&& (((route_entry_t *) (routes_p->data))->mask >= best_match))
{
/* Interface of matching route.*/
g_free (interface_out);
interface_out =
g_strdup (((route_entry_t *) (routes_p->data))->interface);
best_match = ((route_entry_t *) (routes_p->data))->mask;
if (!storage_source)
continue;
/* Set storage_source to global source if global source
* present.*/
if (global_src.s_addr != INADDR_ANY)
sin_src_p->sin_addr.s_addr = global_src.s_addr;
/* Set storage_source to addr of matching interface if no
* global source present.*/
else
{
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr
&& (ifa->ifa_addr->sa_family == AF_INET)
&& (g_strcmp0 (interface_out, ifa->ifa_name)
== 0))
{
sin_src_p->sin_addr.s_addr =
((struct sockaddr_in *) (ifa->ifa_addr))
->sin_addr.s_addr;
break;
}
}
}
}
}
}
/* Free GSList. */
if (routes)
{
for (routes_p = routes; routes_p; routes_p = routes_p->next)
{
if (((route_entry_t *) (routes_p->data))->interface)
g_free (((route_entry_t *) (routes_p->data))->interface);
}
g_slist_free (routes);
}
}
else if (storage_dest->ss_family == AF_INET6)
{
g_warning ("%s: IPv6 not yet implemented for this function. Will be "
"implemented soon. Thanks for your patience.",
__func__);
}
return interface_out != NULL ? interface_out : NULL;
}
static int
get_connected_udp_sock (struct sockaddr_storage *target_addr)
{
int family = target_addr->ss_family;
int sockfd = -1;
if (family == AF_INET)
{
sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
g_warning ("Socket error: %s", strerror (errno));
return -1;
}
((struct sockaddr_in *) target_addr)->sin_port = htons (9877);
if (connect (sockfd, (struct sockaddr *) target_addr,
sizeof (struct sockaddr_in))
< 0)
{
g_warning ("Connect error: %s", strerror (errno));
close (sockfd);
return -1;
}
}
else if (family == AF_INET6)
{
sockfd = socket (AF_INET6, SOCK_DGRAM, 0);
if (sockfd < 0)
{
g_warning ("Socket error: %s", strerror (errno));
return -1;
}
((struct sockaddr_in6 *) target_addr)->sin6_port = htons (9877);
if (connect (sockfd, (struct sockaddr *) target_addr,
sizeof (struct sockaddr_in6))
< 0)
{
g_warning ("Connect error: %s", strerror (errno));
close (sockfd);
return -1;
}
}
return sockfd;
}
static int
get_sock_addr (int sockfd, struct sockaddr_storage *sock_addr)
{
socklen_t len;
int family = sock_addr->ss_family;
if (family == AF_INET)
{
len = sizeof (struct sockaddr_in);
if (getsockname (sockfd, (struct sockaddr *) sock_addr, &len) < 0)
{
g_warning ("getsockname error: %s", strerror (errno));
close (sockfd);
return -1;
}
}
else if (family == AF_INET6)
{
len = sizeof (struct sockaddr_in6);
if (getsockname (sockfd, (struct sockaddr *) sock_addr, &len) < 0)
{
g_warning ("getsockname error:%s", strerror (errno));
close (sockfd);
return -1;
}
}
return 0;
}
static char *
get_ifname_from_ifaddr (struct sockaddr_storage *target_addr)
{
struct ifaddrs *ifaddr, *ifa;
int family = target_addr->ss_family;
char *interface_out = NULL;
if (getifaddrs (&ifaddr) == -1)
{
g_warning ("%s: getifaddr failed: %s", __func__, strerror (errno));
return NULL;
}
if (family == AF_INET)
{
struct sockaddr_in *sin;
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (!(ifa->ifa_flags & IFF_UP))
continue;
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
sin = (struct sockaddr_in *) (ifa->ifa_addr);
if (((struct sockaddr_in *) target_addr)->sin_addr.s_addr
== sin->sin_addr.s_addr)
interface_out = g_strdup (ifa->ifa_name);
}
}
}
else if (family == AF_INET6)
{
struct sockaddr_in6 *sin6;
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (!(ifa->ifa_flags & IFF_UP))
continue;
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_INET6)
{
sin6 = (struct sockaddr_in6 *) (ifa->ifa_addr);
if (IN6_ARE_ADDR_EQUAL (
&(sin6->sin6_addr),
&((struct sockaddr_in6 *) target_addr)->sin6_addr))
interface_out = g_strdup (ifa->ifa_name);
}
}
}
freeifaddrs (ifaddr);
return interface_out;
}
char *
gvm_get_outgoing_iface (struct sockaddr_storage *target_addr)
{
int family, sockfd;
struct sockaddr_storage out_iface_addr;
char *out_iface_str;
out_iface_str = NULL;
family = target_addr->ss_family;
if (!target_addr)
return NULL;
// get a connected udp socket
sockfd = get_connected_udp_sock (target_addr);
if (sockfd < 0)
return NULL;
// get socked address which is the addr of the interface we want to get
out_iface_addr.ss_family = family;
if (get_sock_addr (sockfd, &out_iface_addr) < 0)
return NULL;
// get interface name form interface address
out_iface_str = get_ifname_from_ifaddr (&out_iface_addr);
return out_iface_str;
}
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
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:1125
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:1283
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:1178
ip_islocalhost
static gboolean ip_islocalhost(struct sockaddr_storage *storage)
Determine if IP is localhost.
Definition networking.c:775
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:1214
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:995
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
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