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