From 0a4a06ce74de03afe0e869772072a2cca277688b Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 8 Feb 2020 21:11:39 +0100 Subject: [PATCH] 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 --- src/enum_net.cpp | 2 +- test/test_enum_net.cpp | 66 +++++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/enum_net.cpp b/src/enum_net.cpp index 5d9cab47a..25dd95b38 100644 --- a/src/enum_net.cpp +++ b/src/enum_net.cpp @@ -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 diff --git a/test/test_enum_net.cpp b/test/test_enum_net.cpp index 3e17587ea..186f81bbb 100644 --- a/test/test_enum_net.cpp +++ b/test/test_enum_net.cpp @@ -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 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 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 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 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 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 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")); }