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