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