connection.cc revision c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5
1// 2// Copyright (C) 2012 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "shill/connection.h" 18 19#include <arpa/inet.h> 20#include <linux/rtnetlink.h> 21 22#include <set> 23 24#include <base/strings/stringprintf.h> 25 26#include "shill/control_interface.h" 27#include "shill/device_info.h" 28#include "shill/logging.h" 29#include "shill/net/rtnl_handler.h" 30#include "shill/permission_broker_proxy.h" 31#include "shill/resolver.h" 32#include "shill/routing_table.h" 33 34using base::Bind; 35using base::Closure; 36using base::Unretained; 37using std::deque; 38using std::set; 39using std::string; 40using std::vector; 41 42namespace shill { 43 44namespace Logging { 45static auto kModuleLogScope = ScopeLogger::kConnection; 46static string ObjectID(Connection* c) { 47 if (c == nullptr) 48 return "(connection)"; 49 return c->interface_name(); 50} 51} 52 53// static 54const uint32_t Connection::kDefaultMetric = 1; 55// static 56const uint32_t Connection::kNonDefaultMetricBase = 10; 57// static 58const uint32_t Connection::kMarkForUserTraffic = 0x1; 59// static 60const uint8_t Connection::kSecondaryTableId = 0x1; 61 62Connection::Binder::Binder(const string& name, 63 const Closure& disconnect_callback) 64 : name_(name), 65 client_disconnect_callback_(disconnect_callback) {} 66 67Connection::Binder::~Binder() { 68 Attach(nullptr); 69} 70 71void Connection::Binder::Attach(const ConnectionRefPtr& to_connection) { 72 if (connection_) { 73 connection_->DetachBinder(this); 74 LOG(INFO) << name_ << ": unbound from connection: " 75 << connection_->interface_name(); 76 connection_.reset(); 77 } 78 if (to_connection) { 79 connection_ = to_connection->weak_ptr_factory_.GetWeakPtr(); 80 connection_->AttachBinder(this); 81 LOG(INFO) << name_ << ": bound to connection: " 82 << connection_->interface_name(); 83 } 84} 85 86void Connection::Binder::OnDisconnect() { 87 LOG(INFO) << name_ << ": bound connection disconnected: " 88 << connection_->interface_name(); 89 connection_.reset(); 90 if (!client_disconnect_callback_.is_null()) { 91 SLOG(connection_.get(), 2) << "Running client disconnect callback."; 92 client_disconnect_callback_.Run(); 93 } 94} 95 96Connection::Connection(int interface_index, 97 const std::string& interface_name, 98 Technology::Identifier technology, 99 const DeviceInfo* device_info, 100 ControlInterface* control_interface) 101 : weak_ptr_factory_(this), 102 is_default_(false), 103 has_broadcast_domain_(false), 104 routing_request_count_(0), 105 interface_index_(interface_index), 106 interface_name_(interface_name), 107 technology_(technology), 108 user_traffic_only_(false), 109 table_id_(RT_TABLE_MAIN), 110 local_(IPAddress::kFamilyUnknown), 111 gateway_(IPAddress::kFamilyUnknown), 112 lower_binder_( 113 interface_name_, 114 // Connection owns a single instance of |lower_binder_| so it's safe 115 // to use an Unretained callback. 116 Bind(&Connection::OnLowerDisconnect, Unretained(this))), 117 device_info_(device_info), 118 resolver_(Resolver::GetInstance()), 119 routing_table_(RoutingTable::GetInstance()), 120 rtnl_handler_(RTNLHandler::GetInstance()), 121 control_interface_(control_interface) { 122 SLOG(this, 2) << __func__ << "(" << interface_index << ", " 123 << interface_name << ", " 124 << Technology::NameFromIdentifier(technology) << ")"; 125} 126 127Connection::~Connection() { 128 SLOG(this, 2) << __func__ << " " << interface_name_; 129 130 NotifyBindersOnDisconnect(); 131 132 DCHECK(!routing_request_count_); 133 routing_table_->FlushRoutes(interface_index_); 134 routing_table_->FlushRoutesWithTag(interface_index_); 135 device_info_->FlushAddresses(interface_index_); 136 TearDownIptableEntries(); 137} 138 139void Connection::UpdateFromIPConfig(const IPConfigRefPtr& config) { 140 SLOG(this, 2) << __func__ << " " << interface_name_; 141 142 const IPConfig::Properties& properties = config->properties(); 143 user_traffic_only_ = properties.user_traffic_only; 144 table_id_ = user_traffic_only_ ? kSecondaryTableId : (uint8_t)RT_TABLE_MAIN; 145 146 IPAddress gateway(properties.address_family); 147 if (!properties.gateway.empty() && 148 !gateway.SetAddressFromString(properties.gateway)) { 149 LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid"; 150 return; 151 } 152 153 excluded_ips_cidr_ = properties.exclusion_list; 154 155 IPAddress trusted_ip(properties.address_family); 156 if (!excluded_ips_cidr_.empty()) { 157 const std::string first_excluded_ip = excluded_ips_cidr_[0]; 158 excluded_ips_cidr_.erase(excluded_ips_cidr_.begin()); 159 // A VPN connection can currently be bound to exactly one lower connection 160 // such as eth0 or wan0. The excluded IPs are pinned to the gateway of 161 // that connection. Setting up the routing table this way ensures that when 162 // the lower connection goes offline, the associated entries in the routing 163 // table are removed. On the flip side, when there are multiple connections 164 // such as eth0 and wan0 and some IPs can be reached quickly over one 165 // connection and the others over a different connection, all routes are 166 // still pinned to a connection. 167 // 168 // The optimal connection to reach the first excluded IP is found below. 169 // When this is found the route for the remaining excluded IPs are pinned in 170 // the method PinPendingRoutes below. 171 if (!trusted_ip.SetAddressAndPrefixFromString(first_excluded_ip)) { 172 LOG(ERROR) << "Trusted IP address " 173 << first_excluded_ip << " is invalid"; 174 return; 175 } 176 if (!PinHostRoute(trusted_ip, gateway)) { 177 LOG(ERROR) << "Unable to pin host route to " << first_excluded_ip; 178 return; 179 } 180 } 181 182 IPAddress local(properties.address_family); 183 if (!local.SetAddressFromString(properties.address)) { 184 LOG(ERROR) << "Local address " << properties.address << " is invalid"; 185 return; 186 } 187 local.set_prefix(properties.subnet_prefix); 188 189 IPAddress broadcast(properties.address_family); 190 if (properties.broadcast_address.empty()) { 191 if (properties.peer_address.empty()) { 192 LOG(WARNING) << "Broadcast address is not set. Using default."; 193 broadcast = local.GetDefaultBroadcast(); 194 } 195 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) { 196 LOG(ERROR) << "Broadcast address " << properties.broadcast_address 197 << " is invalid"; 198 return; 199 } 200 201 IPAddress peer(properties.address_family); 202 if (!properties.peer_address.empty() && 203 !peer.SetAddressFromString(properties.peer_address)) { 204 LOG(ERROR) << "Peer address " << properties.peer_address 205 << " is invalid"; 206 return; 207 } 208 209 if (!FixGatewayReachability(local, &peer, &gateway, trusted_ip)) { 210 LOG(WARNING) << "Expect limited network connectivity."; 211 } 212 213 if (device_info_->HasOtherAddress(interface_index_, local)) { 214 // The address has changed for this interface. We need to flush 215 // everything and start over. 216 LOG(INFO) << __func__ << ": Flushing old addresses and routes."; 217 routing_table_->FlushRoutes(interface_index_); 218 device_info_->FlushAddresses(interface_index_); 219 } 220 221 LOG(INFO) << __func__ << ": Installing with parameters:" 222 << " local=" << local.ToString() 223 << " broadcast=" << broadcast.ToString() 224 << " peer=" << peer.ToString() 225 << " gateway=" << gateway.ToString(); 226 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer); 227 228 if (gateway.IsValid() && properties.default_route) { 229 routing_table_->SetDefaultRoute(interface_index_, gateway, 230 GetMetric(is_default_), 231 table_id_); 232 } 233 234 if (user_traffic_only_) { 235 SetupIptableEntries(); 236 } 237 238 // Install any explicitly configured routes at the default metric. 239 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric, 240 table_id_); 241 242 SetMTU(properties.mtu); 243 244 if (properties.blackhole_ipv6) { 245 routing_table_->CreateBlackholeRoute(interface_index_, 246 IPAddress::kFamilyIPv6, 247 kDefaultMetric, 248 table_id_); 249 } 250 251 // Save a copy of the last non-null DNS config. 252 if (!config->properties().dns_servers.empty()) { 253 dns_servers_ = config->properties().dns_servers; 254 } 255 256 if (!config->properties().domain_search.empty()) { 257 dns_domain_search_ = config->properties().domain_search; 258 } 259 260 if (!config->properties().domain_name.empty()) { 261 dns_domain_name_ = config->properties().domain_name; 262 } 263 264 ipconfig_rpc_identifier_ = config->GetRpcIdentifier(); 265 266 PushDNSConfig(); 267 268 local_ = local; 269 gateway_ = gateway; 270 has_broadcast_domain_ = !peer.IsValid(); 271} 272 273bool Connection::SetupIptableEntries() { 274 if (!permission_broker_) { 275 permission_broker_.reset(control_interface_->CreatePermissionBrokerProxy()); 276 } 277 278 std::vector<std::string> user_names; 279 user_names.push_back("chronos"); 280 281 if (!permission_broker_->RequestVpnSetup(user_names, interface_name_)) { 282 LOG(ERROR) << "VPN iptables setup request failed."; 283 return false; 284 } 285 286 return true; 287} 288 289bool Connection::TearDownIptableEntries() { 290 return permission_broker_ ? permission_broker_->RemoveVpnSetup() : true; 291} 292 293void Connection::SetIsDefault(bool is_default) { 294 SLOG(this, 2) << __func__ << " " << interface_name_ 295 << " (index " << interface_index_ << ") " 296 << is_default_ << " -> " << is_default; 297 if (is_default == is_default_) { 298 return; 299 } 300 301 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default)); 302 303 is_default_ = is_default; 304 305 PushDNSConfig(); 306 if (is_default) { 307 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 308 if (device) { 309 device->RequestPortalDetection(); 310 } 311 } 312 routing_table_->FlushCache(); 313} 314 315void Connection::UpdateDNSServers(const vector<string>& dns_servers) { 316 dns_servers_ = dns_servers; 317 PushDNSConfig(); 318} 319 320void Connection::PushDNSConfig() { 321 if (!is_default_) { 322 return; 323 } 324 325 vector<string> domain_search = dns_domain_search_; 326 if (domain_search.empty() && !dns_domain_name_.empty()) { 327 SLOG(this, 2) << "Setting domain search to domain name " 328 << dns_domain_name_; 329 domain_search.push_back(dns_domain_name_ + "."); 330 } 331 resolver_->SetDNSFromLists(dns_servers_, domain_search); 332} 333 334void Connection::RequestRouting() { 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(true); 343 } 344} 345 346void Connection::ReleaseRouting() { 347 DCHECK_GT(routing_request_count_, 0); 348 if (--routing_request_count_ == 0) { 349 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 350 DCHECK(device.get()); 351 if (!device.get()) { 352 LOG(ERROR) << "Device is NULL!"; 353 return; 354 } 355 device->SetLooseRouting(false); 356 357 // Clear any cached routes that might have accumulated while reverse-path 358 // filtering was disabled. 359 routing_table_->FlushCache(); 360 } 361} 362 363bool Connection::RequestHostRoute(const IPAddress& address) { 364 // Do not set interface_index_ since this may not be the default route through 365 // which this destination can be found. However, we should tag the created 366 // route with our interface index so we can clean this route up when this 367 // connection closes. Also, add route query callback to determine the lower 368 // connection and bind to it. 369 if (!routing_table_->RequestRouteToHost( 370 address, 371 -1, 372 interface_index_, 373 Bind(&Connection::OnRouteQueryResponse, 374 weak_ptr_factory_.GetWeakPtr()), 375 table_id_)) { 376 LOG(ERROR) << "Could not request route to " << address.ToString(); 377 return false; 378 } 379 380 return true; 381} 382 383bool Connection::PinPendingRoutes(int interface_index, 384 RoutingTableEntry entry) { 385 // The variable entry is locally modified, hence is passed by value in the 386 // second argument above. 387 for (auto excluded_ip = excluded_ips_cidr_.begin(); 388 excluded_ip != excluded_ips_cidr_.end(); ++excluded_ip) { 389 if (!entry.dst.SetAddressAndPrefixFromString(*excluded_ip) || 390 !entry.dst.IsValid() || 391 !routing_table_->AddRoute(interface_index, entry)) { 392 LOG(ERROR) << "Unable to setup route for " << *excluded_ip << "."; 393 } 394 } 395 396 return true; 397} 398 399string Connection::GetSubnetName() const { 400 if (!local().IsValid()) { 401 return ""; 402 } 403 return base::StringPrintf("%s/%d", 404 local().GetNetworkPart().ToString().c_str(), 405 local().prefix()); 406} 407 408bool Connection::FixGatewayReachability(const IPAddress& local, 409 IPAddress* peer, 410 IPAddress* gateway, 411 const IPAddress& trusted_ip) { 412 SLOG(nullptr, 2) << __func__ 413 << " local " << local.ToString() 414 << ", peer " << peer->ToString() 415 << ", gateway " << gateway->ToString() 416 << ", trusted_ip " << trusted_ip.ToString(); 417 if (!gateway->IsValid()) { 418 LOG(WARNING) << "No gateway address was provided for this connection."; 419 return false; 420 } 421 422 if (peer->IsValid()) { 423 if (!gateway->HasSameAddressAs(*peer)) { 424 LOG(WARNING) << "Gateway address " 425 << gateway->ToString() 426 << " does not match peer address " 427 << peer->ToString(); 428 return false; 429 } 430 if (gateway->HasSameAddressAs(trusted_ip)) { 431 // In order to send outgoing traffic in a point-to-point network, 432 // the gateway IP address isn't of significance. As opposed to 433 // broadcast networks, we never ARP for the gateway IP address, 434 // but just send the IP packet addressed to the recipient. As 435 // such, since using the external trusted IP address as the 436 // gateway or peer wreaks havoc on the routing rules, we choose 437 // not to supply a gateway address. Here's an example: 438 // 439 // Client <-> Internet <-> VPN Gateway <-> Internal Network 440 // 192.168.1.2 10.0.1.25 172.16.5.0/24 441 // 442 // In this example, a client connects to a VPN gateway on its 443 // public IP address 10.0.1.25. It gets issued an IP address 444 // from the VPN internal pool. For some VPN gateways, this 445 // results in a pushed-down PPP configuration which specifies: 446 // 447 // Client local address: 172.16.5.13 448 // Client peer address: 10.0.1.25 449 // Client default gateway: 10.0.1.25 450 // 451 // If we take this literally, we need to resolve the fact that 452 // 10.0.1.25 is now listed as the default gateway and interface 453 // peer address for the point-to-point interface. However, in 454 // order to route tunneled packets to the VPN gateway we must 455 // use the external route through the physical interface and 456 // not the tunnel, or else we end up in an infinite loop 457 // re-entering the tunnel trying to route towards the VPN server. 458 // 459 // We can do this by pinning a route, but we would need to wait 460 // for the pinning process to complete before assigning this 461 // address. Currently this process is asynchronous and will 462 // complete only after returning to the event loop. Additionally, 463 // since there's no metric associated with assigning an address 464 // to an interface, it's always possible that having the peer 465 // address of the interface might still trump a host route. 466 // 467 // To solve this problem, we reset the peer and gateway 468 // addresses. Neither is required in order to perform the 469 // underlying routing task. A gateway route can be specified 470 // without an IP endpoint on point-to-point links, and simply 471 // specify the outbound interface index. Similarly, a peer 472 // IP address is not necessary either, and will be assigned 473 // the same IP address as the local IP. This approach 474 // simplifies routing and doesn't change the desired 475 // functional behavior. 476 // 477 LOG(INFO) << "Removing gateway and peer addresses to preserve " 478 << "routability to trusted IP address."; 479 peer->SetAddressToDefault(); 480 gateway->SetAddressToDefault(); 481 } 482 return true; 483 } 484 485 if (local.CanReachAddress(*gateway)) { 486 return true; 487 } 488 489 LOG(WARNING) << "Gateway " 490 << gateway->ToString() 491 << " is unreachable from local address/prefix " 492 << local.ToString() << "/" << local.prefix(); 493 494 IPAddress gateway_with_max_prefix(*gateway); 495 gateway_with_max_prefix.set_prefix( 496 IPAddress::GetMaxPrefixLength(gateway_with_max_prefix.family())); 497 IPAddress default_address(gateway->family()); 498 RoutingTableEntry entry(gateway_with_max_prefix, 499 default_address, 500 default_address, 501 0, 502 RT_SCOPE_LINK, 503 false, 504 table_id_, 505 RoutingTableEntry::kDefaultTag); 506 507 if (!routing_table_->AddRoute(interface_index_, entry)) { 508 LOG(ERROR) << "Unable to add link-scoped route to gateway."; 509 return false; 510 } 511 512 LOG(WARNING) << "Mitigating this by creating a link route to the gateway."; 513 514 return true; 515} 516 517uint32_t Connection::GetMetric(bool is_default) { 518 // If this is not the default route, assign a metric based on the interface 519 // index. This way all non-default routes (even to the same gateway IP) end 520 // up with unique metrics so they do not collide. 521 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_; 522} 523 524bool Connection::PinHostRoute(const IPAddress& trusted_ip, 525 const IPAddress& gateway) { 526 SLOG(this, 2) << __func__; 527 if (!trusted_ip.IsValid()) { 528 LOG(ERROR) << "No trusted IP -- unable to pin host route."; 529 return false; 530 } 531 532 if (!gateway.IsValid()) { 533 // Although we cannot pin a host route, we are also not going to create 534 // a gateway route that will interfere with our primary connection, so 535 // it is okay to return success here. 536 LOG(WARNING) << "No gateway -- unable to pin host route."; 537 return true; 538 } 539 540 return RequestHostRoute(trusted_ip); 541} 542 543void Connection::SetMTU(int32_t mtu) { 544 SLOG(this, 2) << __func__ << " " << mtu; 545 // Make sure the MTU value is valid. 546 if (mtu == IPConfig::kUndefinedMTU) { 547 mtu = IPConfig::kDefaultMTU; 548 } else { 549 int min_mtu = IsIPv6() ? IPConfig::kMinIPv6MTU : IPConfig::kMinIPv4MTU; 550 if (mtu < min_mtu) { 551 SLOG(this, 2) << __func__ << " MTU " << mtu 552 << " is too small; adjusting up to " << min_mtu; 553 mtu = min_mtu; 554 } 555 } 556 557 rtnl_handler_->SetInterfaceMTU(interface_index_, mtu); 558} 559 560void Connection::OnRouteQueryResponse(int interface_index, 561 const RoutingTableEntry& entry) { 562 SLOG(this, 2) << __func__ << "(" << interface_index << ", " 563 << entry.tag << ")" << " @ " << interface_name_; 564 lower_binder_.Attach(nullptr); 565 DeviceRefPtr device = device_info_->GetDevice(interface_index); 566 if (!device) { 567 LOG(ERROR) << "Unable to lookup device for index " << interface_index; 568 return; 569 } 570 ConnectionRefPtr connection = device->connection(); 571 if (!connection) { 572 LOG(ERROR) << "Device " << interface_index << " has no connection."; 573 return; 574 } 575 if (connection == this) { 576 LOG(ERROR) << "Avoiding a connection bind loop for " << interface_name(); 577 return; 578 } 579 lower_binder_.Attach(connection); 580 connection->CreateGatewayRoute(); 581 device->OnConnectionUpdated(); 582 PinPendingRoutes(interface_index, entry); 583} 584 585bool Connection::CreateGatewayRoute() { 586 // Ensure that the gateway for the lower connection remains reachable, 587 // since we may create routes that conflict with it. 588 if (!has_broadcast_domain_) { 589 return false; 590 } 591 592 // If there is no gateway, don't try to create a route to it. 593 if (!gateway_.IsValid()) { 594 return false; 595 } 596 597 // It is not worth keeping track of this route, since it is benign, 598 // and only pins persistent state that was already true of the connection. 599 // If DHCP parameters change later (without the connection having been 600 // destroyed and recreated), the binding processes will likely terminate 601 // and restart, causing a new link route to be created. 602 return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_, 603 table_id_); 604} 605 606void Connection::OnLowerDisconnect() { 607 SLOG(this, 2) << __func__ << " @ " << interface_name_; 608 // Ensures that |this| instance doesn't get destroyed in the middle of 609 // notifying the binders. This method needs to be separate from 610 // NotifyBindersOnDisconnect because the latter may be invoked by Connection's 611 // destructor when |this| instance's reference count is already 0. 612 ConnectionRefPtr connection(this); 613 connection->NotifyBindersOnDisconnect(); 614} 615 616void Connection::NotifyBindersOnDisconnect() { 617 // Note that this method may be invoked by the destructor. 618 SLOG(this, 2) << __func__ << " @ " << interface_name_; 619 620 // Unbinds the lower connection before notifying the binders. This ensures 621 // correct behavior in case of circular binding. 622 lower_binder_.Attach(nullptr); 623 while (!binders_.empty()) { 624 // Pop the binder first and then notify it to ensure that each binder is 625 // notified only once. 626 Binder* binder = binders_.front(); 627 binders_.pop_front(); 628 binder->OnDisconnect(); 629 } 630} 631 632void Connection::AttachBinder(Binder* binder) { 633 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ " 634 << interface_name_; 635 binders_.push_back(binder); 636} 637 638void Connection::DetachBinder(Binder* binder) { 639 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ " 640 << interface_name_; 641 for (auto it = binders_.begin(); it != binders_.end(); ++it) { 642 if (binder == *it) { 643 binders_.erase(it); 644 return; 645 } 646 } 647} 648 649ConnectionRefPtr Connection::GetCarrierConnection() { 650 SLOG(this, 2) << __func__ << " @ " << interface_name_; 651 set<Connection*> visited; 652 ConnectionRefPtr carrier = this; 653 while (carrier->GetLowerConnection()) { 654 if (ContainsKey(visited, carrier.get())) { 655 LOG(ERROR) << "Circular connection chain starting at: " 656 << carrier->interface_name(); 657 // If a loop is detected return a NULL value to signal that the carrier 658 // connection is unknown. 659 return nullptr; 660 } 661 visited.insert(carrier.get()); 662 carrier = carrier->GetLowerConnection(); 663 } 664 SLOG(this, 2) << "Carrier connection: " << carrier->interface_name() 665 << " @ " << interface_name_; 666 return carrier; 667} 668 669bool Connection::IsIPv6() { 670 return local_.family() == IPAddress::kFamilyIPv6; 671} 672 673} // namespace shill 674