connection.cc revision a794cd60a7339d576ea2eed263a4f0a20fb255af
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/permission_broker_proxy.h" 18#include "shill/proxy_factory.h" 19#include "shill/resolver.h" 20#include "shill/routing_table.h" 21 22using base::Bind; 23using base::Closure; 24using base::Unretained; 25using std::deque; 26using std::set; 27using std::string; 28using std::vector; 29 30namespace shill { 31 32namespace Logging { 33static auto kModuleLogScope = ScopeLogger::kConnection; 34static string ObjectID(Connection* c) { 35 if (c == nullptr) 36 return "(connection)"; 37 return c->interface_name(); 38} 39} 40 41// static 42const uint32_t Connection::kDefaultMetric = 1; 43// static 44const uint32_t Connection::kNonDefaultMetricBase = 10; 45// static 46const uint32_t Connection::kMarkForUserTraffic = 0x1; 47// static 48const uint8_t Connection::kSecondaryTableId = 0x1; 49 50Connection::Binder::Binder(const string& name, 51 const Closure& disconnect_callback) 52 : name_(name), 53 client_disconnect_callback_(disconnect_callback) {} 54 55Connection::Binder::~Binder() { 56 Attach(nullptr); 57} 58 59void Connection::Binder::Attach(const ConnectionRefPtr& to_connection) { 60 if (connection_) { 61 connection_->DetachBinder(this); 62 LOG(INFO) << name_ << ": unbound from connection: " 63 << connection_->interface_name(); 64 connection_.reset(); 65 } 66 if (to_connection) { 67 connection_ = to_connection->weak_ptr_factory_.GetWeakPtr(); 68 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(); 77 connection_.reset(); 78 if (!client_disconnect_callback_.is_null()) { 79 SLOG(connection_.get(), 2) << "Running client disconnect callback."; 80 client_disconnect_callback_.Run(); 81 } 82} 83 84Connection::Connection(int interface_index, 85 const std::string& interface_name, 86 Technology::Identifier technology, 87 const DeviceInfo* device_info) 88 : weak_ptr_factory_(this), 89 is_default_(false), 90 has_broadcast_domain_(false), 91 routing_request_count_(0), 92 interface_index_(interface_index), 93 interface_name_(interface_name), 94 technology_(technology), 95 user_traffic_only_(false), 96 table_id_(RT_TABLE_MAIN), 97 local_(IPAddress::kFamilyUnknown), 98 gateway_(IPAddress::kFamilyUnknown), 99 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))), 104 device_info_(device_info), 105 resolver_(Resolver::GetInstance()), 106 routing_table_(RoutingTable::GetInstance()), 107 rtnl_handler_(RTNLHandler::GetInstance()) { 108 SLOG(this, 2) << __func__ << "(" << interface_index << ", " 109 << interface_name << ", " 110 << Technology::NameFromIdentifier(technology) << ")"; 111 proxy_factory_ = ProxyFactory::GetInstance(); 112} 113 114Connection::~Connection() { 115 SLOG(this, 2) << __func__ << " " << interface_name_; 116 117 NotifyBindersOnDisconnect(); 118 119 DCHECK(!routing_request_count_); 120 routing_table_->FlushRoutes(interface_index_); 121 routing_table_->FlushRoutesWithTag(interface_index_); 122 device_info_->FlushAddresses(interface_index_); 123 TearDownIptableEntries(); 124} 125 126void Connection::UpdateFromIPConfig(const IPConfigRefPtr& config) { 127 SLOG(this, 2) << __func__ << " " << interface_name_; 128 129 const IPConfig::Properties& properties = config->properties(); 130 user_traffic_only_ = properties.user_traffic_only; 131 table_id_ = user_traffic_only_ ? kSecondaryTableId : (uint8_t)RT_TABLE_MAIN; 132 133 IPAddress gateway(properties.address_family); 134 if (!properties.gateway.empty() && 135 !gateway.SetAddressFromString(properties.gateway)) { 136 LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid"; 137 return; 138 } 139 140 excluded_ips_cidr_ = properties.exclusion_list; 141 142 IPAddress trusted_ip(properties.address_family); 143 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)) { 159 LOG(ERROR) << "Trusted IP address " 160 << first_excluded_ip << " is invalid"; 161 return; 162 } 163 if (!PinHostRoute(trusted_ip, gateway)) { 164 LOG(ERROR) << "Unable to pin host route to " << first_excluded_ip; 165 return; 166 } 167 } 168 169 IPAddress local(properties.address_family); 170 if (!local.SetAddressFromString(properties.address)) { 171 LOG(ERROR) << "Local address " << properties.address << " is invalid"; 172 return; 173 } 174 local.set_prefix(properties.subnet_prefix); 175 176 IPAddress broadcast(properties.address_family); 177 if (properties.broadcast_address.empty()) { 178 if (properties.peer_address.empty()) { 179 LOG(WARNING) << "Broadcast address is not set. Using default."; 180 broadcast = local.GetDefaultBroadcast(); 181 } 182 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) { 183 LOG(ERROR) << "Broadcast address " << properties.broadcast_address 184 << " is invalid"; 185 return; 186 } 187 188 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 196 if (!FixGatewayReachability(&local, &peer, &gateway, trusted_ip)) { 197 LOG(WARNING) << "Expect limited network connectivity."; 198 } 199 200 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 208 LOG(INFO) << __func__ << ": Installing with parameters:" 209 << " local=" << local.ToString() 210 << " broadcast=" << broadcast.ToString() 211 << " peer=" << peer.ToString() 212 << " gateway=" << gateway.ToString(); 213 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer); 214 215 if (gateway.IsValid() && properties.default_route) { 216 routing_table_->SetDefaultRoute(interface_index_, gateway, 217 GetMetric(is_default_), 218 table_id_); 219 } 220 221 if (user_traffic_only_) { 222 SetupIptableEntries(); 223 } 224 225 // Install any explicitly configured routes at the default metric. 226 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric, 227 table_id_); 228 229 SetMTU(properties.mtu); 230 231 if (properties.blackhole_ipv6) { 232 routing_table_->CreateBlackholeRoute(interface_index_, 233 IPAddress::kFamilyIPv6, 234 kDefaultMetric, 235 table_id_); 236 } 237 238 // Save a copy of the last non-null DNS config. 239 if (!config->properties().dns_servers.empty()) { 240 dns_servers_ = config->properties().dns_servers; 241 } 242 243 if (!config->properties().domain_search.empty()) { 244 dns_domain_search_ = config->properties().domain_search; 245 } 246 247 if (!config->properties().domain_name.empty()) { 248 dns_domain_name_ = config->properties().domain_name; 249 } 250 251 ipconfig_rpc_identifier_ = config->GetRpcIdentifier(); 252 253 PushDNSConfig(); 254 255 local_ = local; 256 gateway_ = gateway; 257 has_broadcast_domain_ = !peer.IsValid(); 258} 259 260bool 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 280void Connection::SetIsDefault(bool is_default) { 281 SLOG(this, 2) << __func__ << " " << interface_name_ 282 << " (index " << interface_index_ << ") " 283 << is_default_ << " -> " << is_default; 284 if (is_default == is_default_) { 285 return; 286 } 287 288 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default)); 289 290 is_default_ = is_default; 291 292 PushDNSConfig(); 293 if (is_default) { 294 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 295 if (device) { 296 device->RequestPortalDetection(); 297 } 298 } 299 routing_table_->FlushCache(); 300} 301 302void Connection::UpdateDNSServers(const vector<string>& dns_servers) { 303 dns_servers_ = dns_servers; 304 PushDNSConfig(); 305} 306 307void Connection::PushDNSConfig() { 308 if (!is_default_) { 309 return; 310 } 311 312 vector<string> domain_search = dns_domain_search_; 313 if (domain_search.empty() && !dns_domain_name_.empty()) { 314 SLOG(this, 2) << "Setting domain search to domain name " 315 << dns_domain_name_; 316 domain_search.push_back(dns_domain_name_ + "."); 317 } 318 resolver_->SetDNSFromLists(dns_servers_, domain_search); 319} 320 321void 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 } 329 device->SetLooseRouting(true); 330 } 331} 332 333void Connection::ReleaseRouting() { 334 DCHECK_GT(routing_request_count_, 0); 335 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 } 342 device->SetLooseRouting(false); 343 344 // Clear any cached routes that might have accumulated while reverse-path 345 // filtering was disabled. 346 routing_table_->FlushCache(); 347 } 348} 349 350bool Connection::RequestHostRoute(const IPAddress& address) { 351 // 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( 357 address, 358 -1, 359 interface_index_, 360 Bind(&Connection::OnRouteQueryResponse, 361 weak_ptr_factory_.GetWeakPtr()), 362 table_id_)) { 363 LOG(ERROR) << "Could not request route to " << address.ToString(); 364 return false; 365 } 366 367 return true; 368} 369 370bool 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 386string Connection::GetSubnetName() const { 387 if (!local().IsValid()) { 388 return ""; 389 } 390 return base::StringPrintf("%s/%d", 391 local().GetNetworkPart().ToString().c_str(), 392 local().prefix()); 393} 394 395// static 396bool Connection::FixGatewayReachability(IPAddress* local, 397 IPAddress* peer, 398 IPAddress* gateway, 399 const IPAddress& trusted_ip) { 400 SLOG(nullptr, 2) << __func__ 401 << " local " << local->ToString() 402 << ", peer " << peer->ToString() 403 << ", gateway " << gateway->ToString() 404 << ", trusted_ip " << trusted_ip.ToString(); 405 if (!gateway->IsValid()) { 406 LOG(WARNING) << "No gateway address was provided for this connection."; 407 return false; 408 } 409 410 if (peer->IsValid()) { 411 if (!gateway->HasSameAddressAs(*peer)) { 412 LOG(WARNING) << "Gateway address " 413 << gateway->ToString() 414 << " does not match peer address " 415 << peer->ToString(); 416 return false; 417 } 418 if (gateway->HasSameAddressAs(trusted_ip)) { 419 // 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; 471 } 472 473 if (local->CanReachAddress(*gateway)) { 474 return true; 475 } 476 477 LOG(WARNING) << "Gateway " 478 << gateway->ToString() 479 << " is unreachable from local address/prefix " 480 << local->ToString() << "/" << local->prefix(); 481 482 bool found_new_prefix = false; 483 size_t original_prefix = local->prefix(); 484 // 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); 491 if (local->CanReachAddress(*gateway)) { 492 found_new_prefix = true; 493 break; 494 } 495 } 496 } 497 498 if (!found_new_prefix) { 499 // Restore the original prefix since we cannot find a better one. 500 local->set_prefix(original_prefix); 501 DCHECK(!peer->IsValid()); 502 LOG(WARNING) << "Assuming point-to-point configuration."; 503 *peer = *gateway; 504 return true; 505 } 506 507 LOG(WARNING) << "Mitigating this by setting local prefix to " 508 << local->prefix(); 509 return true; 510} 511 512uint32_t Connection::GetMetric(bool is_default) { 513 // 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 519bool Connection::PinHostRoute(const IPAddress& trusted_ip, 520 const IPAddress& gateway) { 521 SLOG(this, 2) << __func__; 522 if (!trusted_ip.IsValid()) { 523 LOG(ERROR) << "No trusted IP -- unable to pin host route."; 524 return false; 525 } 526 527 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 535 return RequestHostRoute(trusted_ip); 536} 537 538void 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 555void Connection::OnRouteQueryResponse(int interface_index, 556 const RoutingTableEntry& entry) { 557 SLOG(this, 2) << __func__ << "(" << interface_index << ", " 558 << entry.tag << ")" << " @ " << interface_name_; 559 lower_binder_.Attach(nullptr); 560 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); 571 connection->CreateGatewayRoute(); 572 device->OnConnectionUpdated(); 573 PinPendingRoutes(interface_index, entry); 574} 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 } 582 583 // If there is no gateway, don't try to create a route to it. 584 if (!gateway_.IsValid()) { 585 return false; 586 } 587 588 // 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. 593 return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_, 594 table_id_); 595} 596 597void Connection::OnLowerDisconnect() { 598 SLOG(this, 2) << __func__ << " @ " << interface_name_; 599 // 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. 609 SLOG(this, 2) << __func__ << " @ " << interface_name_; 610 611 // Unbinds the lower connection before notifying the binders. This ensures 612 // correct behavior in case of circular binding. 613 lower_binder_.Attach(nullptr); 614 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) { 624 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ " 625 << interface_name_; 626 binders_.push_back(binder); 627} 628 629void Connection::DetachBinder(Binder* binder) { 630 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ " 631 << interface_name_; 632 for (auto it = binders_.begin(); it != binders_.end(); ++it) { 633 if (binder == *it) { 634 binders_.erase(it); 635 return; 636 } 637 } 638} 639 640ConnectionRefPtr Connection::GetCarrierConnection() { 641 SLOG(this, 2) << __func__ << " @ " << interface_name_; 642 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. 650 return nullptr; 651 } 652 visited.insert(carrier.get()); 653 carrier = carrier->GetLowerConnection(); 654 } 655 SLOG(this, 2) << "Carrier connection: " << carrier->interface_name() 656 << " @ " << interface_name_; 657 return carrier; 658} 659 660bool Connection::IsIPv6() { 661 return local_.family() == IPAddress::kFamilyIPv6; 662} 663 664} // namespace shill 665