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