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