apparently on VPNs it's common for the gateway for a route to be outside of the netmask of the network it's a router for. fix that in get_gateway

This commit is contained in:
arvidn 2020-02-08 21:11:39 +01:00 committed by Arvid Norberg
parent 6d5bdbdb1a
commit 0a4a06ce74
2 changed files with 40 additions and 28 deletions

View File

@ -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

View File

@ -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;
}
@ -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"));
}