connection.cc revision 608ec29525f553d51f0a92e84176e3d4b45930a9
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/control_interface.h" 15#include "shill/device_info.h" 16#include "shill/logging.h" 17#include "shill/net/rtnl_handler.h" 18#include "shill/permission_broker_proxy.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 ControlInterface* control_interface) 89 : weak_ptr_factory_(this), 90 is_default_(false), 91 has_broadcast_domain_(false), 92 routing_request_count_(0), 93 interface_index_(interface_index), 94 interface_name_(interface_name), 95 technology_(technology), 96 user_traffic_only_(false), 97 table_id_(RT_TABLE_MAIN), 98 local_(IPAddress::kFamilyUnknown), 99 gateway_(IPAddress::kFamilyUnknown), 100 lower_binder_( 101 interface_name_, 102 // Connection owns a single instance of |lower_binder_| so it's safe 103 // to use an Unretained callback. 104 Bind(&Connection::OnLowerDisconnect, Unretained(this))), 105 device_info_(device_info), 106 resolver_(Resolver::GetInstance()), 107 routing_table_(RoutingTable::GetInstance()), 108 rtnl_handler_(RTNLHandler::GetInstance()), 109 control_interface_(control_interface) { 110 SLOG(this, 2) << __func__ << "(" << interface_index << ", " 111 << interface_name << ", " 112 << Technology::NameFromIdentifier(technology) << ")"; 113} 114 115Connection::~Connection() { 116 SLOG(this, 2) << __func__ << " " << interface_name_; 117 118 NotifyBindersOnDisconnect(); 119 120 DCHECK(!routing_request_count_); 121 routing_table_->FlushRoutes(interface_index_); 122 routing_table_->FlushRoutesWithTag(interface_index_); 123 device_info_->FlushAddresses(interface_index_); 124 TearDownIptableEntries(); 125} 126 127void Connection::UpdateFromIPConfig(const IPConfigRefPtr& config) { 128 SLOG(this, 2) << __func__ << " " << interface_name_; 129 130 const IPConfig::Properties& properties = config->properties(); 131 user_traffic_only_ = properties.user_traffic_only; 132 table_id_ = user_traffic_only_ ? kSecondaryTableId : (uint8_t)RT_TABLE_MAIN; 133 134 IPAddress gateway(properties.address_family); 135 if (!properties.gateway.empty() && 136 !gateway.SetAddressFromString(properties.gateway)) { 137 LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid"; 138 return; 139 } 140 141 excluded_ips_cidr_ = properties.exclusion_list; 142 143 IPAddress trusted_ip(properties.address_family); 144 if (!excluded_ips_cidr_.empty()) { 145 const std::string first_excluded_ip = excluded_ips_cidr_[0]; 146 excluded_ips_cidr_.erase(excluded_ips_cidr_.begin()); 147 // A VPN connection can currently be bound to exactly one lower connection 148 // such as eth0 or wan0. The excluded IPs are pinned to the gateway of 149 // that connection. Setting up the routing table this way ensures that when 150 // the lower connection goes offline, the associated entries in the routing 151 // table are removed. On the flip side, when there are multiple connections 152 // such as eth0 and wan0 and some IPs can be reached quickly over one 153 // connection and the others over a different connection, all routes are 154 // still pinned to a connection. 155 // 156 // The optimal connection to reach the first excluded IP is found below. 157 // When this is found the route for the remaining excluded IPs are pinned in 158 // the method PinPendingRoutes below. 159 if (!trusted_ip.SetAddressAndPrefixFromString(first_excluded_ip)) { 160 LOG(ERROR) << "Trusted IP address " 161 << first_excluded_ip << " is invalid"; 162 return; 163 } 164 if (!PinHostRoute(trusted_ip, gateway)) { 165 LOG(ERROR) << "Unable to pin host route to " << first_excluded_ip; 166 return; 167 } 168 } 169 170 IPAddress local(properties.address_family); 171 if (!local.SetAddressFromString(properties.address)) { 172 LOG(ERROR) << "Local address " << properties.address << " is invalid"; 173 return; 174 } 175 local.set_prefix(properties.subnet_prefix); 176 177 IPAddress broadcast(properties.address_family); 178 if (properties.broadcast_address.empty()) { 179 if (properties.peer_address.empty()) { 180 LOG(WARNING) << "Broadcast address is not set. Using default."; 181 broadcast = local.GetDefaultBroadcast(); 182 } 183 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) { 184 LOG(ERROR) << "Broadcast address " << properties.broadcast_address 185 << " is invalid"; 186 return; 187 } 188 189 IPAddress peer(properties.address_family); 190 if (!properties.peer_address.empty() && 191 !peer.SetAddressFromString(properties.peer_address)) { 192 LOG(ERROR) << "Peer address " << properties.peer_address 193 << " is invalid"; 194 return; 195 } 196 197 if (!FixGatewayReachability(local, &peer, &gateway, trusted_ip)) { 198 LOG(WARNING) << "Expect limited network connectivity."; 199 } 200 201 if (device_info_->HasOtherAddress(interface_index_, local)) { 202 // The address has changed for this interface. We need to flush 203 // everything and start over. 204 LOG(INFO) << __func__ << ": Flushing old addresses and routes."; 205 routing_table_->FlushRoutes(interface_index_); 206 device_info_->FlushAddresses(interface_index_); 207 } 208 209 LOG(INFO) << __func__ << ": Installing with parameters:" 210 << " local=" << local.ToString() 211 << " broadcast=" << broadcast.ToString() 212 << " peer=" << peer.ToString() 213 << " gateway=" << gateway.ToString(); 214 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer); 215 216 if (gateway.IsValid() && properties.default_route) { 217 routing_table_->SetDefaultRoute(interface_index_, gateway, 218 GetMetric(is_default_), 219 table_id_); 220 } 221 222 if (user_traffic_only_) { 223 SetupIptableEntries(); 224 } 225 226 // Install any explicitly configured routes at the default metric. 227 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric, 228 table_id_); 229 230 SetMTU(properties.mtu); 231 232 if (properties.blackhole_ipv6) { 233 routing_table_->CreateBlackholeRoute(interface_index_, 234 IPAddress::kFamilyIPv6, 235 kDefaultMetric, 236 table_id_); 237 } 238 239 // Save a copy of the last non-null DNS config. 240 if (!config->properties().dns_servers.empty()) { 241 dns_servers_ = config->properties().dns_servers; 242 } 243 244 if (!config->properties().domain_search.empty()) { 245 dns_domain_search_ = config->properties().domain_search; 246 } 247 248 if (!config->properties().domain_name.empty()) { 249 dns_domain_name_ = config->properties().domain_name; 250 } 251 252 ipconfig_rpc_identifier_ = config->GetRpcIdentifier(); 253 254 PushDNSConfig(); 255 256 local_ = local; 257 gateway_ = gateway; 258 has_broadcast_domain_ = !peer.IsValid(); 259} 260 261bool Connection::SetupIptableEntries() { 262 if (!permission_broker_) { 263 permission_broker_.reset(control_interface_->CreatePermissionBrokerProxy()); 264 } 265 266 std::vector<std::string> user_names; 267 user_names.push_back("chronos"); 268 269 if (!permission_broker_->RequestVpnSetup(user_names, interface_name_)) { 270 LOG(ERROR) << "VPN iptables setup request failed."; 271 return false; 272 } 273 274 return true; 275} 276 277bool Connection::TearDownIptableEntries() { 278 return permission_broker_ ? permission_broker_->RemoveVpnSetup() : true; 279} 280 281void Connection::SetIsDefault(bool is_default) { 282 SLOG(this, 2) << __func__ << " " << interface_name_ 283 << " (index " << interface_index_ << ") " 284 << is_default_ << " -> " << is_default; 285 if (is_default == is_default_) { 286 return; 287 } 288 289 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default)); 290 291 is_default_ = is_default; 292 293 PushDNSConfig(); 294 if (is_default) { 295 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 296 if (device) { 297 device->RequestPortalDetection(); 298 } 299 } 300 routing_table_->FlushCache(); 301} 302 303void Connection::UpdateDNSServers(const vector<string>& dns_servers) { 304 dns_servers_ = dns_servers; 305 PushDNSConfig(); 306} 307 308void Connection::PushDNSConfig() { 309 if (!is_default_) { 310 return; 311 } 312 313 vector<string> domain_search = dns_domain_search_; 314 if (domain_search.empty() && !dns_domain_name_.empty()) { 315 SLOG(this, 2) << "Setting domain search to domain name " 316 << dns_domain_name_; 317 domain_search.push_back(dns_domain_name_ + "."); 318 } 319 resolver_->SetDNSFromLists(dns_servers_, domain_search); 320} 321 322void Connection::RequestRouting() { 323 if (routing_request_count_++ == 0) { 324 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 325 DCHECK(device.get()); 326 if (!device.get()) { 327 LOG(ERROR) << "Device is NULL!"; 328 return; 329 } 330 device->SetLooseRouting(true); 331 } 332} 333 334void Connection::ReleaseRouting() { 335 DCHECK_GT(routing_request_count_, 0); 336 if (--routing_request_count_ == 0) { 337 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 338 DCHECK(device.get()); 339 if (!device.get()) { 340 LOG(ERROR) << "Device is NULL!"; 341 return; 342 } 343 device->SetLooseRouting(false); 344 345 // Clear any cached routes that might have accumulated while reverse-path 346 // filtering was disabled. 347 routing_table_->FlushCache(); 348 } 349} 350 351bool Connection::RequestHostRoute(const IPAddress& address) { 352 // Do not set interface_index_ since this may not be the default route through 353 // which this destination can be found. However, we should tag the created 354 // route with our interface index so we can clean this route up when this 355 // connection closes. Also, add route query callback to determine the lower 356 // connection and bind to it. 357 if (!routing_table_->RequestRouteToHost( 358 address, 359 -1, 360 interface_index_, 361 Bind(&Connection::OnRouteQueryResponse, 362 weak_ptr_factory_.GetWeakPtr()), 363 table_id_)) { 364 LOG(ERROR) << "Could not request route to " << address.ToString(); 365 return false; 366 } 367 368 return true; 369} 370 371bool Connection::PinPendingRoutes(int interface_index, 372 RoutingTableEntry entry) { 373 // The variable entry is locally modified, hence is passed by value in the 374 // second argument above. 375 for (auto excluded_ip = excluded_ips_cidr_.begin(); 376 excluded_ip != excluded_ips_cidr_.end(); ++excluded_ip) { 377 if (!entry.dst.SetAddressAndPrefixFromString(*excluded_ip) || 378 !entry.dst.IsValid() || 379 !routing_table_->AddRoute(interface_index, entry)) { 380 LOG(ERROR) << "Unable to setup route for " << *excluded_ip << "."; 381 } 382 } 383 384 return true; 385} 386 387string Connection::GetSubnetName() const { 388 if (!local().IsValid()) { 389 return ""; 390 } 391 return base::StringPrintf("%s/%d", 392 local().GetNetworkPart().ToString().c_str(), 393 local().prefix()); 394} 395 396bool Connection::FixGatewayReachability(const 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 IPAddress gateway_with_max_prefix(*gateway); 483 gateway_with_max_prefix.set_prefix( 484 IPAddress::GetMaxPrefixLength(gateway_with_max_prefix.family())); 485 IPAddress default_address(gateway->family()); 486 RoutingTableEntry entry(gateway_with_max_prefix, 487 default_address, 488 default_address, 489 0, 490 RT_SCOPE_LINK, 491 false, 492 table_id_, 493 RoutingTableEntry::kDefaultTag); 494 495 if (!routing_table_->AddRoute(interface_index_, entry)) { 496 LOG(ERROR) << "Unable to add link-scoped route to gateway."; 497 return false; 498 } 499 500 LOG(WARNING) << "Mitigating this by creating a link route to the gateway."; 501 502 return true; 503} 504 505uint32_t Connection::GetMetric(bool is_default) { 506 // If this is not the default route, assign a metric based on the interface 507 // index. This way all non-default routes (even to the same gateway IP) end 508 // up with unique metrics so they do not collide. 509 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_; 510} 511 512bool Connection::PinHostRoute(const IPAddress& trusted_ip, 513 const IPAddress& gateway) { 514 SLOG(this, 2) << __func__; 515 if (!trusted_ip.IsValid()) { 516 LOG(ERROR) << "No trusted IP -- unable to pin host route."; 517 return false; 518 } 519 520 if (!gateway.IsValid()) { 521 // Although we cannot pin a host route, we are also not going to create 522 // a gateway route that will interfere with our primary connection, so 523 // it is okay to return success here. 524 LOG(WARNING) << "No gateway -- unable to pin host route."; 525 return true; 526 } 527 528 return RequestHostRoute(trusted_ip); 529} 530 531void Connection::SetMTU(int32_t mtu) { 532 SLOG(this, 2) << __func__ << " " << mtu; 533 // Make sure the MTU value is valid. 534 if (mtu == IPConfig::kUndefinedMTU) { 535 mtu = IPConfig::kDefaultMTU; 536 } else { 537 int min_mtu = IsIPv6() ? IPConfig::kMinIPv6MTU : IPConfig::kMinIPv4MTU; 538 if (mtu < min_mtu) { 539 SLOG(this, 2) << __func__ << " MTU " << mtu 540 << " is too small; adjusting up to " << min_mtu; 541 mtu = min_mtu; 542 } 543 } 544 545 rtnl_handler_->SetInterfaceMTU(interface_index_, mtu); 546} 547 548void Connection::OnRouteQueryResponse(int interface_index, 549 const RoutingTableEntry& entry) { 550 SLOG(this, 2) << __func__ << "(" << interface_index << ", " 551 << entry.tag << ")" << " @ " << interface_name_; 552 lower_binder_.Attach(nullptr); 553 DeviceRefPtr device = device_info_->GetDevice(interface_index); 554 if (!device) { 555 LOG(ERROR) << "Unable to lookup device for index " << interface_index; 556 return; 557 } 558 ConnectionRefPtr connection = device->connection(); 559 if (!connection) { 560 LOG(ERROR) << "Device " << interface_index << " has no connection."; 561 return; 562 } 563 lower_binder_.Attach(connection); 564 connection->CreateGatewayRoute(); 565 device->OnConnectionUpdated(); 566 PinPendingRoutes(interface_index, entry); 567} 568 569bool Connection::CreateGatewayRoute() { 570 // Ensure that the gateway for the lower connection remains reachable, 571 // since we may create routes that conflict with it. 572 if (!has_broadcast_domain_) { 573 return false; 574 } 575 576 // If there is no gateway, don't try to create a route to it. 577 if (!gateway_.IsValid()) { 578 return false; 579 } 580 581 // It is not worth keeping track of this route, since it is benign, 582 // and only pins persistent state that was already true of the connection. 583 // If DHCP parameters change later (without the connection having been 584 // destroyed and recreated), the binding processes will likely terminate 585 // and restart, causing a new link route to be created. 586 return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_, 587 table_id_); 588} 589 590void Connection::OnLowerDisconnect() { 591 SLOG(this, 2) << __func__ << " @ " << interface_name_; 592 // Ensures that |this| instance doesn't get destroyed in the middle of 593 // notifying the binders. This method needs to be separate from 594 // NotifyBindersOnDisconnect because the latter may be invoked by Connection's 595 // destructor when |this| instance's reference count is already 0. 596 ConnectionRefPtr connection(this); 597 connection->NotifyBindersOnDisconnect(); 598} 599 600void Connection::NotifyBindersOnDisconnect() { 601 // Note that this method may be invoked by the destructor. 602 SLOG(this, 2) << __func__ << " @ " << interface_name_; 603 604 // Unbinds the lower connection before notifying the binders. This ensures 605 // correct behavior in case of circular binding. 606 lower_binder_.Attach(nullptr); 607 while (!binders_.empty()) { 608 // Pop the binder first and then notify it to ensure that each binder is 609 // notified only once. 610 Binder* binder = binders_.front(); 611 binders_.pop_front(); 612 binder->OnDisconnect(); 613 } 614} 615 616void Connection::AttachBinder(Binder* binder) { 617 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ " 618 << interface_name_; 619 binders_.push_back(binder); 620} 621 622void Connection::DetachBinder(Binder* binder) { 623 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ " 624 << interface_name_; 625 for (auto it = binders_.begin(); it != binders_.end(); ++it) { 626 if (binder == *it) { 627 binders_.erase(it); 628 return; 629 } 630 } 631} 632 633ConnectionRefPtr Connection::GetCarrierConnection() { 634 SLOG(this, 2) << __func__ << " @ " << interface_name_; 635 set<Connection*> visited; 636 ConnectionRefPtr carrier = this; 637 while (carrier->GetLowerConnection()) { 638 if (ContainsKey(visited, carrier.get())) { 639 LOG(ERROR) << "Circular connection chain starting at: " 640 << carrier->interface_name(); 641 // If a loop is detected return a NULL value to signal that the carrier 642 // connection is unknown. 643 return nullptr; 644 } 645 visited.insert(carrier.get()); 646 carrier = carrier->GetLowerConnection(); 647 } 648 SLOG(this, 2) << "Carrier connection: " << carrier->interface_name() 649 << " @ " << interface_name_; 650 return carrier; 651} 652 653bool Connection::IsIPv6() { 654 return local_.family() == IPAddress::kFamilyIPv6; 655} 656 657} // namespace shill 658