blob: add970e55a0445a57df14e1807115e9f7d1a5c67 [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"
Prabhu Kaliamoorthi77e76832015-02-13 15:20:23 +010017#include "shill/permission_broker_proxy.h"
18#include "shill/proxy_factory.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070019#include "shill/resolver.h"
20#include "shill/routing_table.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070021
Darin Petkov13e6d552012-05-09 14:22:23 +020022using base::Bind;
23using base::Closure;
24using base::Unretained;
25using std::deque;
Alex Deymofddc09a2013-07-03 18:41:31 -070026using std::set;
Paul Stewartdd60e452011-08-08 11:38:36 -070027using std::string;
Paul Stewartd62d6032012-09-11 11:35:49 -070028using std::vector;
Paul Stewartdd60e452011-08-08 11:38:36 -070029
30namespace shill {
31
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070032namespace Logging {
33static auto kModuleLogScope = ScopeLogger::kConnection;
34static string ObjectID(Connection *c) {
Paul Stewart55d95502015-05-02 00:35:41 -070035 if (c == nullptr)
36 return "(connection)";
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070037 return c->interface_name();
38}
39}
40
Paul Stewartdd60e452011-08-08 11:38:36 -070041// static
Ben Chan7fab8972014-08-10 17:14:46 -070042const uint32_t Connection::kDefaultMetric = 1;
Paul Stewartdd60e452011-08-08 11:38:36 -070043// static
Ben Chan7fab8972014-08-10 17:14:46 -070044const uint32_t Connection::kNonDefaultMetricBase = 10;
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +010045// static
46const uint32_t Connection::kMarkForUserTraffic = 0x1;
47// static
48const uint8_t Connection::kSecondaryTableId = 0x1;
Paul Stewartdd60e452011-08-08 11:38:36 -070049
Darin Petkov13e6d552012-05-09 14:22:23 +020050Connection::Binder::Binder(const string &name,
51 const Closure &disconnect_callback)
52 : name_(name),
Darin Petkov13e6d552012-05-09 14:22:23 +020053 client_disconnect_callback_(disconnect_callback) {}
54
55Connection::Binder::~Binder() {
Ben Chancc225ef2014-09-30 13:26:51 -070056 Attach(nullptr);
Darin Petkov13e6d552012-05-09 14:22:23 +020057}
58
Darin Petkovef1f9fe2012-05-11 16:51:52 +020059void Connection::Binder::Attach(const ConnectionRefPtr &to_connection) {
Darin Petkov13e6d552012-05-09 14:22:23 +020060 if (connection_) {
61 connection_->DetachBinder(this);
62 LOG(INFO) << name_ << ": unbound from connection: "
63 << connection_->interface_name();
Darin Petkovef1f9fe2012-05-11 16:51:52 +020064 connection_.reset();
Darin Petkov13e6d552012-05-09 14:22:23 +020065 }
Darin Petkovef1f9fe2012-05-11 16:51:52 +020066 if (to_connection) {
67 connection_ = to_connection->weak_ptr_factory_.GetWeakPtr();
Darin Petkov13e6d552012-05-09 14:22:23 +020068 connection_->AttachBinder(this);
69 LOG(INFO) << name_ << ": bound to connection: "
70 << connection_->interface_name();
71 }
72}
73
74void Connection::Binder::OnDisconnect() {
75 LOG(INFO) << name_ << ": bound connection disconnected: "
76 << connection_->interface_name();
Darin Petkovef1f9fe2012-05-11 16:51:52 +020077 connection_.reset();
Darin Petkov13e6d552012-05-09 14:22:23 +020078 if (!client_disconnect_callback_.is_null()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070079 SLOG(connection_.get(), 2) << "Running client disconnect callback.";
Darin Petkov13e6d552012-05-09 14:22:23 +020080 client_disconnect_callback_.Run();
81 }
82}
83
Paul Stewart9a908082011-08-31 12:18:48 -070084Connection::Connection(int interface_index,
85 const std::string& interface_name,
Paul Stewarte00600e2012-03-16 07:08:00 -070086 Technology::Identifier technology,
mukesh agrawal23ac6b72013-01-31 18:52:37 -080087 const DeviceInfo *device_info)
Darin Petkov13e6d552012-05-09 14:22:23 +020088 : weak_ptr_factory_(this),
89 is_default_(false),
Paul Stewart4a6748d2012-07-17 14:31:36 -070090 has_broadcast_domain_(false),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080091 routing_request_count_(0),
Paul Stewartdd60e452011-08-08 11:38:36 -070092 interface_index_(interface_index),
93 interface_name_(interface_name),
Paul Stewarte00600e2012-03-16 07:08:00 -070094 technology_(technology),
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +010095 user_traffic_only_(false),
96 table_id_(RT_TABLE_MAIN),
Paul Stewart4a6748d2012-07-17 14:31:36 -070097 local_(IPAddress::kFamilyUnknown),
98 gateway_(IPAddress::kFamilyUnknown),
Darin Petkov13e6d552012-05-09 14:22:23 +020099 lower_binder_(
100 interface_name_,
101 // Connection owns a single instance of |lower_binder_| so it's safe
102 // to use an Unretained callback.
103 Bind(&Connection::OnLowerDisconnect, Unretained(this))),
Paul Stewart9a908082011-08-31 12:18:48 -0700104 device_info_(device_info),
Paul Stewartdd60e452011-08-08 11:38:36 -0700105 resolver_(Resolver::GetInstance()),
106 routing_table_(RoutingTable::GetInstance()),
107 rtnl_handler_(RTNLHandler::GetInstance()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700108 SLOG(this, 2) << __func__ << "(" << interface_index << ", "
109 << interface_name << ", "
110 << Technology::NameFromIdentifier(technology) << ")";
Prabhu Kaliamoorthi77e76832015-02-13 15:20:23 +0100111 proxy_factory_ = ProxyFactory::GetInstance();
Paul Stewartdd60e452011-08-08 11:38:36 -0700112}
113
114Connection::~Connection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700115 SLOG(this, 2) << __func__ << " " << interface_name_;
Paul Stewart9a908082011-08-31 12:18:48 -0700116
Darin Petkov13e6d552012-05-09 14:22:23 +0200117 NotifyBindersOnDisconnect();
118
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800119 DCHECK(!routing_request_count_);
Thieu Lefb46caf2012-03-08 11:57:15 -0800120 routing_table_->FlushRoutes(interface_index_);
Paul Stewarte93b0382012-04-24 13:11:28 -0700121 routing_table_->FlushRoutesWithTag(interface_index_);
Paul Stewart9a908082011-08-31 12:18:48 -0700122 device_info_->FlushAddresses(interface_index_);
Prabhu Kaliamoorthi77e76832015-02-13 15:20:23 +0100123 TearDownIptableEntries();
Paul Stewartdd60e452011-08-08 11:38:36 -0700124}
125
126void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700127 SLOG(this, 2) << __func__ << " " << interface_name_;
Paul Stewarte6132022011-08-16 09:11:02 -0700128
Paul Stewart9a908082011-08-31 12:18:48 -0700129 const IPConfig::Properties &properties = config->properties();
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100130 user_traffic_only_ = properties.user_traffic_only;
131 table_id_ = user_traffic_only_ ? kSecondaryTableId : (uint8_t)RT_TABLE_MAIN;
132
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800133 IPAddress gateway(properties.address_family);
134 if (!properties.gateway.empty() &&
135 !gateway.SetAddressFromString(properties.gateway)) {
136 LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid";
Paul Stewarte93b0382012-04-24 13:11:28 -0700137 return;
138 }
139
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100140 excluded_ips_cidr_ = properties.exclusion_list;
141
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800142 IPAddress trusted_ip(properties.address_family);
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100143 if (!excluded_ips_cidr_.empty()) {
144 const std::string first_excluded_ip = excluded_ips_cidr_[0];
145 excluded_ips_cidr_.erase(excluded_ips_cidr_.begin());
146 // A VPN connection can currently be bound to exactly one lower connection
147 // such as eth0 or wan0. The excluded IPs are pinned to the gateway of
148 // that connection. Setting up the routing table this way ensures that when
149 // the lower connection goes offline, the associated entries in the routing
150 // table are removed. On the flip side, when there are multiple connections
151 // such as eth0 and wan0 and some IPs can be reached quickly over one
152 // connection and the others over a different connection, all routes are
153 // still pinned to a connection.
154 //
155 // The optimal connection to reach the first excluded IP is found below.
156 // When this is found the route for the remaining excluded IPs are pinned in
157 // the method PinPendingRoutes below.
158 if (!trusted_ip.SetAddressAndPrefixFromString(first_excluded_ip)) {
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800159 LOG(ERROR) << "Trusted IP address "
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100160 << first_excluded_ip << " is invalid";
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800161 return;
162 }
163 if (!PinHostRoute(trusted_ip, gateway)) {
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100164 LOG(ERROR) << "Unable to pin host route to " << first_excluded_ip;
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800165 return;
166 }
167 }
168
Paul Stewart9a908082011-08-31 12:18:48 -0700169 IPAddress local(properties.address_family);
170 if (!local.SetAddressFromString(properties.address)) {
171 LOG(ERROR) << "Local address " << properties.address << " is invalid";
172 return;
173 }
Paul Stewart48100b02012-03-19 07:53:52 -0700174 local.set_prefix(properties.subnet_prefix);
Paul Stewart9a908082011-08-31 12:18:48 -0700175
176 IPAddress broadcast(properties.address_family);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700177 if (properties.broadcast_address.empty()) {
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700178 if (properties.peer_address.empty()) {
Paul Stewart1062d9d2012-04-27 10:42:27 -0700179 LOG(WARNING) << "Broadcast address is not set. Using default.";
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700180 broadcast = local.GetDefaultBroadcast();
Paul Stewart1062d9d2012-04-27 10:42:27 -0700181 }
182 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
Paul Stewart9a908082011-08-31 12:18:48 -0700183 LOG(ERROR) << "Broadcast address " << properties.broadcast_address
184 << " is invalid";
185 return;
186 }
187
Paul Stewart48100b02012-03-19 07:53:52 -0700188 IPAddress peer(properties.address_family);
189 if (!properties.peer_address.empty() &&
190 !peer.SetAddressFromString(properties.peer_address)) {
191 LOG(ERROR) << "Peer address " << properties.peer_address
192 << " is invalid";
193 return;
194 }
195
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800196 if (!FixGatewayReachability(&local, &peer, &gateway, trusted_ip)) {
Paul Stewart53a30382012-04-26 09:06:59 -0700197 LOG(WARNING) << "Expect limited network connectivity.";
198 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700199
Paul Stewart05a42c22012-08-02 16:47:21 -0700200 if (device_info_->HasOtherAddress(interface_index_, local)) {
201 // The address has changed for this interface. We need to flush
202 // everything and start over.
203 LOG(INFO) << __func__ << ": Flushing old addresses and routes.";
204 routing_table_->FlushRoutes(interface_index_);
205 device_info_->FlushAddresses(interface_index_);
206 }
207
Paul Stewarte78ec542012-06-08 18:28:50 -0700208 LOG(INFO) << __func__ << ": Installing with parameters:"
209 << " local=" << local.ToString()
210 << " broadcast=" << broadcast.ToString()
211 << " peer=" << peer.ToString()
212 << " gateway=" << gateway.ToString();
Paul Stewart48100b02012-03-19 07:53:52 -0700213 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
Paul Stewartdd60e452011-08-08 11:38:36 -0700214
Prabhu Kaliamoorthi1f589032015-02-23 13:28:20 +0100215 if (gateway.IsValid() && properties.default_route) {
Paul Stewarte78ec542012-06-08 18:28:50 -0700216 routing_table_->SetDefaultRoute(interface_index_, gateway,
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100217 GetMetric(is_default_),
218 table_id_);
219 }
220
221 if (user_traffic_only_) {
Prabhu Kaliamoorthi77e76832015-02-13 15:20:23 +0100222 SetupIptableEntries();
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700223 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700224
Paul Stewart3f68bb12012-03-15 13:33:10 -0700225 // Install any explicitly configured routes at the default metric.
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100226 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric,
227 table_id_);
Paul Stewart3f68bb12012-03-15 13:33:10 -0700228
Paul Stewart024a6c82015-01-23 14:59:40 -0800229 SetMTU(properties.mtu);
230
Ben Chana0163122012-09-25 15:10:52 -0700231 if (properties.blackhole_ipv6) {
232 routing_table_->CreateBlackholeRoute(interface_index_,
233 IPAddress::kFamilyIPv6,
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100234 kDefaultMetric,
235 table_id_);
Ben Chana0163122012-09-25 15:10:52 -0700236 }
237
Paul Stewartd62d6032012-09-11 11:35:49 -0700238 // Save a copy of the last non-null DNS config.
Paul Stewartdd60e452011-08-08 11:38:36 -0700239 if (!config->properties().dns_servers.empty()) {
240 dns_servers_ = config->properties().dns_servers;
Paul Stewartd62d6032012-09-11 11:35:49 -0700241 }
242
243 if (!config->properties().domain_search.empty()) {
Paul Stewartdd60e452011-08-08 11:38:36 -0700244 dns_domain_search_ = config->properties().domain_search;
Paul Stewartd62d6032012-09-11 11:35:49 -0700245 }
246
247 if (!config->properties().domain_name.empty()) {
248 dns_domain_name_ = config->properties().domain_name;
Paul Stewartdd60e452011-08-08 11:38:36 -0700249 }
250
Paul Stewart10241e32012-04-23 18:15:06 -0700251 ipconfig_rpc_identifier_ = config->GetRpcIdentifier();
252
Peter Qiua89154b2014-05-23 15:45:42 -0700253 PushDNSConfig();
Paul Stewart4a6748d2012-07-17 14:31:36 -0700254
255 local_ = local;
256 gateway_ = gateway;
257 has_broadcast_domain_ = !peer.IsValid();
Paul Stewartdd60e452011-08-08 11:38:36 -0700258}
259
Prabhu Kaliamoorthi77e76832015-02-13 15:20:23 +0100260bool Connection::SetupIptableEntries() {
261 if (!permission_broker_) {
262 permission_broker_.reset(proxy_factory_->CreatePermissionBrokerProxy());
263 }
264
265 std::vector<std::string> user_names;
266 user_names.push_back("chronos");
267
268 if (!permission_broker_->RequestVpnSetup(user_names, interface_name_)) {
269 LOG(ERROR) << "VPN iptables setup request failed.";
270 return false;
271 }
272
273 return true;
274}
275
276bool Connection::TearDownIptableEntries() {
277 return permission_broker_ ? permission_broker_->RemoveVpnSetup() : true;
278}
279
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800280void Connection::SetIsDefault(bool is_default) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700281 SLOG(this, 2) << __func__ << " " << interface_name_
282 << " (index " << interface_index_ << ") "
283 << is_default_ << " -> " << is_default;
Paul Stewartdd60e452011-08-08 11:38:36 -0700284 if (is_default == is_default_) {
285 return;
286 }
287
Paul Stewart7cfca042011-12-08 14:18:17 -0800288 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
Paul Stewartdd60e452011-08-08 11:38:36 -0700289
Paul Stewartc681fa02012-03-02 19:40:04 -0800290 is_default_ = is_default;
291
Peter Qiua89154b2014-05-23 15:45:42 -0700292 PushDNSConfig();
Paul Stewartdd60e452011-08-08 11:38:36 -0700293 if (is_default) {
Paul Stewartc681fa02012-03-02 19:40:04 -0800294 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
295 if (device) {
296 device->RequestPortalDetection();
297 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700298 }
Paul Stewarte78ec542012-06-08 18:28:50 -0700299 routing_table_->FlushCache();
Paul Stewartdd60e452011-08-08 11:38:36 -0700300}
301
Peter Qiua89154b2014-05-23 15:45:42 -0700302void Connection::UpdateDNSServers(const vector<string> &dns_servers) {
303 dns_servers_ = dns_servers;
304 PushDNSConfig();
305}
306
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700307void Connection::PushDNSConfig() {
Peter Qiua89154b2014-05-23 15:45:42 -0700308 if (!is_default_) {
309 return;
310 }
311
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700312 vector<string> domain_search = dns_domain_search_;
313 if (domain_search.empty() && !dns_domain_name_.empty()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700314 SLOG(this, 2) << "Setting domain search to domain name "
315 << dns_domain_name_;
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700316 domain_search.push_back(dns_domain_name_ + ".");
317 }
mukesh agrawal23ac6b72013-01-31 18:52:37 -0800318 resolver_->SetDNSFromLists(dns_servers_, domain_search);
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700319}
320
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800321void Connection::RequestRouting() {
322 if (routing_request_count_++ == 0) {
323 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
324 DCHECK(device.get());
325 if (!device.get()) {
326 LOG(ERROR) << "Device is NULL!";
327 return;
328 }
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800329 device->SetLooseRouting(true);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800330 }
331}
332
333void Connection::ReleaseRouting() {
Alex Vakulenko8a532292014-06-16 17:18:44 -0700334 DCHECK_GT(routing_request_count_, 0);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800335 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 }
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800342 device->SetLooseRouting(false);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800343
344 // Clear any cached routes that might have accumulated while reverse-path
345 // filtering was disabled.
346 routing_table_->FlushCache();
347 }
348}
349
Paul Stewartf748a362012-03-07 12:01:20 -0800350bool Connection::RequestHostRoute(const IPAddress &address) {
Darin Petkov13e6d552012-05-09 14:22:23 +0200351 // Do not set interface_index_ since this may not be the default route through
352 // which this destination can be found. However, we should tag the created
353 // route with our interface index so we can clean this route up when this
354 // connection closes. Also, add route query callback to determine the lower
355 // connection and bind to it.
356 if (!routing_table_->RequestRouteToHost(
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100357 address,
Darin Petkov13e6d552012-05-09 14:22:23 +0200358 -1,
359 interface_index_,
Darin Petkov5eb05422012-05-11 15:45:25 +0200360 Bind(&Connection::OnRouteQueryResponse,
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100361 weak_ptr_factory_.GetWeakPtr()),
362 table_id_)) {
Paul Stewartf748a362012-03-07 12:01:20 -0800363 LOG(ERROR) << "Could not request route to " << address.ToString();
364 return false;
365 }
366
367 return true;
368}
369
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100370bool Connection::PinPendingRoutes(int interface_index,
371 RoutingTableEntry entry) {
372 // The variable entry is locally modified, hence is passed by value in the
373 // second argument above.
374 for (auto excluded_ip = excluded_ips_cidr_.begin();
375 excluded_ip != excluded_ips_cidr_.end(); ++excluded_ip) {
376 if (!entry.dst.SetAddressAndPrefixFromString(*excluded_ip) ||
377 !entry.dst.IsValid() ||
378 !routing_table_->AddRoute(interface_index, entry)) {
379 LOG(ERROR) << "Unable to setup route for " << *excluded_ip << ".";
380 }
381 }
382
383 return true;
384}
385
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800386string Connection::GetSubnetName() const {
Paul Stewart182888e2014-11-13 01:43:12 -0800387 if (!local().IsValid()) {
388 return "";
389 }
Paul Stewart2cb3fa72014-11-13 01:43:12 -0800390 return base::StringPrintf("%s/%d",
391 local().GetNetworkPart().ToString().c_str(),
392 local().prefix());
393}
394
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700395// static
Paul Stewart53a30382012-04-26 09:06:59 -0700396bool Connection::FixGatewayReachability(IPAddress *local,
Paul Stewart49258292012-05-26 06:37:14 -0700397 IPAddress *peer,
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800398 IPAddress *gateway,
399 const IPAddress &trusted_ip) {
Paul Stewart55d95502015-05-02 00:35:41 -0700400 SLOG(nullptr, 2) << __func__
401 << " local " << local->ToString()
402 << ", peer " << peer->ToString()
403 << ", gateway " << gateway->ToString()
404 << ", trusted_ip " << trusted_ip.ToString();
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800405 if (!gateway->IsValid()) {
Paul Stewart53a30382012-04-26 09:06:59 -0700406 LOG(WARNING) << "No gateway address was provided for this connection.";
407 return false;
408 }
409
Paul Stewart49258292012-05-26 06:37:14 -0700410 if (peer->IsValid()) {
Paul Stewart55d95502015-05-02 00:35:41 -0700411 if (!gateway->HasSameAddressAs(*peer)) {
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800412 LOG(WARNING) << "Gateway address "
413 << gateway->ToString()
414 << " does not match peer address "
415 << peer->ToString();
416 return false;
Paul Stewart53a30382012-04-26 09:06:59 -0700417 }
Paul Stewart55d95502015-05-02 00:35:41 -0700418 if (gateway->HasSameAddressAs(trusted_ip)) {
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800419 // In order to send outgoing traffic in a point-to-point network,
420 // the gateway IP address isn't of significance. As opposed to
421 // broadcast networks, we never ARP for the gateway IP address,
422 // but just send the IP packet addressed to the recipient. As
423 // such, since using the external trusted IP address as the
424 // gateway or peer wreaks havoc on the routing rules, we choose
425 // not to supply a gateway address. Here's an example:
426 //
427 // Client <-> Internet <-> VPN Gateway <-> Internal Network
428 // 192.168.1.2 10.0.1.25 172.16.5.0/24
429 //
430 // In this example, a client connects to a VPN gateway on its
431 // public IP address 10.0.1.25. It gets issued an IP address
432 // from the VPN internal pool. For some VPN gateways, this
433 // results in a pushed-down PPP configuration which specifies:
434 //
435 // Client local address: 172.16.5.13
436 // Client peer address: 10.0.1.25
437 // Client default gateway: 10.0.1.25
438 //
439 // If we take this literally, we need to resolve the fact that
440 // 10.0.1.25 is now listed as the default gateway and interface
441 // peer address for the point-to-point interface. However, in
442 // order to route tunneled packets to the VPN gateway we must
443 // use the external route through the physical interface and
444 // not the tunnel, or else we end up in an infinite loop
445 // re-entering the tunnel trying to route towards the VPN server.
446 //
447 // We can do this by pinning a route, but we would need to wait
448 // for the pinning process to complete before assigning this
449 // address. Currently this process is asynchronous and will
450 // complete only after returning to the event loop. Additionally,
451 // since there's no metric associated with assigning an address
452 // to an interface, it's always possible that having the peer
453 // address of the interface might still trump a host route.
454 //
455 // To solve this problem, we reset the peer and gateway
456 // addresses. Neither is required in order to perform the
457 // underlying routing task. A gateway route can be specified
458 // without an IP endpoint on point-to-point links, and simply
459 // specify the outbound interface index. Similarly, a peer
460 // IP address is not necessary either, and will be assigned
461 // the same IP address as the local IP. This approach
462 // simplifies routing and doesn't change the desired
463 // functional behavior.
464 //
465 LOG(INFO) << "Removing gateway and peer addresses to preserve "
466 << "routability to trusted IP address.";
467 peer->SetAddressToDefault();
468 gateway->SetAddressToDefault();
469 }
470 return true;
Paul Stewart53a30382012-04-26 09:06:59 -0700471 }
472
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800473 if (local->CanReachAddress(*gateway)) {
Paul Stewart53a30382012-04-26 09:06:59 -0700474 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700475 }
476
477 LOG(WARNING) << "Gateway "
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800478 << gateway->ToString()
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700479 << " is unreachable from local address/prefix "
480 << local->ToString() << "/" << local->prefix();
481
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700482 bool found_new_prefix = false;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700483 size_t original_prefix = local->prefix();
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700484 // Only try to expand the netmask if the configured prefix is
485 // less than "all ones". This special-cases the "all-ones"
486 // prefix as a forced conversion to point-to-point networking.
487 if (local->prefix() < IPAddress::GetMaxPrefixLength(local->family())) {
488 size_t prefix = original_prefix - 1;
489 for (; prefix >= local->GetMinPrefixLength(); --prefix) {
490 local->set_prefix(prefix);
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800491 if (local->CanReachAddress(*gateway)) {
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700492 found_new_prefix = true;
493 break;
494 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700495 }
496 }
497
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700498 if (!found_new_prefix) {
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700499 // Restore the original prefix since we cannot find a better one.
500 local->set_prefix(original_prefix);
Paul Stewart49258292012-05-26 06:37:14 -0700501 DCHECK(!peer->IsValid());
502 LOG(WARNING) << "Assuming point-to-point configuration.";
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800503 *peer = *gateway;
Paul Stewart49258292012-05-26 06:37:14 -0700504 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700505 }
Paul Stewart53a30382012-04-26 09:06:59 -0700506
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700507 LOG(WARNING) << "Mitigating this by setting local prefix to "
508 << local->prefix();
Paul Stewart53a30382012-04-26 09:06:59 -0700509 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700510}
511
Ben Chan7fab8972014-08-10 17:14:46 -0700512uint32_t Connection::GetMetric(bool is_default) {
Paul Stewart7cfca042011-12-08 14:18:17 -0800513 // If this is not the default route, assign a metric based on the interface
514 // index. This way all non-default routes (even to the same gateway IP) end
515 // up with unique metrics so they do not collide.
516 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
517}
518
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800519bool Connection::PinHostRoute(const IPAddress &trusted_ip,
520 const IPAddress &gateway) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700521 SLOG(this, 2) << __func__;
Paul Stewarte435d342013-09-27 16:41:00 -0700522 if (!trusted_ip.IsValid()) {
523 LOG(ERROR) << "No trusted IP -- unable to pin host route.";
Paul Stewarte93b0382012-04-24 13:11:28 -0700524 return false;
525 }
526
Paul Stewarte435d342013-09-27 16:41:00 -0700527 if (!gateway.IsValid()) {
528 // Although we cannot pin a host route, we are also not going to create
529 // a gateway route that will interfere with our primary connection, so
530 // it is okay to return success here.
531 LOG(WARNING) << "No gateway -- unable to pin host route.";
532 return true;
533 }
534
Paul Stewarte93b0382012-04-24 13:11:28 -0700535 return RequestHostRoute(trusted_ip);
536}
537
Paul Stewart024a6c82015-01-23 14:59:40 -0800538void Connection::SetMTU(int32_t mtu) {
539 SLOG(this, 2) << __func__ << " " << mtu;
540 // Make sure the MTU value is valid.
541 if (mtu == IPConfig::kUndefinedMTU) {
542 mtu = IPConfig::kDefaultMTU;
543 } else {
544 int min_mtu = IsIPv6() ? IPConfig::kMinIPv6MTU : IPConfig::kMinIPv4MTU;
545 if (mtu < min_mtu) {
546 SLOG(this, 2) << __func__ << " MTU " << mtu
547 << " is too small; adjusting up to " << min_mtu;
548 mtu = min_mtu;
549 }
550 }
551
552 rtnl_handler_->SetInterfaceMTU(interface_index_, mtu);
553}
554
Darin Petkov13e6d552012-05-09 14:22:23 +0200555void Connection::OnRouteQueryResponse(int interface_index,
556 const RoutingTableEntry &entry) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700557 SLOG(this, 2) << __func__ << "(" << interface_index << ", "
558 << entry.tag << ")" << " @ " << interface_name_;
Ben Chancc225ef2014-09-30 13:26:51 -0700559 lower_binder_.Attach(nullptr);
Darin Petkov13e6d552012-05-09 14:22:23 +0200560 DeviceRefPtr device = device_info_->GetDevice(interface_index);
561 if (!device) {
562 LOG(ERROR) << "Unable to lookup device for index " << interface_index;
563 return;
564 }
565 ConnectionRefPtr connection = device->connection();
566 if (!connection) {
567 LOG(ERROR) << "Device " << interface_index << " has no connection.";
568 return;
569 }
570 lower_binder_.Attach(connection);
Paul Stewart4a6748d2012-07-17 14:31:36 -0700571 connection->CreateGatewayRoute();
Paul Stewart8596f9f2013-03-14 07:58:26 -0700572 device->OnConnectionUpdated();
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100573 PinPendingRoutes(interface_index, entry);
Paul Stewart4a6748d2012-07-17 14:31:36 -0700574}
575
576bool Connection::CreateGatewayRoute() {
577 // Ensure that the gateway for the lower connection remains reachable,
578 // since we may create routes that conflict with it.
579 if (!has_broadcast_domain_) {
580 return false;
581 }
Paul Stewart856b8842013-07-10 11:59:13 -0700582
583 // If there is no gateway, don't try to create a route to it.
584 if (!gateway_.IsValid()) {
585 return false;
586 }
587
Paul Stewart4a6748d2012-07-17 14:31:36 -0700588 // It is not worth keeping track of this route, since it is benign,
589 // and only pins persistent state that was already true of the connection.
590 // If DHCP parameters change later (without the connection having been
591 // destroyed and recreated), the binding processes will likely terminate
592 // and restart, causing a new link route to be created.
Prabhu Kaliamoorthi762bfb82015-02-06 13:17:08 +0100593 return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_,
594 table_id_);
Darin Petkov13e6d552012-05-09 14:22:23 +0200595}
596
597void Connection::OnLowerDisconnect() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700598 SLOG(this, 2) << __func__ << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200599 // Ensures that |this| instance doesn't get destroyed in the middle of
600 // notifying the binders. This method needs to be separate from
601 // NotifyBindersOnDisconnect because the latter may be invoked by Connection's
602 // destructor when |this| instance's reference count is already 0.
603 ConnectionRefPtr connection(this);
604 connection->NotifyBindersOnDisconnect();
605}
606
607void Connection::NotifyBindersOnDisconnect() {
608 // Note that this method may be invoked by the destructor.
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700609 SLOG(this, 2) << __func__ << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200610
611 // Unbinds the lower connection before notifying the binders. This ensures
612 // correct behavior in case of circular binding.
Ben Chancc225ef2014-09-30 13:26:51 -0700613 lower_binder_.Attach(nullptr);
Darin Petkov13e6d552012-05-09 14:22:23 +0200614 while (!binders_.empty()) {
615 // Pop the binder first and then notify it to ensure that each binder is
616 // notified only once.
617 Binder *binder = binders_.front();
618 binders_.pop_front();
619 binder->OnDisconnect();
620 }
621}
622
623void Connection::AttachBinder(Binder *binder) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700624 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ "
625 << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200626 binders_.push_back(binder);
627}
628
629void Connection::DetachBinder(Binder *binder) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700630 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ "
631 << interface_name_;
Paul Stewart6db7b242014-05-02 15:34:21 -0700632 for (auto it = binders_.begin(); it != binders_.end(); ++it) {
Darin Petkov13e6d552012-05-09 14:22:23 +0200633 if (binder == *it) {
634 binders_.erase(it);
635 return;
636 }
637 }
638}
639
Alex Deymofddc09a2013-07-03 18:41:31 -0700640ConnectionRefPtr Connection::GetCarrierConnection() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700641 SLOG(this, 2) << __func__ << " @ " << interface_name_;
Alex Deymofddc09a2013-07-03 18:41:31 -0700642 set<Connection *> visited;
643 ConnectionRefPtr carrier = this;
644 while (carrier->GetLowerConnection()) {
645 if (ContainsKey(visited, carrier.get())) {
646 LOG(ERROR) << "Circular connection chain starting at: "
647 << carrier->interface_name();
648 // If a loop is detected return a NULL value to signal that the carrier
649 // connection is unknown.
Ben Chancc225ef2014-09-30 13:26:51 -0700650 return nullptr;
Alex Deymofddc09a2013-07-03 18:41:31 -0700651 }
652 visited.insert(carrier.get());
653 carrier = carrier->GetLowerConnection();
654 }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700655 SLOG(this, 2) << "Carrier connection: " << carrier->interface_name()
656 << " @ " << interface_name_;
Alex Deymofddc09a2013-07-03 18:41:31 -0700657 return carrier;
658}
659
Peter Qiuf3a8f902014-08-20 10:05:42 -0700660bool Connection::IsIPv6() {
661 return local_.family() == IPAddress::kFamilyIPv6;
662}
663
Paul Stewartdd60e452011-08-08 11:38:36 -0700664} // namespace shill