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