connection.cc revision fad4a0b7e55dd82d3815ee96862b6e546727eb6e
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 "shill/device_info.h" 11#include "shill/resolver.h" 12#include "shill/routing_table.h" 13#include "shill/rtnl_handler.h" 14#include "shill/scope_logger.h" 15 16using std::string; 17 18namespace shill { 19 20// static 21const uint32 Connection::kDefaultMetric = 1; 22// static 23const uint32 Connection::kNonDefaultMetricBase = 10; 24 25Connection::Connection(int interface_index, 26 const std::string& interface_name, 27 Technology::Identifier technology, 28 const DeviceInfo *device_info) 29 : is_default_(false), 30 routing_request_count_(0), 31 interface_index_(interface_index), 32 interface_name_(interface_name), 33 technology_(technology), 34 device_info_(device_info), 35 resolver_(Resolver::GetInstance()), 36 routing_table_(RoutingTable::GetInstance()), 37 rtnl_handler_(RTNLHandler::GetInstance()) { 38 SLOG(Connection, 2) << __func__ << "(" << interface_index << ", " 39 << interface_name << ", " 40 << Technology::NameFromIdentifier(technology) << ")"; 41} 42 43Connection::~Connection() { 44 SLOG(Connection, 2) << __func__ << " " << interface_name_; 45 46 DCHECK(!routing_request_count_); 47 routing_table_->FlushRoutes(interface_index_); 48 device_info_->FlushAddresses(interface_index_); 49} 50 51void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) { 52 SLOG(Connection, 2) << __func__ << " " << interface_name_; 53 54 const IPConfig::Properties &properties = config->properties(); 55 IPAddress local(properties.address_family); 56 if (!local.SetAddressFromString(properties.address)) { 57 LOG(ERROR) << "Local address " << properties.address << " is invalid"; 58 return; 59 } 60 local.set_prefix(properties.subnet_prefix); 61 62 IPAddress broadcast(properties.address_family); 63 if (!broadcast.SetAddressFromString(properties.broadcast_address) && 64 technology_ != Technology::kVPN) { 65 LOG(ERROR) << "Broadcast address " << properties.broadcast_address 66 << " is invalid"; 67 return; 68 } 69 70 IPAddress peer(properties.address_family); 71 if (!properties.peer_address.empty() && 72 !peer.SetAddressFromString(properties.peer_address)) { 73 LOG(ERROR) << "Peer address " << properties.peer_address 74 << " is invalid"; 75 return; 76 } 77 78 IPAddress gateway_address(properties.address_family); 79 if (!properties.gateway.empty() && 80 !gateway_address.SetAddressFromString(properties.gateway)) { 81 LOG(ERROR) << "Gateway address " << properties.peer_address 82 << " is invalid"; 83 return; 84 } 85 86 FixGatewayReachability(&local, gateway_address); 87 88 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer); 89 90 if (gateway_address.IsValid()) { 91 routing_table_->SetDefaultRoute(interface_index_, gateway_address, 92 GetMetric(is_default_)); 93 } else if (!peer.IsValid()) { 94 LOG(WARNING) << "No gateway or peer address was provided for this " 95 << "connection. Expect limited network connectivity."; 96 } 97 98 // Install any explicitly configured routes at the default metric. 99 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric); 100 101 // Save a copy of the last non-null DNS config 102 if (!config->properties().dns_servers.empty()) { 103 dns_servers_ = config->properties().dns_servers; 104 dns_domain_search_ = config->properties().domain_search; 105 } 106 107 if (is_default_) { 108 resolver_->SetDNSFromIPConfig(config); 109 } 110} 111 112void Connection::SetIsDefault(bool is_default) { 113 SLOG(Connection, 2) << __func__ << " " << interface_name_ 114 << " (index " << interface_index_ << ") " 115 << is_default_ << " -> " << is_default; 116 if (is_default == is_default_) { 117 return; 118 } 119 120 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default)); 121 122 is_default_ = is_default; 123 124 if (is_default) { 125 resolver_->SetDNSFromLists(dns_servers_, dns_domain_search_); 126 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 127 if (device) { 128 device->RequestPortalDetection(); 129 } 130 } 131} 132 133void Connection::RequestRouting() { 134 if (routing_request_count_++ == 0) { 135 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 136 DCHECK(device.get()); 137 if (!device.get()) { 138 LOG(ERROR) << "Device is NULL!"; 139 return; 140 } 141 device->DisableReversePathFilter(); 142 } 143} 144 145void Connection::ReleaseRouting() { 146 DCHECK(routing_request_count_ > 0); 147 if (--routing_request_count_ == 0) { 148 DeviceRefPtr device = device_info_->GetDevice(interface_index_); 149 DCHECK(device.get()); 150 if (!device.get()) { 151 LOG(ERROR) << "Device is NULL!"; 152 return; 153 } 154 device->EnableReversePathFilter(); 155 156 // Clear any cached routes that might have accumulated while reverse-path 157 // filtering was disabled. 158 routing_table_->FlushCache(); 159 } 160} 161 162bool Connection::RequestHostRoute(const IPAddress &address) { 163 // Set the prefix to be the entire address size. 164 IPAddress address_prefix(address); 165 address_prefix.set_prefix(address_prefix.GetLength() * 8); 166 167 // Do not set interface_index_ since this may not be the 168 // default route through which this destination can be found. 169 if (!routing_table_->RequestRouteToHost(address_prefix, -1)) { 170 LOG(ERROR) << "Could not request route to " << address.ToString(); 171 return false; 172 } 173 174 return true; 175} 176 177// static 178void Connection::FixGatewayReachability(IPAddress *local, 179 const IPAddress &gateway) { 180 if (!gateway.IsValid() || local->CanReachAddress(gateway)) { 181 return; 182 } 183 184 LOG(WARNING) << "Gateway " 185 << gateway.ToString() 186 << " is unreachable from local address/prefix " 187 << local->ToString() << "/" << local->prefix(); 188 189 size_t original_prefix = local->prefix(); 190 size_t prefix = original_prefix - 1; 191 for (; prefix >= local->GetMinPrefixLength(); --prefix) { 192 local->set_prefix(prefix); 193 if (local->CanReachAddress(gateway)) { 194 break; 195 } 196 } 197 198 if (prefix < local->GetMinPrefixLength()) { 199 // Restore the original prefix since we cannot find a better one. 200 local->set_prefix(original_prefix); 201 LOG(WARNING) << "Expect limited network connectivity."; 202 } else { 203 LOG(WARNING) << "Mitigating this by setting local prefix to " << prefix; 204 } 205} 206 207uint32 Connection::GetMetric(bool is_default) { 208 // If this is not the default route, assign a metric based on the interface 209 // index. This way all non-default routes (even to the same gateway IP) end 210 // up with unique metrics so they do not collide. 211 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_; 212} 213 214} // namespace shill 215