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