blob: f83925e340506dffb7ac0c7037be846ce6c11654 [file] [log] [blame]
mukesh agrawalddc378f2012-02-17 18:26:20 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewartdd60e452011-08-08 11:38:36 -07002// 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
Paul Stewart9a908082011-08-31 12:18:48 -07007#include <arpa/inet.h>
8#include <linux/rtnetlink.h>
9
Alex Vakulenko8a532292014-06-16 17:18:44 -070010#include <set>
11
Paul Stewart2cb3fa72014-11-13 01:43:12 -080012#include <base/strings/stringprintf.h>
13
Paul Stewart9a908082011-08-31 12:18:48 -070014#include "shill/device_info.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070015#include "shill/logging.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070016#include "shill/net/rtnl_handler.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070017#include "shill/resolver.h"
18#include "shill/routing_table.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070019
Darin Petkov13e6d552012-05-09 14:22:23 +020020using base::Bind;
21using base::Closure;
22using base::Unretained;
23using std::deque;
Alex Deymofddc09a2013-07-03 18:41:31 -070024using std::set;
Paul Stewartdd60e452011-08-08 11:38:36 -070025using std::string;
Paul Stewartd62d6032012-09-11 11:35:49 -070026using std::vector;
Paul Stewartdd60e452011-08-08 11:38:36 -070027
28namespace shill {
29
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070030namespace Logging {
31static auto kModuleLogScope = ScopeLogger::kConnection;
32static string ObjectID(Connection *c) {
33 return c->interface_name();
34}
35}
36
Paul Stewartdd60e452011-08-08 11:38:36 -070037// static
Ben Chan7fab8972014-08-10 17:14:46 -070038const uint32_t Connection::kDefaultMetric = 1;
Paul Stewartdd60e452011-08-08 11:38:36 -070039// static
Ben Chan7fab8972014-08-10 17:14:46 -070040const uint32_t Connection::kNonDefaultMetricBase = 10;
Paul Stewartdd60e452011-08-08 11:38:36 -070041
Darin Petkov13e6d552012-05-09 14:22:23 +020042Connection::Binder::Binder(const string &name,
43 const Closure &disconnect_callback)
44 : name_(name),
Darin Petkov13e6d552012-05-09 14:22:23 +020045 client_disconnect_callback_(disconnect_callback) {}
46
47Connection::Binder::~Binder() {
Ben Chancc225ef2014-09-30 13:26:51 -070048 Attach(nullptr);
Darin Petkov13e6d552012-05-09 14:22:23 +020049}
50
Darin Petkovef1f9fe2012-05-11 16:51:52 +020051void Connection::Binder::Attach(const ConnectionRefPtr &to_connection) {
Darin Petkov13e6d552012-05-09 14:22:23 +020052 if (connection_) {
53 connection_->DetachBinder(this);
54 LOG(INFO) << name_ << ": unbound from connection: "
55 << connection_->interface_name();
Darin Petkovef1f9fe2012-05-11 16:51:52 +020056 connection_.reset();
Darin Petkov13e6d552012-05-09 14:22:23 +020057 }
Darin Petkovef1f9fe2012-05-11 16:51:52 +020058 if (to_connection) {
59 connection_ = to_connection->weak_ptr_factory_.GetWeakPtr();
Darin Petkov13e6d552012-05-09 14:22:23 +020060 connection_->AttachBinder(this);
61 LOG(INFO) << name_ << ": bound to connection: "
62 << connection_->interface_name();
63 }
64}
65
66void Connection::Binder::OnDisconnect() {
67 LOG(INFO) << name_ << ": bound connection disconnected: "
68 << connection_->interface_name();
Darin Petkovef1f9fe2012-05-11 16:51:52 +020069 connection_.reset();
Darin Petkov13e6d552012-05-09 14:22:23 +020070 if (!client_disconnect_callback_.is_null()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070071 SLOG(connection_.get(), 2) << "Running client disconnect callback.";
Darin Petkov13e6d552012-05-09 14:22:23 +020072 client_disconnect_callback_.Run();
73 }
74}
75
Paul Stewart9a908082011-08-31 12:18:48 -070076Connection::Connection(int interface_index,
77 const std::string& interface_name,
Paul Stewarte00600e2012-03-16 07:08:00 -070078 Technology::Identifier technology,
mukesh agrawal23ac6b72013-01-31 18:52:37 -080079 const DeviceInfo *device_info)
Darin Petkov13e6d552012-05-09 14:22:23 +020080 : weak_ptr_factory_(this),
81 is_default_(false),
Paul Stewart4a6748d2012-07-17 14:31:36 -070082 has_broadcast_domain_(false),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080083 routing_request_count_(0),
Paul Stewartdd60e452011-08-08 11:38:36 -070084 interface_index_(interface_index),
85 interface_name_(interface_name),
Paul Stewarte00600e2012-03-16 07:08:00 -070086 technology_(technology),
Paul Stewart4a6748d2012-07-17 14:31:36 -070087 local_(IPAddress::kFamilyUnknown),
88 gateway_(IPAddress::kFamilyUnknown),
Darin Petkov13e6d552012-05-09 14:22:23 +020089 lower_binder_(
90 interface_name_,
91 // Connection owns a single instance of |lower_binder_| so it's safe
92 // to use an Unretained callback.
93 Bind(&Connection::OnLowerDisconnect, Unretained(this))),
Paul Stewart9a908082011-08-31 12:18:48 -070094 device_info_(device_info),
Paul Stewartdd60e452011-08-08 11:38:36 -070095 resolver_(Resolver::GetInstance()),
96 routing_table_(RoutingTable::GetInstance()),
97 rtnl_handler_(RTNLHandler::GetInstance()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070098 SLOG(this, 2) << __func__ << "(" << interface_index << ", "
99 << interface_name << ", "
100 << Technology::NameFromIdentifier(technology) << ")";
Paul Stewartdd60e452011-08-08 11:38:36 -0700101}
102
103Connection::~Connection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700104 SLOG(this, 2) << __func__ << " " << interface_name_;
Paul Stewart9a908082011-08-31 12:18:48 -0700105
Darin Petkov13e6d552012-05-09 14:22:23 +0200106 NotifyBindersOnDisconnect();
107
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800108 DCHECK(!routing_request_count_);
Thieu Lefb46caf2012-03-08 11:57:15 -0800109 routing_table_->FlushRoutes(interface_index_);
Paul Stewarte93b0382012-04-24 13:11:28 -0700110 routing_table_->FlushRoutesWithTag(interface_index_);
Paul Stewart9a908082011-08-31 12:18:48 -0700111 device_info_->FlushAddresses(interface_index_);
Paul Stewartdd60e452011-08-08 11:38:36 -0700112}
113
114void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700115 SLOG(this, 2) << __func__ << " " << interface_name_;
Paul Stewarte6132022011-08-16 09:11:02 -0700116
Paul Stewart9a908082011-08-31 12:18:48 -0700117 const IPConfig::Properties &properties = config->properties();
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800118 IPAddress gateway(properties.address_family);
119 if (!properties.gateway.empty() &&
120 !gateway.SetAddressFromString(properties.gateway)) {
121 LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid";
Paul Stewarte93b0382012-04-24 13:11:28 -0700122 return;
123 }
124
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800125 IPAddress trusted_ip(properties.address_family);
126 if (!properties.trusted_ip.empty()) {
127 if (!trusted_ip.SetAddressFromString(properties.trusted_ip)) {
128 LOG(ERROR) << "Trusted IP address "
129 << properties.trusted_ip << " is invalid";
130 return;
131 }
132 if (!PinHostRoute(trusted_ip, gateway)) {
133 LOG(ERROR) << "Unable to pin host route to " << properties.trusted_ip;
134 return;
135 }
136 }
137
Paul Stewart9a908082011-08-31 12:18:48 -0700138 IPAddress local(properties.address_family);
139 if (!local.SetAddressFromString(properties.address)) {
140 LOG(ERROR) << "Local address " << properties.address << " is invalid";
141 return;
142 }
Paul Stewart48100b02012-03-19 07:53:52 -0700143 local.set_prefix(properties.subnet_prefix);
Paul Stewart9a908082011-08-31 12:18:48 -0700144
145 IPAddress broadcast(properties.address_family);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700146 if (properties.broadcast_address.empty()) {
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700147 if (properties.peer_address.empty()) {
Paul Stewart1062d9d2012-04-27 10:42:27 -0700148 LOG(WARNING) << "Broadcast address is not set. Using default.";
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700149 broadcast = local.GetDefaultBroadcast();
Paul Stewart1062d9d2012-04-27 10:42:27 -0700150 }
151 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
Paul Stewart9a908082011-08-31 12:18:48 -0700152 LOG(ERROR) << "Broadcast address " << properties.broadcast_address
153 << " is invalid";
154 return;
155 }
156
Paul Stewart48100b02012-03-19 07:53:52 -0700157 IPAddress peer(properties.address_family);
158 if (!properties.peer_address.empty() &&
159 !peer.SetAddressFromString(properties.peer_address)) {
160 LOG(ERROR) << "Peer address " << properties.peer_address
161 << " is invalid";
162 return;
163 }
164
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800165 if (!FixGatewayReachability(&local, &peer, &gateway, trusted_ip)) {
Paul Stewart53a30382012-04-26 09:06:59 -0700166 LOG(WARNING) << "Expect limited network connectivity.";
167 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700168
Paul Stewart05a42c22012-08-02 16:47:21 -0700169 if (device_info_->HasOtherAddress(interface_index_, local)) {
170 // The address has changed for this interface. We need to flush
171 // everything and start over.
172 LOG(INFO) << __func__ << ": Flushing old addresses and routes.";
173 routing_table_->FlushRoutes(interface_index_);
174 device_info_->FlushAddresses(interface_index_);
175 }
176
Paul Stewarte78ec542012-06-08 18:28:50 -0700177 LOG(INFO) << __func__ << ": Installing with parameters:"
178 << " local=" << local.ToString()
179 << " broadcast=" << broadcast.ToString()
180 << " peer=" << peer.ToString()
181 << " gateway=" << gateway.ToString();
Paul Stewart48100b02012-03-19 07:53:52 -0700182 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
Paul Stewartdd60e452011-08-08 11:38:36 -0700183
Paul Stewarte78ec542012-06-08 18:28:50 -0700184 if (gateway.IsValid()) {
185 routing_table_->SetDefaultRoute(interface_index_, gateway,
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700186 GetMetric(is_default_));
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700187 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700188
Paul Stewart3f68bb12012-03-15 13:33:10 -0700189 // Install any explicitly configured routes at the default metric.
190 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric);
191
Ben Chana0163122012-09-25 15:10:52 -0700192 if (properties.blackhole_ipv6) {
193 routing_table_->CreateBlackholeRoute(interface_index_,
194 IPAddress::kFamilyIPv6,
195 kDefaultMetric);
196 }
197
Paul Stewartd62d6032012-09-11 11:35:49 -0700198 // Save a copy of the last non-null DNS config.
Paul Stewartdd60e452011-08-08 11:38:36 -0700199 if (!config->properties().dns_servers.empty()) {
200 dns_servers_ = config->properties().dns_servers;
Paul Stewartd62d6032012-09-11 11:35:49 -0700201 }
202
203 if (!config->properties().domain_search.empty()) {
Paul Stewartdd60e452011-08-08 11:38:36 -0700204 dns_domain_search_ = config->properties().domain_search;
Paul Stewartd62d6032012-09-11 11:35:49 -0700205 }
206
207 if (!config->properties().domain_name.empty()) {
208 dns_domain_name_ = config->properties().domain_name;
Paul Stewartdd60e452011-08-08 11:38:36 -0700209 }
210
Paul Stewart10241e32012-04-23 18:15:06 -0700211 ipconfig_rpc_identifier_ = config->GetRpcIdentifier();
212
Peter Qiua89154b2014-05-23 15:45:42 -0700213 PushDNSConfig();
Paul Stewart4a6748d2012-07-17 14:31:36 -0700214
215 local_ = local;
216 gateway_ = gateway;
217 has_broadcast_domain_ = !peer.IsValid();
Paul Stewartdd60e452011-08-08 11:38:36 -0700218}
219
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800220void Connection::SetIsDefault(bool is_default) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700221 SLOG(this, 2) << __func__ << " " << interface_name_
222 << " (index " << interface_index_ << ") "
223 << is_default_ << " -> " << is_default;
Paul Stewartdd60e452011-08-08 11:38:36 -0700224 if (is_default == is_default_) {
225 return;
226 }
227
Paul Stewart7cfca042011-12-08 14:18:17 -0800228 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
Paul Stewartdd60e452011-08-08 11:38:36 -0700229
Paul Stewartc681fa02012-03-02 19:40:04 -0800230 is_default_ = is_default;
231
Peter Qiua89154b2014-05-23 15:45:42 -0700232 PushDNSConfig();
Paul Stewartdd60e452011-08-08 11:38:36 -0700233 if (is_default) {
Paul Stewartc681fa02012-03-02 19:40:04 -0800234 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
235 if (device) {
236 device->RequestPortalDetection();
237 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700238 }
Paul Stewarte78ec542012-06-08 18:28:50 -0700239 routing_table_->FlushCache();
Paul Stewartdd60e452011-08-08 11:38:36 -0700240}
241
Peter Qiua89154b2014-05-23 15:45:42 -0700242void Connection::UpdateDNSServers(const vector<string> &dns_servers) {
243 dns_servers_ = dns_servers;
244 PushDNSConfig();
245}
246
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700247void Connection::PushDNSConfig() {
Peter Qiua89154b2014-05-23 15:45:42 -0700248 if (!is_default_) {
249 return;
250 }
251
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700252 vector<string> domain_search = dns_domain_search_;
253 if (domain_search.empty() && !dns_domain_name_.empty()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700254 SLOG(this, 2) << "Setting domain search to domain name "
255 << dns_domain_name_;
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700256 domain_search.push_back(dns_domain_name_ + ".");
257 }
mukesh agrawal23ac6b72013-01-31 18:52:37 -0800258 resolver_->SetDNSFromLists(dns_servers_, domain_search);
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700259}
260
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800261void Connection::RequestRouting() {
262 if (routing_request_count_++ == 0) {
263 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
264 DCHECK(device.get());
265 if (!device.get()) {
266 LOG(ERROR) << "Device is NULL!";
267 return;
268 }
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800269 device->SetLooseRouting(true);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800270 }
271}
272
273void Connection::ReleaseRouting() {
Alex Vakulenko8a532292014-06-16 17:18:44 -0700274 DCHECK_GT(routing_request_count_, 0);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800275 if (--routing_request_count_ == 0) {
276 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
277 DCHECK(device.get());
278 if (!device.get()) {
279 LOG(ERROR) << "Device is NULL!";
280 return;
281 }
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800282 device->SetLooseRouting(false);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800283
284 // Clear any cached routes that might have accumulated while reverse-path
285 // filtering was disabled.
286 routing_table_->FlushCache();
287 }
288}
289
Paul Stewartf748a362012-03-07 12:01:20 -0800290bool Connection::RequestHostRoute(const IPAddress &address) {
291 // Set the prefix to be the entire address size.
292 IPAddress address_prefix(address);
293 address_prefix.set_prefix(address_prefix.GetLength() * 8);
294
Darin Petkov13e6d552012-05-09 14:22:23 +0200295 // Do not set interface_index_ since this may not be the default route through
296 // which this destination can be found. However, we should tag the created
297 // route with our interface index so we can clean this route up when this
298 // connection closes. Also, add route query callback to determine the lower
299 // connection and bind to it.
300 if (!routing_table_->RequestRouteToHost(
301 address_prefix,
302 -1,
303 interface_index_,
Darin Petkov5eb05422012-05-11 15:45:25 +0200304 Bind(&Connection::OnRouteQueryResponse,
305 weak_ptr_factory_.GetWeakPtr()))) {
Paul Stewartf748a362012-03-07 12:01:20 -0800306 LOG(ERROR) << "Could not request route to " << address.ToString();
307 return false;
308 }
309
310 return true;
311}
312
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800313string Connection::GetSubnetName() const {
314 return base::StringPrintf("%s/%d",
315 local().GetNetworkPart().ToString().c_str(),
316 local().prefix());
317}
318
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700319// static
Paul Stewart53a30382012-04-26 09:06:59 -0700320bool Connection::FixGatewayReachability(IPAddress *local,
Paul Stewart49258292012-05-26 06:37:14 -0700321 IPAddress *peer,
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800322 IPAddress *gateway,
323 const IPAddress &trusted_ip) {
324 if (!gateway->IsValid()) {
Paul Stewart53a30382012-04-26 09:06:59 -0700325 LOG(WARNING) << "No gateway address was provided for this connection.";
326 return false;
327 }
328
Paul Stewart49258292012-05-26 06:37:14 -0700329 if (peer->IsValid()) {
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800330 if (!gateway->Equals(*peer)) {
331 LOG(WARNING) << "Gateway address "
332 << gateway->ToString()
333 << " does not match peer address "
334 << peer->ToString();
335 return false;
Paul Stewart53a30382012-04-26 09:06:59 -0700336 }
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800337 if (gateway->Equals(trusted_ip)) {
338 // In order to send outgoing traffic in a point-to-point network,
339 // the gateway IP address isn't of significance. As opposed to
340 // broadcast networks, we never ARP for the gateway IP address,
341 // but just send the IP packet addressed to the recipient. As
342 // such, since using the external trusted IP address as the
343 // gateway or peer wreaks havoc on the routing rules, we choose
344 // not to supply a gateway address. Here's an example:
345 //
346 // Client <-> Internet <-> VPN Gateway <-> Internal Network
347 // 192.168.1.2 10.0.1.25 172.16.5.0/24
348 //
349 // In this example, a client connects to a VPN gateway on its
350 // public IP address 10.0.1.25. It gets issued an IP address
351 // from the VPN internal pool. For some VPN gateways, this
352 // results in a pushed-down PPP configuration which specifies:
353 //
354 // Client local address: 172.16.5.13
355 // Client peer address: 10.0.1.25
356 // Client default gateway: 10.0.1.25
357 //
358 // If we take this literally, we need to resolve the fact that
359 // 10.0.1.25 is now listed as the default gateway and interface
360 // peer address for the point-to-point interface. However, in
361 // order to route tunneled packets to the VPN gateway we must
362 // use the external route through the physical interface and
363 // not the tunnel, or else we end up in an infinite loop
364 // re-entering the tunnel trying to route towards the VPN server.
365 //
366 // We can do this by pinning a route, but we would need to wait
367 // for the pinning process to complete before assigning this
368 // address. Currently this process is asynchronous and will
369 // complete only after returning to the event loop. Additionally,
370 // since there's no metric associated with assigning an address
371 // to an interface, it's always possible that having the peer
372 // address of the interface might still trump a host route.
373 //
374 // To solve this problem, we reset the peer and gateway
375 // addresses. Neither is required in order to perform the
376 // underlying routing task. A gateway route can be specified
377 // without an IP endpoint on point-to-point links, and simply
378 // specify the outbound interface index. Similarly, a peer
379 // IP address is not necessary either, and will be assigned
380 // the same IP address as the local IP. This approach
381 // simplifies routing and doesn't change the desired
382 // functional behavior.
383 //
384 LOG(INFO) << "Removing gateway and peer addresses to preserve "
385 << "routability to trusted IP address.";
386 peer->SetAddressToDefault();
387 gateway->SetAddressToDefault();
388 }
389 return true;
Paul Stewart53a30382012-04-26 09:06:59 -0700390 }
391
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800392 if (local->CanReachAddress(*gateway)) {
Paul Stewart53a30382012-04-26 09:06:59 -0700393 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700394 }
395
396 LOG(WARNING) << "Gateway "
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800397 << gateway->ToString()
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700398 << " is unreachable from local address/prefix "
399 << local->ToString() << "/" << local->prefix();
400
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700401 bool found_new_prefix = false;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700402 size_t original_prefix = local->prefix();
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700403 // Only try to expand the netmask if the configured prefix is
404 // less than "all ones". This special-cases the "all-ones"
405 // prefix as a forced conversion to point-to-point networking.
406 if (local->prefix() < IPAddress::GetMaxPrefixLength(local->family())) {
407 size_t prefix = original_prefix - 1;
408 for (; prefix >= local->GetMinPrefixLength(); --prefix) {
409 local->set_prefix(prefix);
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800410 if (local->CanReachAddress(*gateway)) {
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700411 found_new_prefix = true;
412 break;
413 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700414 }
415 }
416
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700417 if (!found_new_prefix) {
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700418 // Restore the original prefix since we cannot find a better one.
419 local->set_prefix(original_prefix);
Paul Stewart49258292012-05-26 06:37:14 -0700420 DCHECK(!peer->IsValid());
421 LOG(WARNING) << "Assuming point-to-point configuration.";
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800422 *peer = *gateway;
Paul Stewart49258292012-05-26 06:37:14 -0700423 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700424 }
Paul Stewart53a30382012-04-26 09:06:59 -0700425
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700426 LOG(WARNING) << "Mitigating this by setting local prefix to "
427 << local->prefix();
Paul Stewart53a30382012-04-26 09:06:59 -0700428 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700429}
430
Ben Chan7fab8972014-08-10 17:14:46 -0700431uint32_t Connection::GetMetric(bool is_default) {
Paul Stewart7cfca042011-12-08 14:18:17 -0800432 // If this is not the default route, assign a metric based on the interface
433 // index. This way all non-default routes (even to the same gateway IP) end
434 // up with unique metrics so they do not collide.
435 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
436}
437
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800438bool Connection::PinHostRoute(const IPAddress &trusted_ip,
439 const IPAddress &gateway) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700440 SLOG(this, 2) << __func__;
Paul Stewarte435d342013-09-27 16:41:00 -0700441 if (!trusted_ip.IsValid()) {
442 LOG(ERROR) << "No trusted IP -- unable to pin host route.";
Paul Stewarte93b0382012-04-24 13:11:28 -0700443 return false;
444 }
445
Paul Stewarte435d342013-09-27 16:41:00 -0700446 if (!gateway.IsValid()) {
447 // Although we cannot pin a host route, we are also not going to create
448 // a gateway route that will interfere with our primary connection, so
449 // it is okay to return success here.
450 LOG(WARNING) << "No gateway -- unable to pin host route.";
451 return true;
452 }
453
Paul Stewarte93b0382012-04-24 13:11:28 -0700454 return RequestHostRoute(trusted_ip);
455}
456
Darin Petkov13e6d552012-05-09 14:22:23 +0200457void Connection::OnRouteQueryResponse(int interface_index,
458 const RoutingTableEntry &entry) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700459 SLOG(this, 2) << __func__ << "(" << interface_index << ", "
460 << entry.tag << ")" << " @ " << interface_name_;
Ben Chancc225ef2014-09-30 13:26:51 -0700461 lower_binder_.Attach(nullptr);
Darin Petkov13e6d552012-05-09 14:22:23 +0200462 DeviceRefPtr device = device_info_->GetDevice(interface_index);
463 if (!device) {
464 LOG(ERROR) << "Unable to lookup device for index " << interface_index;
465 return;
466 }
467 ConnectionRefPtr connection = device->connection();
468 if (!connection) {
469 LOG(ERROR) << "Device " << interface_index << " has no connection.";
470 return;
471 }
472 lower_binder_.Attach(connection);
Paul Stewart4a6748d2012-07-17 14:31:36 -0700473 connection->CreateGatewayRoute();
Paul Stewart8596f9f2013-03-14 07:58:26 -0700474 device->OnConnectionUpdated();
Paul Stewart4a6748d2012-07-17 14:31:36 -0700475}
476
477bool Connection::CreateGatewayRoute() {
478 // Ensure that the gateway for the lower connection remains reachable,
479 // since we may create routes that conflict with it.
480 if (!has_broadcast_domain_) {
481 return false;
482 }
Paul Stewart856b8842013-07-10 11:59:13 -0700483
484 // If there is no gateway, don't try to create a route to it.
485 if (!gateway_.IsValid()) {
486 return false;
487 }
488
Paul Stewart4a6748d2012-07-17 14:31:36 -0700489 // It is not worth keeping track of this route, since it is benign,
490 // and only pins persistent state that was already true of the connection.
491 // If DHCP parameters change later (without the connection having been
492 // destroyed and recreated), the binding processes will likely terminate
493 // and restart, causing a new link route to be created.
494 return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_);
Darin Petkov13e6d552012-05-09 14:22:23 +0200495}
496
497void Connection::OnLowerDisconnect() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700498 SLOG(this, 2) << __func__ << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200499 // Ensures that |this| instance doesn't get destroyed in the middle of
500 // notifying the binders. This method needs to be separate from
501 // NotifyBindersOnDisconnect because the latter may be invoked by Connection's
502 // destructor when |this| instance's reference count is already 0.
503 ConnectionRefPtr connection(this);
504 connection->NotifyBindersOnDisconnect();
505}
506
507void Connection::NotifyBindersOnDisconnect() {
508 // Note that this method may be invoked by the destructor.
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700509 SLOG(this, 2) << __func__ << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200510
511 // Unbinds the lower connection before notifying the binders. This ensures
512 // correct behavior in case of circular binding.
Ben Chancc225ef2014-09-30 13:26:51 -0700513 lower_binder_.Attach(nullptr);
Darin Petkov13e6d552012-05-09 14:22:23 +0200514 while (!binders_.empty()) {
515 // Pop the binder first and then notify it to ensure that each binder is
516 // notified only once.
517 Binder *binder = binders_.front();
518 binders_.pop_front();
519 binder->OnDisconnect();
520 }
521}
522
523void Connection::AttachBinder(Binder *binder) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700524 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ "
525 << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200526 binders_.push_back(binder);
527}
528
529void Connection::DetachBinder(Binder *binder) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700530 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ "
531 << interface_name_;
Paul Stewart6db7b242014-05-02 15:34:21 -0700532 for (auto it = binders_.begin(); it != binders_.end(); ++it) {
Darin Petkov13e6d552012-05-09 14:22:23 +0200533 if (binder == *it) {
534 binders_.erase(it);
535 return;
536 }
537 }
538}
539
Alex Deymofddc09a2013-07-03 18:41:31 -0700540ConnectionRefPtr Connection::GetCarrierConnection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700541 SLOG(this, 2) << __func__ << " @ " << interface_name_;
Alex Deymofddc09a2013-07-03 18:41:31 -0700542 set<Connection *> visited;
543 ConnectionRefPtr carrier = this;
544 while (carrier->GetLowerConnection()) {
545 if (ContainsKey(visited, carrier.get())) {
546 LOG(ERROR) << "Circular connection chain starting at: "
547 << carrier->interface_name();
548 // If a loop is detected return a NULL value to signal that the carrier
549 // connection is unknown.
Ben Chancc225ef2014-09-30 13:26:51 -0700550 return nullptr;
Alex Deymofddc09a2013-07-03 18:41:31 -0700551 }
552 visited.insert(carrier.get());
553 carrier = carrier->GetLowerConnection();
554 }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700555 SLOG(this, 2) << "Carrier connection: " << carrier->interface_name()
556 << " @ " << interface_name_;
Alex Deymofddc09a2013-07-03 18:41:31 -0700557 return carrier;
558}
559
Peter Qiuf3a8f902014-08-20 10:05:42 -0700560bool Connection::IsIPv6() {
561 return local_.family() == IPAddress::kFamilyIPv6;
562}
563
Paul Stewartdd60e452011-08-08 11:38:36 -0700564} // namespace shill