Skip to content

Commit

Permalink
apparently on VPNs it's common for the gateway for a route to be outs…
Browse files Browse the repository at this point in the history
…ide of the netmask of the network it's a router for. fix that in get_gateway
  • Loading branch information
arvidn committed Feb 8, 2020
1 parent 6d5bdbd commit 0a4a06c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/enum_net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ int _System __libsocket_sysctl(int* mib, u_int namelen, void *oldp, size_t *oldl
// IPv6 gateways aren't addressed in the same network as the
// interface, but they are addressed by the local network address
// space. So this check only works for IPv4.
&& (!v4 || match_addr_mask(r.gateway, iface.interface_address, iface.netmask))
&& (!v4 || match_addr_mask(r.gateway, iface.interface_address, r.netmask))
// in case there are multiple networks on the same networking
// device, the source hint may be the only thing telling them
// apart
Expand Down
66 changes: 39 additions & 27 deletions test/test_enum_net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,21 +180,22 @@ TORRENT_TEST(build_netmask_unknown)
}

namespace {
ip_route rt(char const* ip, char const* device, char const* gateway)
ip_route rt(char const* ip, char const* device, char const* gateway, char const* mask)
{
ip_route ret;
ret.destination = address::from_string(ip);
ret.gateway = address::from_string(gateway);
ret.netmask = address::from_string(mask);
std::strncpy(ret.name, device, sizeof(ret.name));
ret.name[sizeof(ret.name) - 1] = '\0';
return ret;
}

ip_interface ip(char const* addr, char const* mask, char const* name)
ip_interface ip(char const* addr, char const* name)
{
ip_interface ret;
ret.interface_address = address::from_string(addr);
ret.netmask = address::from_string(mask);
ret.netmask = address::from_string("255.255.255.255");
std::strncpy(ret.name, name, sizeof(ret.name));
return ret;
}
Expand All @@ -203,70 +204,81 @@ namespace {
TORRENT_TEST(get_gateway_basic)
{
std::vector<ip_route> const routes = {
rt("0.0.0.0", "eth0", "192.168.0.1"),
rt("::", "eth0", "2a02::1234")
rt("0.0.0.0", "eth0", "192.168.0.1", "255.255.255.0"),
rt("::", "eth0", "2a02::1234", "ffff::")
};

TEST_CHECK(get_gateway(ip("192.168.0.130", "255.255.0.0", "eth0"), routes) == address::from_string("192.168.0.1"));
TEST_CHECK(get_gateway(ip("2a02::4567", "ffff::", "eth0"), routes) == address::from_string("2a02::1234"));
TEST_CHECK(get_gateway(ip("192.168.0.130", "eth0"), routes) == address::from_string("192.168.0.1"));
TEST_CHECK(get_gateway(ip("2a02::4567", "eth0"), routes) == address::from_string("2a02::1234"));

// the device name does not match the route
TEST_CHECK(get_gateway(ip("192.168.0.130", "255.255.0.0", "eth1"), routes) == none);
TEST_CHECK(get_gateway(ip("2a02::4567", "ffff::", "eth1"), routes) == none);
TEST_CHECK(get_gateway(ip("192.168.0.130", "eth1"), routes) == none);
TEST_CHECK(get_gateway(ip("2a02::4567", "eth1"), routes) == none);

// the gateway for the route is outside of this local network, it cannot be
// used for this network
TEST_CHECK(get_gateway(ip("192.168.1.130", "255.255.255.0", "eth0"), routes) == none);
TEST_CHECK(get_gateway(ip("192.168.1.130", "eth0"), routes) == none);

// for IPv6, the address family and device name matches, so it's a match
TEST_CHECK(get_gateway(ip("2a02:8000::0123:4567", "ffff:ffff::", "eth0"), routes) == address::from_string("2a02::1234"));
TEST_CHECK(get_gateway(ip("2a02:8000::0123:4567", "eth0"), routes) == address::from_string("2a02::1234"));
}

TORRENT_TEST(get_gateway_no_default_route)
{
std::vector<ip_route> const routes = {
rt("192.168.0.0", "eth0", "0.0.0.0"),
rt("2a02::", "eth0", "::")
rt("192.168.0.0", "eth0", "0.0.0.0", "0.0.0.0"),
rt("2a02::", "eth0", "::", "ffff::")
};

// no default route
TEST_CHECK(get_gateway(ip("192.168.1.130", "255.255.0.0", "eth0"), routes) == none);
TEST_CHECK(get_gateway(ip("2a02::1234", "ffff::", "eth0"), routes) == none);
TEST_CHECK(get_gateway(ip("192.168.1.130", "eth0"), routes) == none);
TEST_CHECK(get_gateway(ip("2a02::1234", "eth0"), routes) == none);
}

TORRENT_TEST(get_gateway_local_v6)
{
std::vector<ip_route> const routes = {
rt("2a02::", "eth0", "::")
rt("2a02::", "eth0", "::", "ffff::")
};

// local IPv6 addresses never have a gateway
TEST_CHECK(get_gateway(ip("fe80::1234", "ffff::", "eth0"), routes) == none);
TEST_CHECK(get_gateway(ip("fe80::1234", "eth0"), routes) == none);
}

// an odd, imaginary setup, where the loopback network has a gateway
TORRENT_TEST(get_gateway_loopback)
{
std::vector<ip_route> const routes = {
rt("0.0.0.0", "eth0", "192.168.0.1"),
rt("0.0.0.0", "lo", "127.1.1.1"),
rt("::", "eth0", "fec0::1234"),
rt("::", "lo", "::2")
rt("0.0.0.0", "eth0", "192.168.0.1", "255.255.0.0"),
rt("0.0.0.0", "lo", "127.1.1.1", "255.0.0.0"),
rt("::", "eth0", "fec0::1234", "ffff::"),
rt("::", "lo", "::2", "ffff:ffff:ffff:ffff::")
};

TEST_CHECK(get_gateway(ip("127.0.0.1", "255.0.0.0", "lo"), routes) == address::from_string("127.1.1.1"));
TEST_CHECK(get_gateway(ip("127.0.0.1", "lo"), routes) == address::from_string("127.1.1.1"));

// with IPv6, there are no gateways for local or loopback addresses
TEST_CHECK(get_gateway(ip("::1", "ffff:ffff:ffff:ffff::", "lo"), routes) == none);
TEST_CHECK(get_gateway(ip("::1", "lo"), routes) == none);
}

TORRENT_TEST(get_gateway_netmask)
{
std::vector<ip_route> const routes = {
rt("0.0.0.0", "eth0", "192.168.1.1", "255.255.255.0"),
rt("0.0.0.0", "eth0", "192.168.2.1", "0.0.0.0")
};

TEST_CHECK(get_gateway(ip("192.168.0.130", "eth0"), routes) == address::from_string("192.168.2.1"));
TEST_CHECK(get_gateway(ip("192.168.1.130", "eth0"), routes) == address::from_string("192.168.1.1"));
}

TORRENT_TEST(get_gateway_multi_homed)
{
std::vector<ip_route> const routes = {
rt("0.0.0.0", "eth0", "192.168.0.1"),
rt("0.0.0.0", "eth0", "10.0.0.1")
rt("0.0.0.0", "eth0", "192.168.0.1", "255.255.0.0"),
rt("0.0.0.0", "eth0", "10.0.0.1", "255.0.0.0")
};

TEST_CHECK(get_gateway(ip("192.168.0.130", "255.255.0.0", "eth0"), routes) == address::from_string("192.168.0.1"));
TEST_CHECK(get_gateway(ip("10.0.1.130", "255.0.0.0", "eth0"), routes) == address::from_string("10.0.0.1"));
TEST_CHECK(get_gateway(ip("192.168.0.130", "eth0"), routes) == address::from_string("192.168.0.1"));
TEST_CHECK(get_gateway(ip("10.0.1.130", "eth0"), routes) == address::from_string("10.0.0.1"));
}

0 comments on commit 0a4a06c

Please sign in to comment.