routing_table.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/routing_table.h" 18 19#include <arpa/inet.h> 20#include <fcntl.h> 21#include <linux/netlink.h> 22#include <linux/rtnetlink.h> 23#include <netinet/ether.h> 24#include <net/if.h> // NOLINT - must be included after netinet/ether.h 25#include <net/if_arp.h> 26#include <string.h> 27#include <sys/socket.h> 28#include <time.h> 29#include <unistd.h> 30 31#include <memory> 32#include <string> 33 34#include <base/bind.h> 35#include <base/files/file_path.h> 36#include <base/files/file_util.h> 37#include <base/stl_util.h> 38#include <base/strings/stringprintf.h> 39 40#include "shill/ipconfig.h" 41#include "shill/logging.h" 42#include "shill/net/byte_string.h" 43#include "shill/net/rtnl_handler.h" 44#include "shill/net/rtnl_listener.h" 45#include "shill/net/rtnl_message.h" 46#include "shill/routing_table_entry.h" 47 48using base::Bind; 49using base::FilePath; 50using base::Unretained; 51using std::deque; 52using std::string; 53using std::vector; 54 55namespace shill { 56 57namespace Logging { 58static auto kModuleLogScope = ScopeLogger::kRoute; 59static string ObjectID(RoutingTable* r) { return "(routing_table)"; } 60} 61 62namespace { 63base::LazyInstance<RoutingTable> g_routing_table = LAZY_INSTANCE_INITIALIZER; 64} // namespace 65 66// static 67const char RoutingTable::kRouteFlushPath4[] = "/proc/sys/net/ipv4/route/flush"; 68// static 69const char RoutingTable::kRouteFlushPath6[] = "/proc/sys/net/ipv6/route/flush"; 70 71RoutingTable::RoutingTable() 72 : route_callback_(Bind(&RoutingTable::RouteMsgHandler, Unretained(this))), 73 rtnl_handler_(RTNLHandler::GetInstance()) { 74 SLOG(this, 2) << __func__; 75} 76 77RoutingTable::~RoutingTable() {} 78 79RoutingTable* RoutingTable::GetInstance() { 80 return g_routing_table.Pointer(); 81} 82 83void RoutingTable::Start() { 84 SLOG(this, 2) << __func__; 85 86 route_listener_.reset( 87 new RTNLListener(RTNLHandler::kRequestRoute, route_callback_)); 88 rtnl_handler_->RequestDump(RTNLHandler::kRequestRoute); 89} 90 91void RoutingTable::Stop() { 92 SLOG(this, 2) << __func__; 93 94 route_listener_.reset(); 95} 96 97bool RoutingTable::AddRoute(int interface_index, 98 const RoutingTableEntry& entry) { 99 SLOG(this, 2) << __func__ << ": " 100 << "destination " << entry.dst.ToString() 101 << " index " << interface_index 102 << " gateway " << entry.gateway.ToString() 103 << " metric " << entry.metric; 104 105 CHECK(!entry.from_rtnl); 106 if (!ApplyRoute(interface_index, 107 entry, 108 RTNLMessage::kModeAdd, 109 NLM_F_CREATE | NLM_F_EXCL)) { 110 return false; 111 } 112 tables_[interface_index].push_back(entry); 113 return true; 114} 115 116bool RoutingTable::GetDefaultRoute(int interface_index, 117 IPAddress::Family family, 118 RoutingTableEntry* entry) { 119 RoutingTableEntry* found_entry; 120 bool ret = GetDefaultRouteInternal(interface_index, family, &found_entry); 121 if (ret) { 122 *entry = *found_entry; 123 } 124 return ret; 125} 126 127bool RoutingTable::GetDefaultRouteInternal(int interface_index, 128 IPAddress::Family family, 129 RoutingTableEntry** entry) { 130 SLOG(this, 2) << __func__ << " index " << interface_index 131 << " family " << IPAddress::GetAddressFamilyName(family); 132 133 Tables::iterator table = tables_.find(interface_index); 134 if (table == tables_.end()) { 135 SLOG(this, 2) << __func__ << " no table"; 136 return false; 137 } 138 139 for (auto& nent : table->second) { 140 if (nent.dst.IsDefault() && nent.dst.family() == family) { 141 *entry = &nent; 142 SLOG(this, 2) << __func__ << ": found" 143 << " gateway " << nent.gateway.ToString() 144 << " metric " << nent.metric; 145 return true; 146 } 147 } 148 149 SLOG(this, 2) << __func__ << " no route"; 150 return false; 151} 152 153bool RoutingTable::SetDefaultRoute(int interface_index, 154 const IPAddress& gateway_address, 155 uint32_t metric, 156 uint8_t table_id) { 157 SLOG(this, 2) << __func__ << " index " << interface_index 158 << " metric " << metric; 159 160 RoutingTableEntry* old_entry; 161 162 if (GetDefaultRouteInternal(interface_index, 163 gateway_address.family(), 164 &old_entry)) { 165 if (old_entry->gateway.Equals(gateway_address)) { 166 if (old_entry->metric != metric) { 167 ReplaceMetric(interface_index, old_entry, metric); 168 } 169 return true; 170 } else { 171 // TODO(quiche): Update internal state as well? 172 ApplyRoute(interface_index, 173 *old_entry, 174 RTNLMessage::kModeDelete, 175 0); 176 } 177 } 178 179 IPAddress default_address(gateway_address.family()); 180 default_address.SetAddressToDefault(); 181 182 return AddRoute(interface_index, 183 RoutingTableEntry(default_address, 184 default_address, 185 gateway_address, 186 metric, 187 RT_SCOPE_UNIVERSE, 188 false, 189 table_id, 190 RoutingTableEntry::kDefaultTag)); 191} 192 193bool RoutingTable::ConfigureRoutes(int interface_index, 194 const IPConfigRefPtr& ipconfig, 195 uint32_t metric, 196 uint8_t table_id) { 197 bool ret = true; 198 199 IPAddress::Family address_family = ipconfig->properties().address_family; 200 const vector<IPConfig::Route>& routes = ipconfig->properties().routes; 201 202 for (const auto& route : routes) { 203 SLOG(this, 3) << "Installing route:" 204 << " Destination: " << route.host 205 << " Netmask: " << route.netmask 206 << " Gateway: " << route.gateway; 207 IPAddress destination_address(address_family); 208 IPAddress source_address(address_family); // Left as default. 209 IPAddress gateway_address(address_family); 210 if (!destination_address.SetAddressFromString(route.host)) { 211 LOG(ERROR) << "Failed to parse host " 212 << route.host; 213 ret = false; 214 continue; 215 } 216 if (!gateway_address.SetAddressFromString(route.gateway)) { 217 LOG(ERROR) << "Failed to parse gateway " 218 << route.gateway; 219 ret = false; 220 continue; 221 } 222 destination_address.set_prefix( 223 IPAddress::GetPrefixLengthFromMask(address_family, route.netmask)); 224 if (!AddRoute(interface_index, 225 RoutingTableEntry(destination_address, 226 source_address, 227 gateway_address, 228 metric, 229 RT_SCOPE_UNIVERSE, 230 false, 231 table_id, 232 RoutingTableEntry::kDefaultTag))) { 233 ret = false; 234 } 235 } 236 return ret; 237} 238 239void RoutingTable::FlushRoutes(int interface_index) { 240 SLOG(this, 2) << __func__; 241 242 auto table = tables_.find(interface_index); 243 if (table == tables_.end()) { 244 return; 245 } 246 247 for (const auto& nent : table->second) { 248 ApplyRoute(interface_index, nent, RTNLMessage::kModeDelete, 0); 249 } 250 table->second.clear(); 251} 252 253void RoutingTable::FlushRoutesWithTag(int tag) { 254 SLOG(this, 2) << __func__; 255 256 for (auto& table : tables_) { 257 for (auto nent = table.second.begin(); nent != table.second.end();) { 258 if (nent->tag == tag) { 259 ApplyRoute(table.first, *nent, RTNLMessage::kModeDelete, 0); 260 nent = table.second.erase(nent); 261 } else { 262 ++nent; 263 } 264 } 265 } 266} 267 268void RoutingTable::ResetTable(int interface_index) { 269 tables_.erase(interface_index); 270} 271 272void RoutingTable::SetDefaultMetric(int interface_index, uint32_t metric) { 273 SLOG(this, 2) << __func__ << " index " << interface_index 274 << " metric " << metric; 275 276 RoutingTableEntry* entry; 277 if (GetDefaultRouteInternal( 278 interface_index, IPAddress::kFamilyIPv4, &entry) && 279 entry->metric != metric) { 280 ReplaceMetric(interface_index, entry, metric); 281 } 282 283 if (GetDefaultRouteInternal( 284 interface_index, IPAddress::kFamilyIPv6, &entry) && 285 entry->metric != metric) { 286 ReplaceMetric(interface_index, entry, metric); 287 } 288} 289 290// static 291bool RoutingTable::ParseRoutingTableMessage(const RTNLMessage& message, 292 int* interface_index, 293 RoutingTableEntry* entry) { 294 if (message.type() != RTNLMessage::kTypeRoute || 295 message.family() == IPAddress::kFamilyUnknown || 296 !message.HasAttribute(RTA_OIF)) { 297 return false; 298 } 299 300 const RTNLMessage::RouteStatus& route_status = message.route_status(); 301 302 if (route_status.type != RTN_UNICAST) { 303 return false; 304 } 305 306 uint32_t interface_index_u32 = 0; 307 if (!message.GetAttribute(RTA_OIF).ConvertToCPUUInt32(&interface_index_u32)) { 308 return false; 309 } 310 *interface_index = interface_index_u32; 311 312 uint32_t metric = 0; 313 if (message.HasAttribute(RTA_PRIORITY)) { 314 message.GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&metric); 315 } 316 317 IPAddress default_addr(message.family()); 318 default_addr.SetAddressToDefault(); 319 320 ByteString dst_bytes(default_addr.address()); 321 if (message.HasAttribute(RTA_DST)) { 322 dst_bytes = message.GetAttribute(RTA_DST); 323 } 324 ByteString src_bytes(default_addr.address()); 325 if (message.HasAttribute(RTA_SRC)) { 326 src_bytes = message.GetAttribute(RTA_SRC); 327 } 328 ByteString gateway_bytes(default_addr.address()); 329 if (message.HasAttribute(RTA_GATEWAY)) { 330 gateway_bytes = message.GetAttribute(RTA_GATEWAY); 331 } 332 333 entry->dst = IPAddress(message.family(), dst_bytes, route_status.dst_prefix); 334 entry->src = IPAddress(message.family(), src_bytes, route_status.src_prefix); 335 entry->gateway = IPAddress(message.family(), gateway_bytes); 336 entry->metric = metric; 337 entry->scope = route_status.scope; 338 entry->from_rtnl = true; 339 entry->table = route_status.table; 340 341 return true; 342} 343 344void RoutingTable::RouteMsgHandler(const RTNLMessage& message) { 345 int interface_index; 346 RoutingTableEntry entry; 347 348 if (!ParseRoutingTableMessage(message, &interface_index, &entry)) { 349 return; 350 } 351 352 if (!route_queries_.empty() && 353 message.route_status().protocol == RTPROT_UNSPEC) { 354 SLOG(this, 3) << __func__ << ": Message seq: " << message.seq() 355 << " mode " << message.mode() 356 << ", next query seq: " << route_queries_.front().sequence; 357 358 // Purge queries that have expired (sequence number of this message is 359 // greater than that of the head of the route query sequence). Do the 360 // math in a way that's roll-over independent. 361 while (route_queries_.front().sequence - message.seq() > kuint32max / 2) { 362 LOG(ERROR) << __func__ << ": Purging un-replied route request sequence " 363 << route_queries_.front().sequence 364 << " (< " << message.seq() << ")"; 365 route_queries_.pop_front(); 366 if (route_queries_.empty()) 367 return; 368 } 369 370 const Query& query = route_queries_.front(); 371 if (query.sequence == message.seq()) { 372 RoutingTableEntry add_entry(entry); 373 add_entry.from_rtnl = false; 374 add_entry.tag = query.tag; 375 add_entry.table = query.table_id; 376 bool added = true; 377 if (add_entry.gateway.IsDefault()) { 378 SLOG(this, 2) << __func__ << ": Ignoring route result with no gateway " 379 << "since we don't need to plumb these."; 380 } else { 381 SLOG(this, 2) << __func__ << ": Adding host route to " 382 << add_entry.dst.ToString(); 383 added = AddRoute(interface_index, add_entry); 384 } 385 if (added && !query.callback.is_null()) { 386 SLOG(this, 2) << "Running query callback."; 387 query.callback.Run(interface_index, add_entry); 388 } 389 route_queries_.pop_front(); 390 } 391 return; 392 } else if (message.route_status().protocol != RTPROT_BOOT) { 393 // Responses to route queries come back with a protocol of 394 // RTPROT_UNSPEC. Otherwise, normal route updates that we are 395 // interested in come with a protocol of RTPROT_BOOT. 396 return; 397 } 398 399 TableEntryVector& table = tables_[interface_index]; 400 for (auto nent = table.begin(); nent != table.end(); ++nent) { 401 if (nent->dst.Equals(entry.dst) && 402 nent->src.Equals(entry.src) && 403 nent->gateway.Equals(entry.gateway) && 404 nent->scope == entry.scope) { 405 if (message.mode() == RTNLMessage::kModeDelete && 406 nent->metric == entry.metric) { 407 table.erase(nent); 408 } else if (message.mode() == RTNLMessage::kModeAdd) { 409 nent->from_rtnl = true; 410 nent->metric = entry.metric; 411 } 412 return; 413 } 414 } 415 416 if (message.mode() == RTNLMessage::kModeAdd) { 417 SLOG(this, 2) << __func__ << " adding" 418 << " destination " << entry.dst.ToString() 419 << " index " << interface_index 420 << " gateway " << entry.gateway.ToString() 421 << " metric " << entry.metric; 422 table.push_back(entry); 423 } 424} 425 426bool RoutingTable::ApplyRoute(uint32_t interface_index, 427 const RoutingTableEntry& entry, 428 RTNLMessage::Mode mode, 429 unsigned int flags) { 430 SLOG(this, 2) << base::StringPrintf( 431 "%s: dst %s/%d src %s/%d index %d mode %d flags 0x%x", 432 __func__, entry.dst.ToString().c_str(), entry.dst.prefix(), 433 entry.src.ToString().c_str(), entry.src.prefix(), 434 interface_index, mode, flags); 435 436 RTNLMessage message( 437 RTNLMessage::kTypeRoute, 438 mode, 439 NLM_F_REQUEST | flags, 440 0, 441 0, 442 0, 443 entry.dst.family()); 444 445 message.set_route_status(RTNLMessage::RouteStatus( 446 entry.dst.prefix(), 447 entry.src.prefix(), 448 entry.table, 449 RTPROT_BOOT, 450 entry.scope, 451 RTN_UNICAST, 452 0)); 453 454 message.SetAttribute(RTA_DST, entry.dst.address()); 455 if (!entry.src.IsDefault()) { 456 message.SetAttribute(RTA_SRC, entry.src.address()); 457 } 458 if (!entry.gateway.IsDefault()) { 459 message.SetAttribute(RTA_GATEWAY, entry.gateway.address()); 460 } 461 message.SetAttribute(RTA_PRIORITY, 462 ByteString::CreateFromCPUUInt32(entry.metric)); 463 message.SetAttribute(RTA_OIF, 464 ByteString::CreateFromCPUUInt32(interface_index)); 465 466 return rtnl_handler_->SendMessage(&message); 467} 468 469// Somewhat surprisingly, the kernel allows you to create multiple routes 470// to the same destination through the same interface with different metrics. 471// Therefore, to change the metric on a route, we can't just use the 472// NLM_F_REPLACE flag by itself. We have to explicitly remove the old route. 473// We do so after creating the route at a new metric so there is no traffic 474// disruption to existing network streams. 475void RoutingTable::ReplaceMetric(uint32_t interface_index, 476 RoutingTableEntry* entry, 477 uint32_t metric) { 478 SLOG(this, 2) << __func__ << " index " << interface_index 479 << " metric " << metric; 480 RoutingTableEntry new_entry = *entry; 481 new_entry.metric = metric; 482 // First create the route at the new metric. 483 ApplyRoute(interface_index, new_entry, RTNLMessage::kModeAdd, 484 NLM_F_CREATE | NLM_F_REPLACE); 485 // Then delete the route at the old metric. 486 ApplyRoute(interface_index, *entry, RTNLMessage::kModeDelete, 0); 487 // Now, update our routing table (via |*entry|) from |new_entry|. 488 *entry = new_entry; 489} 490 491bool RoutingTable::FlushCache() { 492 static const char* kPaths[2] = { kRouteFlushPath4, kRouteFlushPath6 }; 493 bool ret = true; 494 495 SLOG(this, 2) << __func__; 496 497 for (size_t i = 0; i < arraysize(kPaths); ++i) { 498 if (base::WriteFile(FilePath(kPaths[i]), "-1", 2) != 2) { 499 LOG(ERROR) << base::StringPrintf("Cannot write to route flush file %s", 500 kPaths[i]); 501 ret = false; 502 } 503 } 504 505 return ret; 506} 507 508bool RoutingTable::RequestRouteToHost(const IPAddress& address, 509 int interface_index, 510 int tag, 511 const Query::Callback& callback, 512 uint8_t table_id) { 513 // Make sure we don't get a cached response that is no longer valid. 514 FlushCache(); 515 516 RTNLMessage message( 517 RTNLMessage::kTypeRoute, 518 RTNLMessage::kModeQuery, 519 NLM_F_REQUEST, 520 0, 521 0, 522 interface_index, 523 address.family()); 524 525 RTNLMessage::RouteStatus status; 526 status.dst_prefix = address.prefix(); 527 message.set_route_status(status); 528 message.SetAttribute(RTA_DST, address.address()); 529 530 if (interface_index != -1) { 531 message.SetAttribute(RTA_OIF, 532 ByteString::CreateFromCPUUInt32(interface_index)); 533 } 534 535 if (!rtnl_handler_->SendMessage(&message)) { 536 return false; 537 } 538 539 // Save the sequence number of the request so we can create a route for 540 // this host when we get a reply. 541 route_queries_.push_back(Query(message.seq(), tag, callback, table_id)); 542 543 return true; 544} 545 546bool RoutingTable::CreateBlackholeRoute(int interface_index, 547 IPAddress::Family family, 548 uint32_t metric, 549 uint8_t table_id) { 550 SLOG(this, 2) << base::StringPrintf( 551 "%s: index %d family %s metric %d", 552 __func__, interface_index, 553 IPAddress::GetAddressFamilyName(family).c_str(), metric); 554 555 RTNLMessage message( 556 RTNLMessage::kTypeRoute, 557 RTNLMessage::kModeAdd, 558 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, 559 0, 560 0, 561 0, 562 family); 563 564 message.set_route_status(RTNLMessage::RouteStatus( 565 0, 566 0, 567 table_id, 568 RTPROT_BOOT, 569 RT_SCOPE_UNIVERSE, 570 RTN_BLACKHOLE, 571 0)); 572 573 message.SetAttribute(RTA_PRIORITY, 574 ByteString::CreateFromCPUUInt32(metric)); 575 message.SetAttribute(RTA_OIF, 576 ByteString::CreateFromCPUUInt32(interface_index)); 577 578 return rtnl_handler_->SendMessage(&message); 579} 580 581bool RoutingTable::CreateLinkRoute(int interface_index, 582 const IPAddress& local_address, 583 const IPAddress& remote_address, 584 uint8_t table_id) { 585 if (!local_address.CanReachAddress(remote_address)) { 586 LOG(ERROR) << __func__ << " failed: " 587 << remote_address.ToString() << " is not reachable from " 588 << local_address.ToString(); 589 return false; 590 } 591 592 IPAddress default_address(local_address.family()); 593 default_address.SetAddressToDefault(); 594 IPAddress destination_address(remote_address); 595 destination_address.set_prefix( 596 IPAddress::GetMaxPrefixLength(remote_address.family())); 597 SLOG(this, 2) << "Creating link route to " << destination_address.ToString() 598 << " from " << local_address.ToString() 599 << " on interface index " << interface_index; 600 return AddRoute(interface_index, 601 RoutingTableEntry(destination_address, 602 local_address, 603 default_address, 604 0, 605 RT_SCOPE_LINK, 606 false, 607 table_id, 608 RoutingTableEntry::kDefaultTag)); 609} 610 611} // namespace shill 612