blob: 655b06fa64790007ca5763d366fbe19eeb1ddb43 [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
10#include "shill/device_info.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070011#include "shill/resolver.h"
12#include "shill/routing_table.h"
13#include "shill/rtnl_handler.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070014#include "shill/scope_logger.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070015
16using std::string;
17
18namespace shill {
19
20// static
21const uint32 Connection::kDefaultMetric = 1;
22// static
Paul Stewart7cfca042011-12-08 14:18:17 -080023const uint32 Connection::kNonDefaultMetricBase = 10;
Paul Stewartdd60e452011-08-08 11:38:36 -070024
Paul Stewart9a908082011-08-31 12:18:48 -070025Connection::Connection(int interface_index,
26 const std::string& interface_name,
Paul Stewarte00600e2012-03-16 07:08:00 -070027 Technology::Identifier technology,
Paul Stewart9a908082011-08-31 12:18:48 -070028 const DeviceInfo *device_info)
Paul Stewartdd60e452011-08-08 11:38:36 -070029 : is_default_(false),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080030 routing_request_count_(0),
Paul Stewartdd60e452011-08-08 11:38:36 -070031 interface_index_(interface_index),
32 interface_name_(interface_name),
Paul Stewarte00600e2012-03-16 07:08:00 -070033 technology_(technology),
Paul Stewart9a908082011-08-31 12:18:48 -070034 device_info_(device_info),
Paul Stewartdd60e452011-08-08 11:38:36 -070035 resolver_(Resolver::GetInstance()),
36 routing_table_(RoutingTable::GetInstance()),
37 rtnl_handler_(RTNLHandler::GetInstance()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070038 SLOG(Connection, 2) << __func__ << "(" << interface_index << ", "
39 << interface_name << ", "
40 << Technology::NameFromIdentifier(technology) << ")";
Paul Stewartdd60e452011-08-08 11:38:36 -070041}
42
43Connection::~Connection() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070044 SLOG(Connection, 2) << __func__ << " " << interface_name_;
Paul Stewart9a908082011-08-31 12:18:48 -070045
Paul Stewartc8f4bef2011-12-13 09:45:51 -080046 DCHECK(!routing_request_count_);
Thieu Lefb46caf2012-03-08 11:57:15 -080047 routing_table_->FlushRoutes(interface_index_);
Paul Stewarte93b0382012-04-24 13:11:28 -070048 routing_table_->FlushRoutesWithTag(interface_index_);
Paul Stewart9a908082011-08-31 12:18:48 -070049 device_info_->FlushAddresses(interface_index_);
Paul Stewartdd60e452011-08-08 11:38:36 -070050}
51
52void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070053 SLOG(Connection, 2) << __func__ << " " << interface_name_;
Paul Stewarte6132022011-08-16 09:11:02 -070054
Paul Stewart9a908082011-08-31 12:18:48 -070055 const IPConfig::Properties &properties = config->properties();
Paul Stewarte93b0382012-04-24 13:11:28 -070056 if (!properties.trusted_ip.empty() && !PinHostRoute(properties)) {
57 LOG(ERROR) << "Unable to pin host route to " << properties.trusted_ip;
58 return;
59 }
60
Paul Stewart9a908082011-08-31 12:18:48 -070061 IPAddress local(properties.address_family);
62 if (!local.SetAddressFromString(properties.address)) {
63 LOG(ERROR) << "Local address " << properties.address << " is invalid";
64 return;
65 }
Paul Stewart48100b02012-03-19 07:53:52 -070066 local.set_prefix(properties.subnet_prefix);
Paul Stewart9a908082011-08-31 12:18:48 -070067
68 IPAddress broadcast(properties.address_family);
Paul Stewart1062d9d2012-04-27 10:42:27 -070069 if (properties.broadcast_address.empty()) {
Paul Stewartfe1c0e12012-04-30 19:57:04 -070070 if (properties.peer_address.empty()) {
Paul Stewart1062d9d2012-04-27 10:42:27 -070071 LOG(WARNING) << "Broadcast address is not set. Using default.";
Paul Stewartfe1c0e12012-04-30 19:57:04 -070072 broadcast = local.GetDefaultBroadcast();
Paul Stewart1062d9d2012-04-27 10:42:27 -070073 }
74 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
Paul Stewart9a908082011-08-31 12:18:48 -070075 LOG(ERROR) << "Broadcast address " << properties.broadcast_address
76 << " is invalid";
77 return;
78 }
79
Paul Stewart48100b02012-03-19 07:53:52 -070080 IPAddress peer(properties.address_family);
81 if (!properties.peer_address.empty() &&
82 !peer.SetAddressFromString(properties.peer_address)) {
83 LOG(ERROR) << "Peer address " << properties.peer_address
84 << " is invalid";
85 return;
86 }
87
Paul Stewart5b7ba8c2012-04-18 09:08:00 -070088 IPAddress gateway_address(properties.address_family);
89 if (!properties.gateway.empty() &&
90 !gateway_address.SetAddressFromString(properties.gateway)) {
91 LOG(ERROR) << "Gateway address " << properties.peer_address
92 << " is invalid";
93 return;
94 }
95
Paul Stewart53a30382012-04-26 09:06:59 -070096 if (!FixGatewayReachability(&local, gateway_address, peer)) {
97 LOG(WARNING) << "Expect limited network connectivity.";
98 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -070099
Paul Stewart48100b02012-03-19 07:53:52 -0700100 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
Paul Stewartdd60e452011-08-08 11:38:36 -0700101
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700102 if (gateway_address.IsValid()) {
103 routing_table_->SetDefaultRoute(interface_index_, gateway_address,
104 GetMetric(is_default_));
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700105 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700106
Paul Stewart3f68bb12012-03-15 13:33:10 -0700107 // Install any explicitly configured routes at the default metric.
108 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric);
109
Paul Stewartdd60e452011-08-08 11:38:36 -0700110 // Save a copy of the last non-null DNS config
111 if (!config->properties().dns_servers.empty()) {
112 dns_servers_ = config->properties().dns_servers;
113 dns_domain_search_ = config->properties().domain_search;
114 }
115
Paul Stewart10241e32012-04-23 18:15:06 -0700116 ipconfig_rpc_identifier_ = config->GetRpcIdentifier();
117
Paul Stewartdd60e452011-08-08 11:38:36 -0700118 if (is_default_) {
119 resolver_->SetDNSFromIPConfig(config);
120 }
121}
122
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800123void Connection::SetIsDefault(bool is_default) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700124 SLOG(Connection, 2) << __func__ << " " << interface_name_
125 << " (index " << interface_index_ << ") "
126 << is_default_ << " -> " << is_default;
Paul Stewartdd60e452011-08-08 11:38:36 -0700127 if (is_default == is_default_) {
128 return;
129 }
130
Paul Stewart7cfca042011-12-08 14:18:17 -0800131 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
Paul Stewartdd60e452011-08-08 11:38:36 -0700132
Paul Stewartc681fa02012-03-02 19:40:04 -0800133 is_default_ = is_default;
134
Paul Stewartdd60e452011-08-08 11:38:36 -0700135 if (is_default) {
136 resolver_->SetDNSFromLists(dns_servers_, dns_domain_search_);
Paul Stewartc681fa02012-03-02 19:40:04 -0800137 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
138 if (device) {
139 device->RequestPortalDetection();
140 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700141 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700142}
143
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800144void Connection::RequestRouting() {
145 if (routing_request_count_++ == 0) {
146 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
147 DCHECK(device.get());
148 if (!device.get()) {
149 LOG(ERROR) << "Device is NULL!";
150 return;
151 }
152 device->DisableReversePathFilter();
153 }
154}
155
156void Connection::ReleaseRouting() {
157 DCHECK(routing_request_count_ > 0);
158 if (--routing_request_count_ == 0) {
159 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
160 DCHECK(device.get());
161 if (!device.get()) {
162 LOG(ERROR) << "Device is NULL!";
163 return;
164 }
165 device->EnableReversePathFilter();
166
167 // Clear any cached routes that might have accumulated while reverse-path
168 // filtering was disabled.
169 routing_table_->FlushCache();
170 }
171}
172
Paul Stewartf748a362012-03-07 12:01:20 -0800173bool Connection::RequestHostRoute(const IPAddress &address) {
174 // Set the prefix to be the entire address size.
175 IPAddress address_prefix(address);
176 address_prefix.set_prefix(address_prefix.GetLength() * 8);
177
Paul Stewart536820d2012-03-19 16:05:59 -0700178 // Do not set interface_index_ since this may not be the
179 // default route through which this destination can be found.
Paul Stewarte93b0382012-04-24 13:11:28 -0700180 // However, we should tag the created route with our interface
181 // index so we can clean this route up when this connection closes.
182 if (!routing_table_->RequestRouteToHost(address_prefix, -1,
183 interface_index_)) {
Paul Stewartf748a362012-03-07 12:01:20 -0800184 LOG(ERROR) << "Could not request route to " << address.ToString();
185 return false;
186 }
187
188 return true;
189}
190
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700191// static
Paul Stewart53a30382012-04-26 09:06:59 -0700192bool Connection::FixGatewayReachability(IPAddress *local,
193 const IPAddress &gateway,
194 const IPAddress &peer) {
195 if (!gateway.IsValid()) {
196 LOG(WARNING) << "No gateway address was provided for this connection.";
197 return false;
198 }
199
200 if (peer.IsValid()) {
201 if (gateway.Equals(peer)) {
202 return true;
203 }
204 LOG(WARNING) << "Gateway address "
205 << gateway.ToString()
206 << " does not match peer address "
207 << peer.ToString();
208 return false;
209 }
210
211 if (local->CanReachAddress(gateway)) {
212 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700213 }
214
215 LOG(WARNING) << "Gateway "
216 << gateway.ToString()
217 << " is unreachable from local address/prefix "
218 << local->ToString() << "/" << local->prefix();
219
220 size_t original_prefix = local->prefix();
221 size_t prefix = original_prefix - 1;
222 for (; prefix >= local->GetMinPrefixLength(); --prefix) {
223 local->set_prefix(prefix);
224 if (local->CanReachAddress(gateway)) {
225 break;
226 }
227 }
228
229 if (prefix < local->GetMinPrefixLength()) {
230 // Restore the original prefix since we cannot find a better one.
231 local->set_prefix(original_prefix);
Paul Stewart53a30382012-04-26 09:06:59 -0700232 return false;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700233 }
Paul Stewart53a30382012-04-26 09:06:59 -0700234
235 LOG(WARNING) << "Mitigating this by setting local prefix to " << prefix;
236 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700237}
238
Paul Stewart7cfca042011-12-08 14:18:17 -0800239uint32 Connection::GetMetric(bool is_default) {
240 // If this is not the default route, assign a metric based on the interface
241 // index. This way all non-default routes (even to the same gateway IP) end
242 // up with unique metrics so they do not collide.
243 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
244}
245
Paul Stewarte93b0382012-04-24 13:11:28 -0700246bool Connection::PinHostRoute(const IPConfig::Properties &properties) {
247 SLOG(Connection, 2) << __func__;
248 if (properties.gateway.empty() || properties.trusted_ip.empty()) {
249 return false;
250 }
251
252 IPAddress trusted_ip(properties.address_family);
253 if (!trusted_ip.SetAddressFromString(properties.trusted_ip)) {
254 LOG(ERROR) << "Failed to parse trusted_ip "
255 << properties.trusted_ip << "; ignored.";
256 return false;
257 }
258
259 return RequestHostRoute(trusted_ip);
260}
261
Paul Stewartdd60e452011-08-08 11:38:36 -0700262} // namespace shill