shill: Connection: Create a link route if we are bound
Due to the behavior of some VPN servers, we may lose our route
to the default gateway of a physical interface due to the routes
assigned by a virtual interfaces. To avert this, set a host route
for the default gateway as we bind a lower connection.
BUG=chromium-os:32643
TEST=New unit tests; tried on a known-misbehaving net (actually
working from there right now); VPN autotests
Change-Id: I68db1da339f61c415f9ba8c2c26d8cdb0276b209
Reviewed-on: https://gerrit.chromium.org/gerrit/27705
Commit-Ready: Paul Stewart <pstew@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/routing_table_unittest.cc b/routing_table_unittest.cc
index 04add74..746bec2 100644
--- a/routing_table_unittest.cc
+++ b/routing_table_unittest.cc
@@ -175,10 +175,13 @@
IPAddress(arg->family(),
arg->GetAttribute(RTA_DST),
status.dst_prefix).Equals(entry.dst) &&
- !arg->HasAttribute(RTA_SRC) &&
- arg->HasAttribute(RTA_GATEWAY) &&
- IPAddress(arg->family(),
- arg->GetAttribute(RTA_GATEWAY)).Equals(entry.gateway) &&
+ ((!arg->HasAttribute(RTA_SRC) && entry.src.IsDefault()) ||
+ (arg->HasAttribute(RTA_SRC) && IPAddress(arg->family(),
+ arg->GetAttribute(RTA_SRC),
+ status.src_prefix).Equals(entry.src))) &&
+ ((!arg->HasAttribute(RTA_GATEWAY) && entry.gateway.IsDefault()) ||
+ (arg->HasAttribute(RTA_GATEWAY) && IPAddress(arg->family(),
+ arg->GetAttribute(RTA_GATEWAY)).Equals(entry.gateway))) &&
arg->GetAttribute(RTA_OIF).ConvertToCPUUInt32(&oif) &&
oif == index &&
arg->GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&priority) &&
@@ -770,4 +773,36 @@
RTPROT_UNSPEC);
}
+TEST_F(RoutingTableTest, CreateLinkRoute) {
+ IPAddress local_address(IPAddress::kFamilyIPv4);
+ ASSERT_TRUE(local_address.SetAddressFromString(kTestNetAddress0));
+ local_address.set_prefix(kTestRemotePrefix4);
+ IPAddress remote_address(IPAddress::kFamilyIPv4);
+ ASSERT_TRUE(remote_address.SetAddressFromString(kTestNetAddress1));
+ IPAddress default_address(IPAddress::kFamilyIPv4);
+ IPAddress remote_address_with_prefix(remote_address);
+ remote_address_with_prefix.set_prefix(
+ IPAddress::GetMaxPrefixLength(remote_address_with_prefix.family()));
+ RoutingTableEntry entry(remote_address_with_prefix,
+ local_address,
+ default_address,
+ 0,
+ RT_SCOPE_LINK,
+ false);
+ EXPECT_CALL(rtnl_handler_,
+ SendMessage(IsRoutingPacket(RTNLMessage::kModeAdd,
+ kTestDeviceIndex0,
+ entry,
+ NLM_F_CREATE | NLM_F_EXCL)))
+ .Times(1);
+ EXPECT_TRUE(routing_table_->CreateLinkRoute(kTestDeviceIndex0,
+ local_address,
+ remote_address));
+
+ ASSERT_TRUE(remote_address.SetAddressFromString(kTestRemoteAddress4));
+ EXPECT_FALSE(routing_table_->CreateLinkRoute(kTestDeviceIndex0,
+ local_address,
+ remote_address));
+}
+
} // namespace shill