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