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/connection_unittest.cc b/connection_unittest.cc
index c9c45e1..2fd5bd0 100644
--- a/connection_unittest.cc
+++ b/connection_unittest.cc
@@ -29,6 +29,7 @@
using testing::Mock;
using testing::NiceMock;
using testing::Return;
+using testing::ReturnRef;
using testing::StrictMock;
using testing::Test;
@@ -107,6 +108,18 @@
return connection->PinHostRoute(properties);
}
+ const IPAddress &GetLocalAddress(ConnectionRefPtr connection) {
+ return connection->local_;
+ }
+
+ const IPAddress &GetGatewayAddress(ConnectionRefPtr connection) {
+ return connection->gateway_;
+ }
+
+ bool GetHasBroadcastDomain(ConnectionRefPtr connection) {
+ return connection->has_broadcast_domain_;
+ }
+
protected:
class DisconnectCallbackTarget {
public:
@@ -190,6 +203,22 @@
ipconfig_,
Connection::kDefaultMetric));
connection_->UpdateFromIPConfig(ipconfig_);
+ IPAddress test_local_address(local_address_);
+ test_local_address.set_prefix(kPrefix0);
+ EXPECT_TRUE(test_local_address.Equals(GetLocalAddress(connection_)));
+ EXPECT_TRUE(gateway_address_.Equals(GetGatewayAddress(connection_)));
+ EXPECT_TRUE(GetHasBroadcastDomain(connection_));
+
+ EXPECT_CALL(routing_table_,
+ CreateLinkRoute(kTestDeviceInterfaceIndex0,
+ IsIPAddress(local_address_, kPrefix0),
+ IsIPAddress(gateway_address_, 0)))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false));
+ EXPECT_TRUE(connection_->CreateGatewayRoute());
+ EXPECT_FALSE(connection_->CreateGatewayRoute());
+ connection_->has_broadcast_domain_ = false;
+ EXPECT_FALSE(connection_->CreateGatewayRoute());
EXPECT_CALL(routing_table_, SetDefaultMetric(kTestDeviceInterfaceIndex0,
Connection::kDefaultMetric));
@@ -243,6 +272,7 @@
ipconfig_,
Connection::kDefaultMetric));
connection_->UpdateFromIPConfig(ipconfig_);
+ EXPECT_FALSE(GetHasBroadcastDomain(connection_));
}
TEST_F(ConnectionTest, AddConfigWithBrokenNetmask) {
@@ -683,14 +713,28 @@
kTestDeviceInterfaceIndex1, RoutingTableEntry());
EXPECT_FALSE(binder->IsBound());
- // Check that the upper connection is bound to the lower connection.
- device->connection_ = connection;
+ // Create a mock connection that will be used fo binding.
+ scoped_refptr<MockConnection> mock_connection(
+ new StrictMock<MockConnection>(device_info_.get()));
+ EXPECT_CALL(*device_info_.get(),
+ FlushAddresses(mock_connection->interface_index()));
+ const string kInterfaceName(kTestDeviceName0);
+ EXPECT_CALL(*mock_connection, interface_name())
+ .WillRepeatedly(ReturnRef(kInterfaceName));
+ device->connection_ = mock_connection;
EXPECT_CALL(*device_info_, GetDevice(kTestDeviceInterfaceIndex1))
.WillOnce(Return(device));
+
+ // Check that the the binding process completes, causing its upper
+ // connection to create a gateway route.
+ EXPECT_CALL(*mock_connection, CreateGatewayRoute())
+ .WillOnce(Return(true));
connection_->OnRouteQueryResponse(
kTestDeviceInterfaceIndex1, RoutingTableEntry());
+
+ // Check that the upper connection is bound to the lower connection.
EXPECT_TRUE(binder->IsBound());
- EXPECT_EQ(connection.get(), binder->connection().get());
+ EXPECT_EQ(mock_connection.get(), binder->connection().get());
device->connection_ = NULL;
AddDestructorExpectations();