Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get interface used for routing to given destination #339

Merged
merged 12 commits into from
May 28, 2020
189 changes: 189 additions & 0 deletions base/networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,3 +762,192 @@ ipv6_is_enabled ()

return 1;
}

gboolean
ip_islocalhost (struct sockaddr_storage *storage)
{
struct in_addr addr;
struct in_addr *addr_p = &addr;
struct in6_addr addr6;
struct in6_addr *addr6_p = &addr6;
struct sockaddr_in *sin_p;
struct sockaddr_in6 *sin6_p;
struct ifaddrs *ifaddr = NULL;
struct ifaddrs *ifa = NULL;
int family;

family = storage->ss_family;

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 (IN6_ARE_ADDR_EQUAL (&(sin6->sin6_addr), addr6_p))
return TRUE;
}
}
freeifaddrs (ifaddr);
}

return FALSE;
}


struct proc_entry
{
gchar *interface;
unsigned long mask;
unsigned long dest;
};
static GSList *
get_routes (void)
{
GSList *proc_routes = NULL;
mattmundell marked this conversation as resolved.
Show resolved Hide resolved
GError *err = NULL;
GIOChannel *mychannel;
gchar *line;
gchar **items_in_line;
int status;
struct proc_entry *entry;

/* Open "/proc/net/route". */
mychannel = g_io_channel_new_file ("/proc/net/route", "r", &err);
if (mychannel == 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 (mychannel, &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");
if (line)
g_free (line);
err = NULL;
}

/* Until EOF or err we go through lines of file and extract Iface, Mask and
* Destination and but it into the to be returned list of routes.*/
mattmundell marked this conversation as resolved.
Show resolved Hide resolved
while (1)
{
gchar *interface;
unsigned long mask;
unsigned long dest;
gchar *char_p;
int count = 0;

/* get new line */
status = g_io_channel_read_line (mychannel, &line, NULL, NULL, &err);
mattmundell marked this conversation as resolved.
Show resolved Hide resolved
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;
if (line)
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 (; 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. */
if ((char_p = strchr (interface, ':')))
{
*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 (struct proc_entry));
entry->interface = interface;
entry->dest = dest;
entry->mask = mask;
proc_routes = g_slist_append (proc_routes, entry);

g_strfreev (items_in_line);
if (line)
g_free (line);
}

status = g_io_channel_shutdown (mychannel, TRUE, &err);
if ((G_IO_STATUS_NORMAL != status) || err)
g_warning ("%s: %s", __func__,
err ? err->message
: "g_io_channel_shutdown() was not successfull");

return proc_routes;
}
87 changes: 87 additions & 0 deletions base/networking_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -935,12 +935,99 @@ Ensure (networking, port_in_port_ranges)

/* Test suite. */

Ensure (networking, ip_islocalhost)
{
cgreen_mocks_are (loose_mocks);

/* IPv4 */
struct in_addr addr;
struct sockaddr_storage storage;
struct sockaddr_in sin;
memset (&sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;

inet_pton (AF_INET, "127.0.0.1", &(addr.s_addr));
sin.sin_addr.s_addr = addr.s_addr;
memcpy (&storage, &sin, sizeof (sin));
assert_that (ip_islocalhost (&storage), is_true);

inet_pton (AF_INET, "0.0.0.0", &(addr.s_addr));
sin.sin_addr.s_addr = addr.s_addr;
memcpy (&storage, &sin, sizeof (sin));
assert_that (ip_islocalhost (&storage), is_true);

inet_pton (AF_INET, "127.100.5.99", &(addr.s_addr));
sin.sin_addr.s_addr = addr.s_addr;
memcpy (&storage, &sin, sizeof (sin));
assert_that (ip_islocalhost (&storage), is_true);

//!! local interface address
// inet_pton (AF_INET, <some local interface address>, &(addr.s_addr));
// sin.sin_addr.s_addr = addr.s_addr;
// memcpy (&storage, &sin, sizeof (sin));
// assert_that (ip_islocalhost (&storage), is_true);

/* example.com */
inet_pton (AF_INET, "93.184.216.34", &(addr.s_addr));
sin.sin_addr.s_addr = addr.s_addr;
memcpy (&storage, &sin, sizeof (sin));
assert_that (ip_islocalhost (&storage), is_false);

/* IPv6 */
struct in6_addr addr_6;
struct sockaddr_in6 sin6;
memset (&sin, 0, sizeof (struct sockaddr_in6));
sin6.sin6_family = AF_INET6;

inet_pton (AF_INET6, "::FFFF:127.0.0.1", &(addr_6));
sin6.sin6_addr = addr_6;
memcpy (&storage, &sin6, sizeof (sin6));
assert_that (ip_islocalhost (&storage), is_true);

inet_pton (AF_INET6, "::FFFF:0.0.0.0", &(addr_6));
sin6.sin6_addr = addr_6;
memcpy (&storage, &sin6, sizeof (sin6));
assert_that (ip_islocalhost (&storage), is_true);

inet_pton (AF_INET6, "::FFFF:127.100.5.99", &(addr_6));
sin6.sin6_addr = addr_6;
memcpy (&storage, &sin6, sizeof (sin6));
assert_that (ip_islocalhost (&storage), is_true);

/* loopback address */
inet_pton (AF_INET6, "0:0:0:0:0:0:0:1", &(addr_6));
sin6.sin6_addr = addr_6;
memcpy (&storage, &sin6, sizeof (sin6));
assert_that (ip_islocalhost (&storage), is_true);

/* dependent on local environment */
// inet_pton (AF_INET6, <some local interface address>, &(addr_6));
// sin6.sin6_addr = addr_6;
// memcpy (&storage, &sin6, sizeof (sin6));
// assert_that (ip_islocalhost (&storage), is_true);

/* example.com */
inet_pton (AF_INET6, "2606:2800:220:1:248:1893:25c8:1946", &(addr_6));
sin6.sin6_addr = addr_6;
memcpy (&storage, &sin6, sizeof (sin6));
assert_that (ip_islocalhost (&storage), is_false);
}

TestSuite *
gvm_routethough ()
{
TestSuite *suite = create_test_suite ();
add_test_with_context (suite, networking, ip_islocalhost);
return suite;
}

int
main (int argc, char **argv)
{
TestSuite *suite;

suite = create_test_suite ();
add_suite (suite, gvm_routethough ());

add_test_with_context (suite, networking, validate_port_range);
add_test_with_context (suite, networking, port_range_ranges);
Expand Down