diff --git a/webrtc/base/network.cc b/webrtc/base/network.cc index 0018779470..c9ad181776 100644 --- a/webrtc/base/network.cc +++ b/webrtc/base/network.cc @@ -357,12 +357,34 @@ bool NetworkManagerBase::GetDefaultLocalAddress(int family, *ipaddr = default_local_ipv4_address_; return true; } else if (family == AF_INET6 && !default_local_ipv6_address_.IsNil()) { - *ipaddr = default_local_ipv6_address_; + Network* ipv6_network = GetNetworkFromAddress(default_local_ipv6_address_); + if (ipv6_network) { + // If the default ipv6 network's BestIP is different than + // default_local_ipv6_address_, use it instead. + // This is to prevent potential IP address leakage. See WebRTC bug 5376. + *ipaddr = ipv6_network->GetBestIP(); + } else { + *ipaddr = default_local_ipv6_address_; + } return true; } return false; } +Network* NetworkManagerBase::GetNetworkFromAddress( + const rtc::IPAddress& ip) const { + for (Network* network : networks_) { + const auto& ips = network->GetIPs(); + if (std::find_if(ips.begin(), ips.end(), + [ip](const InterfaceAddress& existing_ip) { + return ip == static_cast(existing_ip); + }) != ips.end()) { + return network; + } + } + return nullptr; +} + BasicNetworkManager::BasicNetworkManager() : thread_(NULL), sent_first_update_(false), start_count_(0), ignore_non_default_routes_(false) { diff --git a/webrtc/base/network.h b/webrtc/base/network.h index ee22d5e573..7c328fffe9 100644 --- a/webrtc/base/network.h +++ b/webrtc/base/network.h @@ -160,6 +160,8 @@ class NetworkManagerBase : public NetworkManager { private: friend class NetworkTest; + Network* GetNetworkFromAddress(const rtc::IPAddress& ip) const; + EnumerationPermission enumeration_permission_; NetworkList networks_; diff --git a/webrtc/base/network_unittest.cc b/webrtc/base/network_unittest.cc index 7133d8b405..d365477a07 100644 --- a/webrtc/base/network_unittest.cc +++ b/webrtc/base/network_unittest.cc @@ -1006,6 +1006,35 @@ TEST_F(NetworkTest, DefaultLocalAddress) { EXPECT_EQ(ip, GetLoopbackIP(AF_INET)); EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET6, &ip)); EXPECT_EQ(ip, GetLoopbackIP(AF_INET6)); + + // More tests on GetDefaultLocalAddress with ipv6 addresses where the set + // default address may be different from the best IP address of any network. + InterfaceAddress ip1; + EXPECT_TRUE(IPFromString("abcd::1234:5678:abcd:1111", + IPV6_ADDRESS_FLAG_TEMPORARY, &ip1)); + // Create a network with a prefix of ip1. + Network ipv6_network("test_eth0", "Test NetworkAdapter", TruncateIP(ip1, 64), + 64); + IPAddress ip2; + EXPECT_TRUE(IPFromString("abcd::1234:5678:abcd:2222", &ip2)); + ipv6_network.AddIP(ip1); + ipv6_network.AddIP(ip2); + BasicNetworkManager::NetworkList list(1, new Network(ipv6_network)); + bool changed; + MergeNetworkList(manager, list, &changed); + // If the set default address is not in any network, GetDefaultLocalAddress + // should return it. + IPAddress ip3; + EXPECT_TRUE(IPFromString("abcd::1234:5678:abcd:3333", &ip3)); + manager.set_default_local_addresses(GetLoopbackIP(AF_INET), ip3); + EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET6, &ip)); + EXPECT_EQ(ip3, ip); + // If the set default address is in a network, GetDefaultLocalAddress will + // return the best IP in that network. + manager.set_default_local_addresses(GetLoopbackIP(AF_INET), ip2); + EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET6, &ip)); + EXPECT_EQ(static_cast(ip1), ip); + manager.StopUpdating(); }