1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "shill/connection.h"
18 
19 #include <arpa/inet.h>
20 #include <linux/rtnetlink.h>
21 
22 #include <set>
23 
24 #include <base/strings/stringprintf.h>
25 
26 #include "shill/control_interface.h"
27 #include "shill/device_info.h"
28 #include "shill/firewall_proxy_interface.h"
29 #include "shill/logging.h"
30 #include "shill/net/rtnl_handler.h"
31 #include "shill/routing_table.h"
32 
33 #if !defined(__ANDROID__)
34 #include "shill/resolver.h"
35 #else
36 #include "shill/dns_server_proxy.h"
37 #include "shill/dns_server_proxy_factory.h"
38 #endif  // __ANDROID__
39 
40 using base::Bind;
41 using base::Closure;
42 using base::Unretained;
43 using std::deque;
44 using std::set;
45 using std::string;
46 using std::vector;
47 
48 namespace shill {
49 
50 namespace Logging {
51 static auto kModuleLogScope = ScopeLogger::kConnection;
ObjectID(Connection * c)52 static string ObjectID(Connection* c) {
53   if (c == nullptr)
54     return "(connection)";
55   return c->interface_name();
56 }
57 }
58 
59 #if defined(__ANDROID__)
60 namespace {
61 const char* kGoogleDNSServers[] = {
62     "8.8.4.4",
63     "8.8.8.8"
64 };
65 }  // namespace
66 #endif  // __ANDROID__
67 
68 // static
69 const uint32_t Connection::kDefaultMetric = 1;
70 // static
71 const uint32_t Connection::kNonDefaultMetricBase = 10;
72 // static
73 const uint32_t Connection::kMarkForUserTraffic = 0x1;
74 // static
75 const uint8_t Connection::kSecondaryTableId = 0x1;
76 
Binder(const string & name,const Closure & disconnect_callback)77 Connection::Binder::Binder(const string& name,
78                            const Closure& disconnect_callback)
79     : name_(name),
80       client_disconnect_callback_(disconnect_callback) {}
81 
~Binder()82 Connection::Binder::~Binder() {
83   Attach(nullptr);
84 }
85 
Attach(const ConnectionRefPtr & to_connection)86 void Connection::Binder::Attach(const ConnectionRefPtr& to_connection) {
87   if (connection_) {
88     connection_->DetachBinder(this);
89     LOG(INFO) << name_ << ": unbound from connection: "
90               << connection_->interface_name();
91     connection_.reset();
92   }
93   if (to_connection) {
94     connection_ = to_connection->weak_ptr_factory_.GetWeakPtr();
95     connection_->AttachBinder(this);
96     LOG(INFO) << name_ << ": bound to connection: "
97               << connection_->interface_name();
98   }
99 }
100 
OnDisconnect()101 void Connection::Binder::OnDisconnect() {
102   LOG(INFO) << name_ << ": bound connection disconnected: "
103             << connection_->interface_name();
104   connection_.reset();
105   if (!client_disconnect_callback_.is_null()) {
106     SLOG(connection_.get(), 2) << "Running client disconnect callback.";
107     client_disconnect_callback_.Run();
108   }
109 }
110 
Connection(int interface_index,const std::string & interface_name,Technology::Identifier technology,const DeviceInfo * device_info,ControlInterface * control_interface)111 Connection::Connection(int interface_index,
112                        const std::string& interface_name,
113                        Technology::Identifier technology,
114                        const DeviceInfo* device_info,
115                        ControlInterface* control_interface)
116     : weak_ptr_factory_(this),
117       is_default_(false),
118       has_broadcast_domain_(false),
119       routing_request_count_(0),
120       interface_index_(interface_index),
121       interface_name_(interface_name),
122       technology_(technology),
123       user_traffic_only_(false),
124       table_id_(RT_TABLE_MAIN),
125       local_(IPAddress::kFamilyUnknown),
126       gateway_(IPAddress::kFamilyUnknown),
127       lower_binder_(
128           interface_name_,
129           // Connection owns a single instance of |lower_binder_| so it's safe
130           // to use an Unretained callback.
131           Bind(&Connection::OnLowerDisconnect, Unretained(this))),
132       device_info_(device_info),
133 #if !defined(__ANDROID__)
134       resolver_(Resolver::GetInstance()),
135 #else
136       dns_server_proxy_factory_(DNSServerProxyFactory::GetInstance()),
137 #endif  // __ANDROID__
138       routing_table_(RoutingTable::GetInstance()),
139       rtnl_handler_(RTNLHandler::GetInstance()),
140       control_interface_(control_interface) {
141   SLOG(this, 2) << __func__ << "(" << interface_index << ", "
142                 << interface_name << ", "
143                 << Technology::NameFromIdentifier(technology) << ")";
144 }
145 
~Connection()146 Connection::~Connection() {
147   SLOG(this, 2) << __func__ << " " << interface_name_;
148 
149   NotifyBindersOnDisconnect();
150 
151   DCHECK(!routing_request_count_);
152   routing_table_->FlushRoutes(interface_index_);
153   routing_table_->FlushRoutesWithTag(interface_index_);
154   device_info_->FlushAddresses(interface_index_);
155   TearDownIptableEntries();
156 }
157 
UpdateFromIPConfig(const IPConfigRefPtr & config)158 void Connection::UpdateFromIPConfig(const IPConfigRefPtr& config) {
159   SLOG(this, 2) << __func__ << " " << interface_name_;
160 
161   const IPConfig::Properties& properties = config->properties();
162   user_traffic_only_ = properties.user_traffic_only;
163   table_id_ = user_traffic_only_ ? kSecondaryTableId : (uint8_t)RT_TABLE_MAIN;
164 
165   IPAddress gateway(properties.address_family);
166   if (!properties.gateway.empty() &&
167       !gateway.SetAddressFromString(properties.gateway)) {
168     LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid";
169     return;
170   }
171 
172   excluded_ips_cidr_ = properties.exclusion_list;
173 
174   IPAddress trusted_ip(properties.address_family);
175   if (!excluded_ips_cidr_.empty()) {
176     const std::string first_excluded_ip = excluded_ips_cidr_[0];
177     excluded_ips_cidr_.erase(excluded_ips_cidr_.begin());
178     // A VPN connection can currently be bound to exactly one lower connection
179     // such as eth0 or wan0. The excluded IPs are pinned to the gateway of
180     // that connection. Setting up the routing table this way ensures that when
181     // the lower connection goes offline, the associated entries in the routing
182     // table are removed. On the flip side, when there are multiple connections
183     // such as eth0 and wan0 and some IPs can be reached quickly over one
184     // connection and the others over a different connection, all routes are
185     // still pinned to a connection.
186     //
187     // The optimal connection to reach the first excluded IP is found below.
188     // When this is found the route for the remaining excluded IPs are pinned in
189     // the method PinPendingRoutes below.
190     if (!trusted_ip.SetAddressAndPrefixFromString(first_excluded_ip)) {
191       LOG(ERROR) << "Trusted IP address "
192                  << first_excluded_ip << " is invalid";
193       return;
194     }
195     if (!PinHostRoute(trusted_ip, gateway)) {
196       LOG(ERROR) << "Unable to pin host route to " << first_excluded_ip;
197       return;
198     }
199   }
200 
201   IPAddress local(properties.address_family);
202   if (!local.SetAddressFromString(properties.address)) {
203     LOG(ERROR) << "Local address " << properties.address << " is invalid";
204     return;
205   }
206   local.set_prefix(properties.subnet_prefix);
207 
208   IPAddress broadcast(properties.address_family);
209   if (properties.broadcast_address.empty()) {
210     if (properties.peer_address.empty()) {
211       LOG(WARNING) << "Broadcast address is not set.  Using default.";
212       broadcast = local.GetDefaultBroadcast();
213     }
214   } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
215     LOG(ERROR) << "Broadcast address " << properties.broadcast_address
216                << " is invalid";
217     return;
218   }
219 
220   IPAddress peer(properties.address_family);
221   if (!properties.peer_address.empty() &&
222       !peer.SetAddressFromString(properties.peer_address)) {
223     LOG(ERROR) << "Peer address " << properties.peer_address
224                << " is invalid";
225     return;
226   }
227 
228   if (!FixGatewayReachability(local, &peer, &gateway, trusted_ip)) {
229     LOG(WARNING) << "Expect limited network connectivity.";
230   }
231 
232   if (device_info_->HasOtherAddress(interface_index_, local)) {
233     // The address has changed for this interface.  We need to flush
234     // everything and start over.
235     LOG(INFO) << __func__ << ": Flushing old addresses and routes.";
236     routing_table_->FlushRoutes(interface_index_);
237     device_info_->FlushAddresses(interface_index_);
238   }
239 
240   LOG(INFO) << __func__ << ": Installing with parameters:"
241             << " local=" << local.ToString()
242             << " broadcast=" << broadcast.ToString()
243             << " peer=" << peer.ToString()
244             << " gateway=" << gateway.ToString();
245   rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
246 
247   if (gateway.IsValid() && properties.default_route) {
248     routing_table_->SetDefaultRoute(interface_index_, gateway,
249                                     GetMetric(is_default_),
250                                     table_id_);
251   }
252 
253   if (user_traffic_only_) {
254     SetupIptableEntries();
255   }
256 
257   // Install any explicitly configured routes at the default metric.
258   routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric,
259                                   table_id_);
260 
261   SetMTU(properties.mtu);
262 
263   if (properties.blackhole_ipv6) {
264     routing_table_->CreateBlackholeRoute(interface_index_,
265                                          IPAddress::kFamilyIPv6,
266                                          kDefaultMetric,
267                                          table_id_);
268   }
269 
270   // Save a copy of the last non-null DNS config.
271   if (!config->properties().dns_servers.empty()) {
272     dns_servers_ = config->properties().dns_servers;
273   }
274 
275 #if defined(__ANDROID__)
276   // Default to Google's DNS server if it is not provided through DHCP.
277   if (config->properties().dns_servers.empty()) {
278     LOG(INFO) << "Default to use Google DNS servers";
279     dns_servers_ =
280         vector<string>(std::begin(kGoogleDNSServers),
281                        std::end(kGoogleDNSServers));
282   }
283 #endif  // __ANDROID__
284 
285   if (!config->properties().domain_search.empty()) {
286     dns_domain_search_ = config->properties().domain_search;
287   }
288 
289   if (!config->properties().domain_name.empty()) {
290     dns_domain_name_ = config->properties().domain_name;
291   }
292 
293   ipconfig_rpc_identifier_ = config->GetRpcIdentifier();
294 
295   PushDNSConfig();
296 
297   local_ = local;
298   gateway_ = gateway;
299   has_broadcast_domain_ = !peer.IsValid();
300 }
301 
SetupIptableEntries()302 bool Connection::SetupIptableEntries() {
303   if (!firewall_proxy_) {
304     firewall_proxy_.reset(control_interface_->CreateFirewallProxy());
305   }
306 
307   std::vector<std::string> user_names;
308   user_names.push_back("chronos");
309   user_names.push_back("debugd");
310 
311   if (!firewall_proxy_->RequestVpnSetup(user_names, interface_name_)) {
312     LOG(ERROR) << "VPN iptables setup request failed.";
313     return false;
314   }
315 
316   return true;
317 }
318 
TearDownIptableEntries()319 bool Connection::TearDownIptableEntries() {
320   return firewall_proxy_ ? firewall_proxy_->RemoveVpnSetup() : true;
321 }
322 
SetIsDefault(bool is_default)323 void Connection::SetIsDefault(bool is_default) {
324   SLOG(this, 2) << __func__ << " " << interface_name_
325                 << " (index " << interface_index_ << ") "
326                 << is_default_ << " -> " << is_default;
327   if (is_default == is_default_) {
328     return;
329   }
330 
331   routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
332 
333   is_default_ = is_default;
334 
335   PushDNSConfig();
336   if (is_default) {
337     DeviceRefPtr device = device_info_->GetDevice(interface_index_);
338     if (device) {
339       device->RequestPortalDetection();
340     }
341   }
342   routing_table_->FlushCache();
343 }
344 
UpdateDNSServers(const vector<string> & dns_servers)345 void Connection::UpdateDNSServers(const vector<string>& dns_servers) {
346   dns_servers_ = dns_servers;
347   PushDNSConfig();
348 }
349 
PushDNSConfig()350 void Connection::PushDNSConfig() {
351   if (!is_default_) {
352 #if defined(__ANDROID__)
353     // Stop DNS server proxy to avoid having multiple instances of it running.
354     // Only run DNS server proxy for the current default connection.
355     dns_server_proxy_.reset();
356 #endif  // __ANDROID__
357     return;
358   }
359 
360   vector<string> domain_search = dns_domain_search_;
361   if (domain_search.empty() && !dns_domain_name_.empty()) {
362     SLOG(this, 2) << "Setting domain search to domain name "
363                   << dns_domain_name_;
364     domain_search.push_back(dns_domain_name_ + ".");
365   }
366 #if !defined(__ANDROID__)
367   resolver_->SetDNSFromLists(dns_servers_, domain_search);
368 #else
369   dns_server_proxy_.reset(
370       dns_server_proxy_factory_->CreateDNSServerProxy(dns_servers_));
371   dns_server_proxy_->Start();
372 #endif  // __ANDROID__
373 }
374 
RequestRouting()375 void Connection::RequestRouting() {
376   if (routing_request_count_++ == 0) {
377     DeviceRefPtr device = device_info_->GetDevice(interface_index_);
378     DCHECK(device.get());
379     if (!device.get()) {
380       LOG(ERROR) << "Device is NULL!";
381       return;
382     }
383     device->SetLooseRouting(true);
384   }
385 }
386 
ReleaseRouting()387 void Connection::ReleaseRouting() {
388   DCHECK_GT(routing_request_count_, 0);
389   if (--routing_request_count_ == 0) {
390     DeviceRefPtr device = device_info_->GetDevice(interface_index_);
391     DCHECK(device.get());
392     if (!device.get()) {
393       LOG(ERROR) << "Device is NULL!";
394       return;
395     }
396     device->SetLooseRouting(false);
397 
398     // Clear any cached routes that might have accumulated while reverse-path
399     // filtering was disabled.
400     routing_table_->FlushCache();
401   }
402 }
403 
RequestHostRoute(const IPAddress & address)404 bool Connection::RequestHostRoute(const IPAddress& address) {
405   // Do not set interface_index_ since this may not be the default route through
406   // which this destination can be found.  However, we should tag the created
407   // route with our interface index so we can clean this route up when this
408   // connection closes.  Also, add route query callback to determine the lower
409   // connection and bind to it.
410   if (!routing_table_->RequestRouteToHost(
411           address,
412           -1,
413           interface_index_,
414           Bind(&Connection::OnRouteQueryResponse,
415                weak_ptr_factory_.GetWeakPtr()),
416           table_id_)) {
417     LOG(ERROR) << "Could not request route to " << address.ToString();
418     return false;
419   }
420 
421   return true;
422 }
423 
PinPendingRoutes(int interface_index,RoutingTableEntry entry)424 bool Connection::PinPendingRoutes(int interface_index,
425                                   RoutingTableEntry entry) {
426   // The variable entry is locally modified, hence is passed by value in the
427   // second argument above.
428   for (auto excluded_ip = excluded_ips_cidr_.begin();
429        excluded_ip != excluded_ips_cidr_.end(); ++excluded_ip) {
430     if (!entry.dst.SetAddressAndPrefixFromString(*excluded_ip) ||
431         !entry.dst.IsValid() ||
432         !routing_table_->AddRoute(interface_index, entry)) {
433       LOG(ERROR) << "Unable to setup route for " << *excluded_ip << ".";
434     }
435   }
436 
437   return true;
438 }
439 
GetSubnetName() const440 string Connection::GetSubnetName() const {
441   if (!local().IsValid()) {
442     return "";
443   }
444   return base::StringPrintf("%s/%d",
445                             local().GetNetworkPart().ToString().c_str(),
446                             local().prefix());
447 }
448 
FixGatewayReachability(const IPAddress & local,IPAddress * peer,IPAddress * gateway,const IPAddress & trusted_ip)449 bool Connection::FixGatewayReachability(const IPAddress& local,
450                                         IPAddress* peer,
451                                         IPAddress* gateway,
452                                         const IPAddress& trusted_ip) {
453   SLOG(nullptr, 2) << __func__
454       << " local " << local.ToString()
455       << ", peer " << peer->ToString()
456       << ", gateway " << gateway->ToString()
457       << ", trusted_ip " << trusted_ip.ToString();
458   if (!gateway->IsValid()) {
459     LOG(WARNING) << "No gateway address was provided for this connection.";
460     return false;
461   }
462 
463   if (peer->IsValid()) {
464     if (!gateway->HasSameAddressAs(*peer)) {
465       LOG(WARNING) << "Gateway address "
466                    << gateway->ToString()
467                    << " does not match peer address "
468                    << peer->ToString();
469       return false;
470     }
471     if (gateway->HasSameAddressAs(trusted_ip)) {
472       // In order to send outgoing traffic in a point-to-point network,
473       // the gateway IP address isn't of significance.  As opposed to
474       // broadcast networks, we never ARP for the gateway IP address,
475       // but just send the IP packet addressed to the recipient.  As
476       // such, since using the external trusted IP address as the
477       // gateway or peer wreaks havoc on the routing rules, we choose
478       // not to supply a gateway address.  Here's an example:
479       //
480       //     Client    <->  Internet  <->  VPN Gateway  <->  Internal Network
481       //   192.168.1.2                      10.0.1.25         172.16.5.0/24
482       //
483       // In this example, a client connects to a VPN gateway on its
484       // public IP address 10.0.1.25.  It gets issued an IP address
485       // from the VPN internal pool.  For some VPN gateways, this
486       // results in a pushed-down PPP configuration which specifies:
487       //
488       //    Client local address:   172.16.5.13
489       //    Client peer address:    10.0.1.25
490       //    Client default gateway: 10.0.1.25
491       //
492       // If we take this literally, we need to resolve the fact that
493       // 10.0.1.25 is now listed as the default gateway and interface
494       // peer address for the point-to-point interface.  However, in
495       // order to route tunneled packets to the VPN gateway we must
496       // use the external route through the physical interface and
497       // not the tunnel, or else we end up in an infinite loop
498       // re-entering the tunnel trying to route towards the VPN server.
499       //
500       // We can do this by pinning a route, but we would need to wait
501       // for the pinning process to complete before assigning this
502       // address.  Currently this process is asynchronous and will
503       // complete only after returning to the event loop.  Additionally,
504       // since there's no metric associated with assigning an address
505       // to an interface, it's always possible that having the peer
506       // address of the interface might still trump a host route.
507       //
508       // To solve this problem, we reset the peer and gateway
509       // addresses.  Neither is required in order to perform the
510       // underlying routing task.  A gateway route can be specified
511       // without an IP endpoint on point-to-point links, and simply
512       // specify the outbound interface index.  Similarly, a peer
513       // IP address is not necessary either, and will be assigned
514       // the same IP address as the local IP.  This approach
515       // simplifies routing and doesn't change the desired
516       // functional behavior.
517       //
518       LOG(INFO) << "Removing gateway and peer addresses to preserve "
519                 << "routability to trusted IP address.";
520       peer->SetAddressToDefault();
521       gateway->SetAddressToDefault();
522     }
523     return true;
524   }
525 
526   if (local.CanReachAddress(*gateway)) {
527     return true;
528   }
529 
530   LOG(WARNING) << "Gateway "
531                << gateway->ToString()
532                << " is unreachable from local address/prefix "
533                << local.ToString() << "/" << local.prefix();
534 
535   IPAddress gateway_with_max_prefix(*gateway);
536   gateway_with_max_prefix.set_prefix(
537       IPAddress::GetMaxPrefixLength(gateway_with_max_prefix.family()));
538   IPAddress default_address(gateway->family());
539   RoutingTableEntry entry(gateway_with_max_prefix,
540                           default_address,
541                           default_address,
542                           0,
543                           RT_SCOPE_LINK,
544                           false,
545                           table_id_,
546                           RoutingTableEntry::kDefaultTag);
547 
548   if (!routing_table_->AddRoute(interface_index_, entry)) {
549     LOG(ERROR) << "Unable to add link-scoped route to gateway.";
550     return false;
551   }
552 
553   LOG(WARNING) << "Mitigating this by creating a link route to the gateway.";
554 
555   return true;
556 }
557 
GetMetric(bool is_default)558 uint32_t Connection::GetMetric(bool is_default) {
559   // If this is not the default route, assign a metric based on the interface
560   // index.  This way all non-default routes (even to the same gateway IP) end
561   // up with unique metrics so they do not collide.
562   return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
563 }
564 
PinHostRoute(const IPAddress & trusted_ip,const IPAddress & gateway)565 bool Connection::PinHostRoute(const IPAddress& trusted_ip,
566                               const IPAddress& gateway) {
567   SLOG(this, 2) << __func__;
568   if (!trusted_ip.IsValid()) {
569     LOG(ERROR) << "No trusted IP -- unable to pin host route.";
570     return false;
571   }
572 
573   if (!gateway.IsValid()) {
574     // Although we cannot pin a host route, we are also not going to create
575     // a gateway route that will interfere with our primary connection, so
576     // it is okay to return success here.
577     LOG(WARNING) << "No gateway -- unable to pin host route.";
578     return true;
579   }
580 
581   return RequestHostRoute(trusted_ip);
582 }
583 
SetMTU(int32_t mtu)584 void Connection::SetMTU(int32_t mtu) {
585   SLOG(this, 2) << __func__ << " " << mtu;
586   // Make sure the MTU value is valid.
587   if (mtu == IPConfig::kUndefinedMTU) {
588     mtu = IPConfig::kDefaultMTU;
589   } else {
590     int min_mtu = IsIPv6() ? IPConfig::kMinIPv6MTU : IPConfig::kMinIPv4MTU;
591     if (mtu < min_mtu) {
592       SLOG(this, 2) << __func__ << " MTU " << mtu
593                     << " is too small; adjusting up to " << min_mtu;
594       mtu = min_mtu;
595     }
596   }
597 
598   rtnl_handler_->SetInterfaceMTU(interface_index_, mtu);
599 }
600 
OnRouteQueryResponse(int interface_index,const RoutingTableEntry & entry)601 void Connection::OnRouteQueryResponse(int interface_index,
602                                       const RoutingTableEntry& entry) {
603   SLOG(this, 2) << __func__ << "(" << interface_index << ", "
604                 << entry.tag << ")" << " @ " << interface_name_;
605   lower_binder_.Attach(nullptr);
606   DeviceRefPtr device = device_info_->GetDevice(interface_index);
607   if (!device) {
608     LOG(ERROR) << "Unable to lookup device for index " << interface_index;
609     return;
610   }
611   ConnectionRefPtr connection = device->connection();
612   if (!connection) {
613     LOG(ERROR) << "Device " << interface_index << " has no connection.";
614     return;
615   }
616   if (connection == this) {
617     LOG(ERROR) << "Avoiding a connection bind loop for " << interface_name();
618     return;
619   }
620   lower_binder_.Attach(connection);
621   connection->CreateGatewayRoute();
622   device->OnConnectionUpdated();
623   PinPendingRoutes(interface_index, entry);
624 }
625 
CreateGatewayRoute()626 bool Connection::CreateGatewayRoute() {
627   // Ensure that the gateway for the lower connection remains reachable,
628   // since we may create routes that conflict with it.
629   if (!has_broadcast_domain_) {
630     return false;
631   }
632 
633   // If there is no gateway, don't try to create a route to it.
634   if (!gateway_.IsValid()) {
635     return false;
636   }
637 
638   // It is not worth keeping track of this route, since it is benign,
639   // and only pins persistent state that was already true of the connection.
640   // If DHCP parameters change later (without the connection having been
641   // destroyed and recreated), the binding processes will likely terminate
642   // and restart, causing a new link route to be created.
643   return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_,
644                                          table_id_);
645 }
646 
OnLowerDisconnect()647 void Connection::OnLowerDisconnect() {
648   SLOG(this, 2) << __func__ << " @ " << interface_name_;
649   // Ensures that |this| instance doesn't get destroyed in the middle of
650   // notifying the binders. This method needs to be separate from
651   // NotifyBindersOnDisconnect because the latter may be invoked by Connection's
652   // destructor when |this| instance's reference count is already 0.
653   ConnectionRefPtr connection(this);
654   connection->NotifyBindersOnDisconnect();
655 }
656 
NotifyBindersOnDisconnect()657 void Connection::NotifyBindersOnDisconnect() {
658   // Note that this method may be invoked by the destructor.
659   SLOG(this, 2) << __func__ << " @ " << interface_name_;
660 
661   // Unbinds the lower connection before notifying the binders. This ensures
662   // correct behavior in case of circular binding.
663   lower_binder_.Attach(nullptr);
664   while (!binders_.empty()) {
665     // Pop the binder first and then notify it to ensure that each binder is
666     // notified only once.
667     Binder* binder = binders_.front();
668     binders_.pop_front();
669     binder->OnDisconnect();
670   }
671 }
672 
AttachBinder(Binder * binder)673 void Connection::AttachBinder(Binder* binder) {
674   SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ "
675                             << interface_name_;
676   binders_.push_back(binder);
677 }
678 
DetachBinder(Binder * binder)679 void Connection::DetachBinder(Binder* binder) {
680   SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ "
681                             << interface_name_;
682   for (auto it = binders_.begin(); it != binders_.end(); ++it) {
683     if (binder == *it) {
684       binders_.erase(it);
685       return;
686     }
687   }
688 }
689 
GetCarrierConnection()690 ConnectionRefPtr Connection::GetCarrierConnection() {
691   SLOG(this, 2) << __func__ << " @ " << interface_name_;
692   set<Connection*> visited;
693   ConnectionRefPtr carrier = this;
694   while (carrier->GetLowerConnection()) {
695     if (ContainsKey(visited, carrier.get())) {
696       LOG(ERROR) << "Circular connection chain starting at: "
697                  << carrier->interface_name();
698       // If a loop is detected return a NULL value to signal that the carrier
699       // connection is unknown.
700       return nullptr;
701     }
702     visited.insert(carrier.get());
703     carrier = carrier->GetLowerConnection();
704   }
705   SLOG(this, 2) << "Carrier connection: " << carrier->interface_name()
706                 << " @ " << interface_name_;
707   return carrier;
708 }
709 
IsIPv6()710 bool Connection::IsIPv6() {
711   return local_.family() == IPAddress::kFamilyIPv6;
712 }
713 
714 }  // namespace shill
715