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.cc b/connection.cc
index 3a7e4c3..f3a2e6d 100644
--- a/connection.cc
+++ b/connection.cc
@@ -66,10 +66,13 @@
                        const DeviceInfo *device_info)
     : weak_ptr_factory_(this),
       is_default_(false),
+      has_broadcast_domain_(false),
       routing_request_count_(0),
       interface_index_(interface_index),
       interface_name_(interface_name),
       technology_(technology),
+      local_(IPAddress::kFamilyUnknown),
+      gateway_(IPAddress::kFamilyUnknown),
       lower_binder_(
           interface_name_,
           // Connection owns a single instance of |lower_binder_| so it's safe
@@ -169,6 +172,10 @@
   if (is_default_) {
     resolver_->SetDNSFromIPConfig(config);
   }
+
+  local_ = local;
+  gateway_ = gateway;
+  has_broadcast_domain_ = !peer.IsValid();
 }
 
 void Connection::SetIsDefault(bool is_default) {
@@ -347,6 +354,21 @@
     return;
   }
   lower_binder_.Attach(connection);
+  connection->CreateGatewayRoute();
+}
+
+bool Connection::CreateGatewayRoute() {
+  // Ensure that the gateway for the lower connection remains reachable,
+  // since we may create routes that conflict with it.
+  if (!has_broadcast_domain_) {
+    return false;
+  }
+  // It is not worth keeping track of this route, since it is benign,
+  // and only pins persistent state that was already true of the connection.
+  // If DHCP parameters change later (without the connection having been
+  // destroyed and recreated), the binding processes will likely terminate
+  // and restart, causing a new link route to be created.
+  return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_);
 }
 
 void Connection::OnLowerDisconnect() {