diff --git a/talk/app/webrtc/peerconnectioninterface.h b/talk/app/webrtc/peerconnectioninterface.h index 77caa9d78b..b7814e5830 100644 --- a/talk/app/webrtc/peerconnectioninterface.h +++ b/talk/app/webrtc/peerconnectioninterface.h @@ -248,9 +248,6 @@ class PeerConnectionInterface : public rtc::RefCountInterface { // TODO(pthatcher): Rename this ice_servers, but update Chromium // at the same time. IceServers servers; - // A localhost candidate is signaled whenever a candidate with the any - // address is allocated. - bool enable_localhost_ice_candidate; BundlePolicy bundle_policy; RtcpMuxPolicy rtcp_mux_policy; TcpCandidatePolicy tcp_candidate_policy; @@ -262,7 +259,6 @@ class PeerConnectionInterface : public rtc::RefCountInterface { RTCConfiguration() : type(kAll), - enable_localhost_ice_candidate(false), bundle_policy(kBundlePolicyBalanced), rtcp_mux_policy(kRtcpMuxPolicyNegotiate), tcp_candidate_policy(kTcpCandidatePolicyEnabled), diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc index 11b2d602a2..1fc2a37902 100644 --- a/talk/app/webrtc/webrtcsession.cc +++ b/talk/app/webrtc/webrtcsession.cc @@ -743,12 +743,6 @@ bool WebRtcSession::Initialize( port_allocator()->set_candidate_filter( ConvertIceTransportTypeToCandidateFilter(rtc_configuration.type)); - if (rtc_configuration.enable_localhost_ice_candidate) { - port_allocator()->set_flags( - port_allocator()->flags() | - cricket::PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE); - } - return true; } diff --git a/webrtc/base/fakenetwork.h b/webrtc/base/fakenetwork.h index fb99d59e1b..4d98c6c66d 100644 --- a/webrtc/base/fakenetwork.h +++ b/webrtc/base/fakenetwork.h @@ -76,6 +76,7 @@ class FakeNetworkManager : public NetworkManagerBase, } using NetworkManagerBase::set_enumeration_permission; + using NetworkManagerBase::set_default_local_addresses; private: void DoUpdateNetworks() { @@ -95,6 +96,7 @@ class FakeNetworkManager : public NetworkManagerBase, it->hostname(), prefix, prefix_length)); + net->set_default_local_address_provider(this); net->AddIP(it->ipaddr()); networks.push_back(net.release()); } @@ -111,6 +113,9 @@ class FakeNetworkManager : public NetworkManagerBase, int next_index_ = 0; int start_count_ = 0; bool sent_first_update_ = false; + + IPAddress default_local_ipv4_address_; + IPAddress default_local_ipv6_address_; }; } // namespace rtc diff --git a/webrtc/base/ipaddress.cc b/webrtc/base/ipaddress.cc index 316207fe49..f0698e52f1 100644 --- a/webrtc/base/ipaddress.cc +++ b/webrtc/base/ipaddress.cc @@ -506,4 +506,15 @@ IPAddress GetLoopbackIP(int family) { } return rtc::IPAddress(); } + +IPAddress GetAnyIP(int family) { + if (family == AF_INET) { + return rtc::IPAddress(INADDR_ANY); + } + if (family == AF_INET6) { + return rtc::IPAddress(in6addr_any); + } + return rtc::IPAddress(); +} + } // Namespace rtc diff --git a/webrtc/base/ipaddress.h b/webrtc/base/ipaddress.h index fe2d6e2c92..0789017e6d 100644 --- a/webrtc/base/ipaddress.h +++ b/webrtc/base/ipaddress.h @@ -180,6 +180,7 @@ int IPAddressPrecedence(const IPAddress& ip); IPAddress TruncateIP(const IPAddress& ip, int length); IPAddress GetLoopbackIP(int family); +IPAddress GetAnyIP(int family); // Returns the number of contiguously set bits, counting from the MSB in network // byte order, in this IPAddress. Bits after the first 0 encountered are not diff --git a/webrtc/base/network.cc b/webrtc/base/network.cc index 32b2a91844..f35dcbacf8 100644 --- a/webrtc/base/network.cc +++ b/webrtc/base/network.cc @@ -151,6 +151,12 @@ bool IsIgnoredIPv6(const IPAddress& ip) { } // namespace +// These addresses are used as the targets to find out the default local address +// on a multi-homed endpoint. They are actually DNS servers. +const char kPublicIPv4Host[] = "8.8.8.8"; +const char kPublicIPv6Host[] = "2001:4860:4860::8888"; +const int kPublicPort = 53; // DNS port. + std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix, int prefix_length) { std::ostringstream ost; @@ -169,6 +175,10 @@ NetworkManager::EnumerationPermission NetworkManager::enumeration_permission() return ENUMERATION_ALLOWED; } +bool NetworkManager::GetDefaultLocalAddress(int family, IPAddress* addr) const { + return false; +} + NetworkManagerBase::NetworkManagerBase() : enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED), max_ipv6_networks_(kMaxIPv6Networks), @@ -191,6 +201,7 @@ void NetworkManagerBase::GetAnyAddressNetworks(NetworkList* networks) { const rtc::IPAddress ipv4_any_address(INADDR_ANY); ipv4_any_address_network_.reset( new rtc::Network("any", "any", ipv4_any_address, 0)); + ipv4_any_address_network_->set_default_local_address_provider(this); ipv4_any_address_network_->AddIP(ipv4_any_address); } networks->push_back(ipv4_any_address_network_.get()); @@ -200,6 +211,7 @@ void NetworkManagerBase::GetAnyAddressNetworks(NetworkList* networks) { const rtc::IPAddress ipv6_any_address(in6addr_any); ipv6_any_address_network_.reset( new rtc::Network("any", "any", ipv6_any_address, 0)); + ipv6_any_address_network_->set_default_local_address_provider(this); ipv6_any_address_network_->AddIP(ipv6_any_address); } networks->push_back(ipv6_any_address_network_.get()); @@ -321,6 +333,28 @@ void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks, } } +void NetworkManagerBase::set_default_local_addresses(const IPAddress& ipv4, + const IPAddress& ipv6) { + if (ipv4.family() == AF_INET) { + default_local_ipv4_address_ = ipv4; + } + if (ipv6.family() == AF_INET6) { + default_local_ipv6_address_ = ipv6; + } +} + +bool NetworkManagerBase::GetDefaultLocalAddress(int family, + IPAddress* ipaddr) const { + if (family == AF_INET) { + *ipaddr = default_local_ipv4_address_; + return true; + } else if (family == AF_INET6) { + *ipaddr = default_local_ipv6_address_; + return true; + } + return false; +} + BasicNetworkManager::BasicNetworkManager() : thread_(NULL), sent_first_update_(false), start_count_(0), network_ignore_mask_(kDefaultNetworkIgnoreMask), @@ -409,10 +443,9 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces, #endif // TODO(phoglund): Need to recognize other types as well. scoped_ptr network(new Network(cursor->ifa_name, - cursor->ifa_name, - prefix, - prefix_length, - adapter_type)); + cursor->ifa_name, prefix, + prefix_length, adapter_type)); + network->set_default_local_address_provider(this); network->set_scope_id(scope_id); network->AddIP(ip); network->set_ignored(IsIgnoredNetwork(*network)); @@ -563,11 +596,9 @@ bool BasicNetworkManager::CreateNetworks(bool include_ignored, // TODO(phoglund): Need to recognize other types as well. adapter_type = ADAPTER_TYPE_LOOPBACK; } - scoped_ptr network(new Network(name, - description, - prefix, - prefix_length, - adapter_type)); + scoped_ptr network(new Network(name, description, prefix, + prefix_length, adapter_type)); + network->set_default_local_address_provider(this); network->set_scope_id(scope_id); network->AddIP(ip); bool ignored = IsIgnoredNetwork(*network); @@ -724,6 +755,25 @@ void BasicNetworkManager::OnMessage(Message* msg) { } } +IPAddress BasicNetworkManager::QueryDefaultLocalAddress(int family) const { + ASSERT(thread_ == Thread::Current()); + ASSERT(thread_->socketserver() != nullptr); + ASSERT(family == AF_INET || family == AF_INET6); + + scoped_ptr socket( + thread_->socketserver()->CreateAsyncSocket(family, SOCK_DGRAM)); + if (!socket) { + return IPAddress(); + } + + if (!socket->Connect( + SocketAddress(family == AF_INET ? kPublicIPv4Host : kPublicIPv6Host, + kPublicPort))) { + return IPAddress(); + } + return socket->GetLocalAddress().ipaddr(); +} + void BasicNetworkManager::UpdateNetworksOnce() { if (!start_count_) return; @@ -735,7 +785,10 @@ void BasicNetworkManager::UpdateNetworksOnce() { SignalError(); } else { bool changed; - MergeNetworkList(list, &changed); + NetworkManager::Stats stats; + MergeNetworkList(list, &changed, &stats); + set_default_local_addresses(QueryDefaultLocalAddress(AF_INET), + QueryDefaultLocalAddress(AF_INET6)); if (changed || !sent_first_update_) { SignalNetworksChanged(); sent_first_update_ = true; @@ -766,21 +819,34 @@ void BasicNetworkManager::DumpNetworks(bool include_ignored) { } } -Network::Network(const std::string& name, const std::string& desc, - const IPAddress& prefix, int prefix_length) - : name_(name), description_(desc), prefix_(prefix), +Network::Network(const std::string& name, + const std::string& desc, + const IPAddress& prefix, + int prefix_length) + : name_(name), + description_(desc), + prefix_(prefix), prefix_length_(prefix_length), - key_(MakeNetworkKey(name, prefix, prefix_length)), scope_id_(0), - ignored_(false), type_(ADAPTER_TYPE_UNKNOWN), preference_(0) { -} + key_(MakeNetworkKey(name, prefix, prefix_length)), + scope_id_(0), + ignored_(false), + type_(ADAPTER_TYPE_UNKNOWN), + preference_(0) {} -Network::Network(const std::string& name, const std::string& desc, - const IPAddress& prefix, int prefix_length, AdapterType type) - : name_(name), description_(desc), prefix_(prefix), +Network::Network(const std::string& name, + const std::string& desc, + const IPAddress& prefix, + int prefix_length, + AdapterType type) + : name_(name), + description_(desc), + prefix_(prefix), prefix_length_(prefix_length), - key_(MakeNetworkKey(name, prefix, prefix_length)), scope_id_(0), - ignored_(false), type_(type), preference_(0) { -} + key_(MakeNetworkKey(name, prefix, prefix_length)), + scope_id_(0), + ignored_(false), + type_(type), + preference_(0) {} Network::~Network() = default; diff --git a/webrtc/base/network.h b/webrtc/base/network.h index ab3a88dc7d..ccd205e83d 100644 --- a/webrtc/base/network.h +++ b/webrtc/base/network.h @@ -28,6 +28,9 @@ struct ifaddrs; namespace rtc { +extern const char kPublicIPv4Host[]; +extern const char kPublicIPv6Host[]; + class Network; class NetworkMonitorInterface; class Thread; @@ -51,9 +54,17 @@ const int kDefaultNetworkIgnoreMask = ADAPTER_TYPE_LOOPBACK; std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix, int prefix_length); +class DefaultLocalAddressProvider { + public: + virtual ~DefaultLocalAddressProvider() = default; + // The default local address is the local address used in multi-homed endpoint + // when the any address (0.0.0.0 or ::) is used as the local address. + virtual bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const = 0; +}; + // Generic network manager interface. It provides list of local // networks. -class NetworkManager { +class NetworkManager : public DefaultLocalAddressProvider { public: typedef std::vector NetworkList; @@ -67,7 +78,7 @@ class NetworkManager { }; NetworkManager(); - virtual ~NetworkManager(); + ~NetworkManager() override; // Called when network list is updated. sigslot::signal0<> SignalNetworksChanged; @@ -99,6 +110,8 @@ class NetworkManager { // TODO(guoweis): remove this body when chromium implements this. virtual void GetAnyAddressNetworks(NetworkList* networks) {} + bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const override; + // Dumps a list of networks available to LS_INFO. virtual void DumpNetworks(bool include_ignored) {} @@ -128,6 +141,8 @@ class NetworkManagerBase : public NetworkManager { EnumerationPermission enumeration_permission() const override; + bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const override; + protected: typedef std::map NetworkMap; // Updates |networks_| with the networks listed in |list|. If @@ -146,6 +161,9 @@ class NetworkManagerBase : public NetworkManager { enumeration_permission_ = state; } + void set_default_local_addresses(const IPAddress& ipv4, + const IPAddress& ipv6); + private: friend class NetworkTest; @@ -159,6 +177,9 @@ class NetworkManagerBase : public NetworkManager { rtc::scoped_ptr ipv4_any_address_network_; rtc::scoped_ptr ipv6_any_address_network_; + + IPAddress default_local_ipv4_address_; + IPAddress default_local_ipv6_address_; }; // Basic implementation of the NetworkManager interface that gets list @@ -220,6 +241,11 @@ class BasicNetworkManager : public NetworkManagerBase, // based on the network's property instead of any individual IP. bool IsIgnoredNetwork(const Network& network) const; + // This function connects a UDP socket to a public address and returns the + // local address associated it. Since it binds to the "any" address + // internally, it returns the default local address on a multi-homed endpoint. + IPAddress QueryDefaultLocalAddress(int family) const; + private: friend class NetworkTest; @@ -247,13 +273,26 @@ class BasicNetworkManager : public NetworkManagerBase, // Represents a Unix-type network interface, with a name and single address. class Network { public: - Network(const std::string& name, const std::string& description, - const IPAddress& prefix, int prefix_length); + Network(const std::string& name, + const std::string& description, + const IPAddress& prefix, + int prefix_length); - Network(const std::string& name, const std::string& description, - const IPAddress& prefix, int prefix_length, AdapterType type); + Network(const std::string& name, + const std::string& description, + const IPAddress& prefix, + int prefix_length, + AdapterType type); ~Network(); + const DefaultLocalAddressProvider* default_local_address_provider() { + return default_local_address_provider_; + } + void set_default_local_address_provider( + const DefaultLocalAddressProvider* provider) { + default_local_address_provider_ = provider; + } + // Returns the name of the interface this network is associated wtih. const std::string& name() const { return name_; } @@ -323,6 +362,7 @@ class Network { std::string ToString() const; private: + const DefaultLocalAddressProvider* default_local_address_provider_ = nullptr; std::string name_; std::string description_; IPAddress prefix_; diff --git a/webrtc/base/network_unittest.cc b/webrtc/base/network_unittest.cc index 436222127e..5324e86e2c 100644 --- a/webrtc/base/network_unittest.cc +++ b/webrtc/base/network_unittest.cc @@ -10,6 +10,7 @@ #include "webrtc/base/network.h" +#include "webrtc/base/nethelpers.h" #include "webrtc/base/networkmonitor.h" #include #if defined(WEBRTC_POSIX) @@ -96,6 +97,11 @@ class NetworkTest : public testing::Test, public sigslot::has_slots<> { bool callback_called_; }; +class TestBasicNetworkManager : public BasicNetworkManager { + public: + using BasicNetworkManager::QueryDefaultLocalAddress; +}; + // Test that the Network ctor works properly. TEST_F(NetworkTest, TestNetworkConstruct) { Network ipv4_network1("test_eth0", "Test Network Adapter 1", @@ -842,4 +848,19 @@ TEST_F(NetworkTest, TestNetworkMonitoring) { NetworkMonitorFactory::ReleaseFactory(factory); } +TEST_F(NetworkTest, DefaultPrivateAddress) { + TestBasicNetworkManager manager; + manager.StartUpdating(); + std::vector networks; + manager.GetNetworks(&networks); + for (auto& network : networks) { + if (network->GetBestIP().family() == AF_INET) { + EXPECT_TRUE(manager.QueryDefaultLocalAddress(AF_INET) != IPAddress()); + } else if (network->GetBestIP().family() == AF_INET6) { + EXPECT_TRUE(manager.QueryDefaultLocalAddress(AF_INET6) != IPAddress()); + } + } + manager.StopUpdating(); +} + } // namespace rtc diff --git a/webrtc/p2p/base/port_unittest.cc b/webrtc/p2p/base/port_unittest.cc index 4a4ed32456..c3e5df6538 100644 --- a/webrtc/p2p/base/port_unittest.cc +++ b/webrtc/p2p/base/port_unittest.cc @@ -456,9 +456,8 @@ class PortTest : public testing::Test, public sigslot::has_slots<> { } UDPPort* CreateUdpPort(const SocketAddress& addr, PacketSocketFactory* socket_factory) { - return UDPPort::Create(main_, socket_factory, &network_, - addr.ipaddr(), 0, 0, username_, password_, - std::string(), false); + return UDPPort::Create(main_, socket_factory, &network_, addr.ipaddr(), 0, + 0, username_, password_, std::string(), true); } TCPPort* CreateTcpPort(const SocketAddress& addr) { return CreateTcpPort(addr, &socket_factory_); diff --git a/webrtc/p2p/base/portallocator.h b/webrtc/p2p/base/portallocator.h index 4f8ec2fbe6..38650a52a1 100644 --- a/webrtc/p2p/base/portallocator.h +++ b/webrtc/p2p/base/portallocator.h @@ -46,10 +46,14 @@ enum { PORTALLOCATOR_ENABLE_SHARED_UFRAG = 0x80, PORTALLOCATOR_ENABLE_SHARED_SOCKET = 0x100, PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE = 0x200, + // When specified, we'll only allocate the STUN candidate for the public + // interface as seen by regular http traffic and the HOST candidate associated + // with the default local interface. PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION = 0x400, - // When specified, a loopback candidate will be generated if - // PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION is specified. - PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE = 0x800, + // When specified along with PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION, the + // default local candidate mentioned above will not be allocated. Only the + // STUN candidate will be. + PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE = 0x800, // Disallow use of UDP when connecting to a relay server. Since proxy servers // usually don't handle UDP, using UDP will leak the IP address. PORTALLOCATOR_DISABLE_UDP_RELAY = 0x1000, diff --git a/webrtc/p2p/base/stunport.cc b/webrtc/p2p/base/stunport.cc index 86eaf65a21..ab8b2bff18 100644 --- a/webrtc/p2p/base/stunport.cc +++ b/webrtc/p2p/base/stunport.cc @@ -13,6 +13,7 @@ #include "webrtc/p2p/base/common.h" #include "webrtc/p2p/base/portallocator.h" #include "webrtc/p2p/base/stun.h" +#include "webrtc/base/checks.h" #include "webrtc/base/common.h" #include "webrtc/base/helpers.h" #include "webrtc/base/ipaddress.h" @@ -169,15 +170,19 @@ UDPPort::UDPPort(rtc::Thread* thread, const std::string& username, const std::string& password, const std::string& origin, - bool emit_localhost_for_anyaddress) - : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(), - username, password), + bool emit_local_for_anyaddress) + : Port(thread, + factory, + network, + socket->GetLocalAddress().ipaddr(), + username, + password), requests_(thread), socket_(socket), error_(0), ready_(false), stun_keepalive_delay_(KEEPALIVE_DELAY), - emit_localhost_for_anyaddress_(emit_localhost_for_anyaddress) { + emit_local_for_anyaddress_(emit_local_for_anyaddress) { requests_.set_origin(origin); } @@ -190,7 +195,7 @@ UDPPort::UDPPort(rtc::Thread* thread, const std::string& username, const std::string& password, const std::string& origin, - bool emit_localhost_for_anyaddress) + bool emit_local_for_anyaddress) : Port(thread, LOCAL_PORT_TYPE, factory, @@ -205,7 +210,7 @@ UDPPort::UDPPort(rtc::Thread* thread, error_(0), ready_(false), stun_keepalive_delay_(KEEPALIVE_DELAY), - emit_localhost_for_anyaddress_(emit_localhost_for_anyaddress) { + emit_local_for_anyaddress_(emit_local_for_anyaddress) { requests_.set_origin(origin); } @@ -297,13 +302,11 @@ int UDPPort::GetError() { void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket, const rtc::SocketAddress& address) { // When adapter enumeration is disabled and binding to the any address, the - // loopback address will be issued as a candidate instead if - // |emit_localhost_for_anyaddress| is true. This is to allow connectivity on - // demo pages without STUN/TURN to work. + // default local address will be issued as a candidate instead if + // |emit_local_for_anyaddress| is true. This is to allow connectivity for + // applications which absolutely requires a HOST candidate. rtc::SocketAddress addr = address; - if (addr.IsAnyIP() && emit_localhost_for_anyaddress_) { - addr.SetIP(rtc::GetLoopbackIP(addr.family())); - } + MaybeSetDefaultLocalAddress(&addr); AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME, "", "", LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, false); @@ -401,6 +404,19 @@ void UDPPort::SendStunBindingRequest(const rtc::SocketAddress& stun_addr) { } } +void UDPPort::MaybeSetDefaultLocalAddress(rtc::SocketAddress* addr) const { + if (!addr->IsAnyIP() || !emit_local_for_anyaddress_ || + !Network()->default_local_address_provider()) { + return; + } + rtc::IPAddress default_address; + bool result = + Network()->default_local_address_provider()->GetDefaultLocalAddress( + addr->family(), &default_address); + RTC_DCHECK(result && !default_address.IsNil()); + addr->SetIP(default_address); +} + void UDPPort::OnStunBindingRequestSucceeded( const rtc::SocketAddress& stun_server_addr, const rtc::SocketAddress& stun_reflected_addr) { @@ -418,6 +434,7 @@ void UDPPort::OnStunBindingRequestSucceeded( !HasCandidateWithAddress(stun_reflected_addr)) { rtc::SocketAddress related_address = socket_->GetLocalAddress(); + MaybeSetDefaultLocalAddress(&related_address); if (!(candidate_filter() & CF_HOST)) { // If candidate filter doesn't have CF_HOST specified, empty raddr to // avoid local address leakage. diff --git a/webrtc/p2p/base/stunport.h b/webrtc/p2p/base/stunport.h index 62b23cf074..6e7a239578 100644 --- a/webrtc/p2p/base/stunport.h +++ b/webrtc/p2p/base/stunport.h @@ -35,10 +35,9 @@ class UDPPort : public Port { const std::string& username, const std::string& password, const std::string& origin, - bool emit_localhost_for_anyaddress) { - UDPPort* port = new UDPPort(thread, factory, network, socket, - username, password, origin, - emit_localhost_for_anyaddress); + bool emit_local_for_anyaddress) { + UDPPort* port = new UDPPort(thread, factory, network, socket, username, + password, origin, emit_local_for_anyaddress); if (!port->Init()) { delete port; port = NULL; @@ -55,11 +54,10 @@ class UDPPort : public Port { const std::string& username, const std::string& password, const std::string& origin, - bool emit_localhost_for_anyaddress) { - UDPPort* port = new UDPPort(thread, factory, network, - ip, min_port, max_port, - username, password, origin, - emit_localhost_for_anyaddress); + bool emit_local_for_anyaddress) { + UDPPort* port = + new UDPPort(thread, factory, network, ip, min_port, max_port, username, + password, origin, emit_local_for_anyaddress); if (!port->Init()) { delete port; port = NULL; @@ -115,7 +113,7 @@ class UDPPort : public Port { const std::string& username, const std::string& password, const std::string& origin, - bool emit_localhost_for_anyaddress); + bool emit_local_for_anyaddress); UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, @@ -124,7 +122,7 @@ class UDPPort : public Port { const std::string& username, const std::string& password, const std::string& origin, - bool emit_localhost_for_anyaddress); + bool emit_local_for_anyaddress); bool Init(); @@ -150,6 +148,10 @@ class UDPPort : public Port { void SendStunBindingRequests(); + // Helper function which will set |addr|'s IP to the default local address if + // |addr| is the "any" address and |emit_local_for_anyaddress_| is true. + void MaybeSetDefaultLocalAddress(rtc::SocketAddress* addr) const; + private: // A helper class which can be called repeatedly to resolve multiple // addresses, as opposed to rtc::AsyncResolverInterface, which can only @@ -211,8 +213,9 @@ class UDPPort : public Port { bool ready_; int stun_keepalive_delay_; - // This is true when PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE is specified. - bool emit_localhost_for_anyaddress_; + // This is true by default and false when + // PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE is specified. + bool emit_local_for_anyaddress_; friend class StunBindingRequest; }; diff --git a/webrtc/p2p/client/basicportallocator.cc b/webrtc/p2p/client/basicportallocator.cc index 21c8921f40..865fbbb4c0 100644 --- a/webrtc/p2p/client/basicportallocator.cc +++ b/webrtc/p2p/client/basicportallocator.cc @@ -436,7 +436,8 @@ void BasicPortAllocatorSession::AddAllocatedPort(Port* port, // When adapter enumeration is disabled, disable CF_HOST at port level so // local address is not leaked by stunport in the candidate's related address. - if (flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) { + if ((flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) && + (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) { candidate_filter &= ~CF_HOST; } port->set_candidate_filter(candidate_filter); @@ -600,25 +601,6 @@ bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) { return true; } - // If PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE is specified and it's - // loopback address, we should allow it as it's for demo page connectivity - // when no TURN/STUN specified. - if (c.address().IsLoopbackIP() && - (flags() & PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE) != 0) { - return true; - } - - // This is just to prevent the case when binding to any address (all 0s), if - // somehow the host candidate address is not all 0s. Either because local - // installed proxy changes the address or a packet has been sent for any - // reason before getsockname is called. - if (flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) { - LOG(LS_WARNING) << "Received non-0 host address: " - << c.address().ToString() - << " when adapter enumeration is disabled"; - return false; - } - return ((filter & CF_HOST) != 0); } return false; @@ -882,19 +864,19 @@ void AllocationSequence::CreateUDPPorts() { // TODO(mallinath) - Remove UDPPort creating socket after shared socket // is enabled completely. UDPPort* port = NULL; - bool emit_localhost_for_anyaddress = - IsFlagSet(PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE); + bool emit_local_candidate_for_anyaddress = + !IsFlagSet(PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE); if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) { port = UDPPort::Create( session_->network_thread(), session_->socket_factory(), network_, udp_socket_.get(), session_->username(), session_->password(), - session_->allocator()->origin(), emit_localhost_for_anyaddress); + session_->allocator()->origin(), emit_local_candidate_for_anyaddress); } else { port = UDPPort::Create( session_->network_thread(), session_->socket_factory(), network_, ip_, session_->allocator()->min_port(), session_->allocator()->max_port(), session_->username(), session_->password(), - session_->allocator()->origin(), emit_localhost_for_anyaddress); + session_->allocator()->origin(), emit_local_candidate_for_anyaddress); } if (port) { diff --git a/webrtc/p2p/client/portallocator_unittest.cc b/webrtc/p2p/client/portallocator_unittest.cc index 9617688302..45545f5c50 100644 --- a/webrtc/p2p/client/portallocator_unittest.cc +++ b/webrtc/p2p/client/portallocator_unittest.cc @@ -114,6 +114,12 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> { void AddInterface(const SocketAddress& addr, const std::string& if_name) { network_manager_.AddInterface(addr, if_name); } + // The default route is the public address that STUN server will observe when + // the endpoint is sitting on the public internet and the local port is bound + // to the "any" address. This may be different from the default local address + // which the endpoint observes. This can occur if the route to the public + // endpoint like 8.8.8.8 (specified as the default local address) is + // different from the route to the STUN server (the default route). void AddInterfaceAsDefaultRoute(const SocketAddress& addr) { AddInterface(addr); // When a binding comes from the any address, the |addr| will be used as the @@ -254,6 +260,8 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> { const rtc::IPAddress& stun_candidate_addr, const rtc::IPAddress& relay_candidate_udp_transport_addr, const rtc::IPAddress& relay_candidate_tcp_transport_addr) { + network_manager_.set_default_local_addresses(kPrivateAddr.ipaddr(), + rtc::IPAddress()); if (!session_) { EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); } @@ -268,16 +276,20 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> { if (!host_candidate_addr.IsNil()) { EXPECT_PRED5(CheckCandidate, candidates_[total_candidates], cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", - rtc::SocketAddress(host_candidate_addr, 0)); + rtc::SocketAddress(kPrivateAddr.ipaddr(), 0)); ++total_candidates; } if (!stun_candidate_addr.IsNil()) { EXPECT_PRED5(CheckCandidate, candidates_[total_candidates], cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", rtc::SocketAddress(stun_candidate_addr, 0)); - EXPECT_EQ(rtc::EmptySocketAddressWithFamily( - candidates_[total_candidates].address().family()), - candidates_[total_candidates].related_address()); + rtc::IPAddress related_address = host_candidate_addr; + if (host_candidate_addr.IsNil()) { + related_address = + rtc::GetAnyIP(candidates_[total_candidates].address().family()); + } + EXPECT_EQ(related_address, + candidates_[total_candidates].related_address().ipaddr()); ++total_candidates; } if (!relay_candidate_udp_transport_addr.IsNil()) { @@ -589,7 +601,6 @@ TEST_F(PortAllocatorTest, TestGetAllPortsNoAdapters) { // candidate_filter() is set to CF_RELAY and no relay is specified. TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationWithoutNatRelayTransportOnly) { - AddInterfaceAsDefaultRoute(kClientAddr); ResetWithStunServerNoNat(kStunAddr); allocator().set_candidate_filter(cricket::CF_RELAY); // Expect to see no ports and no candidates. @@ -597,86 +608,88 @@ TEST_F(PortAllocatorTest, rtc::IPAddress(), rtc::IPAddress()); } -// Test that we should only get STUN and TURN candidates when adapter -// enumeration is disabled. -TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationBehindNat) { - AddInterface(kClientAddr); - // GTURN is not configured here. - ResetWithStunServerAndNat(kStunAddr); - AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress()); - // Expect to see 3 ports: STUN, TURN/UDP and TCP ports, and both STUN and - // TURN/UDP candidates. - CheckDisableAdapterEnumeration(3U, rtc::IPAddress(), kNatUdpAddr.ipaddr(), - kTurnUdpExtAddr.ipaddr(), rtc::IPAddress()); -} - -// Test that even with multiple interfaces, the result should still be one STUN -// and one TURN candidate since we bind to any address (i.e. all 0s). +// Test that even with multiple interfaces, the result should still be a single +// default private, one STUN and one TURN candidate since we bind to any address +// (i.e. all 0s). TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationBehindNatMultipleInterfaces) { AddInterface(kPrivateAddr); AddInterface(kPrivateAddr2); ResetWithStunServerAndNat(kStunAddr); AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress()); - // Expect to see 3 ports: STUN, TURN/UDP and TCP ports, and both STUN and - // TURN/UDP candidates. - CheckDisableAdapterEnumeration(3U, rtc::IPAddress(), kNatUdpAddr.ipaddr(), - kTurnUdpExtAddr.ipaddr(), rtc::IPAddress()); + // Expect to see 3 ports: STUN, TURN/UDP and TCP ports, and a default private, + // STUN and TURN/UDP candidates. + CheckDisableAdapterEnumeration(3U, kPrivateAddr.ipaddr(), + kNatUdpAddr.ipaddr(), kTurnUdpExtAddr.ipaddr(), + rtc::IPAddress()); } -// Test that we should get STUN, TURN/UDP and TURN/TCP candidates when a -// TURN/TCP server is specified. +// Test that we should get a default private, STUN, TURN/UDP and TURN/TCP +// candidates when both TURN/UDP and TURN/TCP servers are specified. TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationBehindNatWithTcp) { turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); - AddInterface(kClientAddr); - // GTURN is not configured here. + AddInterface(kPrivateAddr); ResetWithStunServerAndNat(kStunAddr); AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr); - // Expect to see 4 ports - STUN, TURN/UDP, TURN/TCP and TCP port. STUN, - // TURN/UDP, and TURN/TCP candidates. - CheckDisableAdapterEnumeration(4U, rtc::IPAddress(), kNatUdpAddr.ipaddr(), - kTurnUdpExtAddr.ipaddr(), + // Expect to see 4 ports - STUN, TURN/UDP, TURN/TCP and TCP port. A default + // private, STUN, TURN/UDP, and TURN/TCP candidates. + CheckDisableAdapterEnumeration(4U, kPrivateAddr.ipaddr(), + kNatUdpAddr.ipaddr(), kTurnUdpExtAddr.ipaddr(), kTurnUdpExtAddr.ipaddr()); } -// Test that we should only get STUN and TURN candidates when adapter -// enumeration is disabled. Since the endpoint is not behind NAT, the srflx -// address should be the public client interface. -TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationWithoutNat) { - AddInterfaceAsDefaultRoute(kClientAddr); - ResetWithStunServerNoNat(kStunAddr); - AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress()); - // Expect to see 3 ports: STUN, TURN/UDP and TCP ports, but only both STUN and - // TURN candidates. The STUN candidate should have kClientAddr as srflx - // address, and TURN candidate with kClientAddr as the related address. - CheckDisableAdapterEnumeration(3U, rtc::IPAddress(), kClientAddr.ipaddr(), - kTurnUdpExtAddr.ipaddr(), rtc::IPAddress()); +// Test that when adapter enumeration is disabled, for endpoints without +// STUN/TURN specified, a default private candidate is still generated. +TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationWithoutNatOrServers) { + ResetWithNoServersOrNat(); + // Expect to see 2 ports: STUN and TCP ports, one default private candidate. + CheckDisableAdapterEnumeration(2U, kPrivateAddr.ipaddr(), rtc::IPAddress(), + rtc::IPAddress(), rtc::IPAddress()); } -// Test that when adapter enumeration is disabled, for endpoints without -// STUN/TURN specified, no candidate is generated. -TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationWithoutNatOrServers) { - AddInterfaceAsDefaultRoute(kClientAddr); - ResetWithNoServersOrNat(); - // Expect to see 2 ports: STUN and TCP ports, but no candidate. +// Test that when adapter enumeration is disabled, with +// PORTALLOCATOR_DISABLE_LOCALHOST_CANDIDATE specified, for endpoints not behind +// a NAT, there is no local candidate. +TEST_F(PortAllocatorTest, + TestDisableAdapterEnumerationWithoutNatLocalhostCandidateDisabled) { + ResetWithStunServerNoNat(kStunAddr); + EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); + session_->set_flags(cricket::PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE); + // Expect to see 2 ports: STUN and TCP ports, localhost candidate and STUN + // candidate. CheckDisableAdapterEnumeration(2U, rtc::IPAddress(), rtc::IPAddress(), rtc::IPAddress(), rtc::IPAddress()); } // Test that when adapter enumeration is disabled, with -// PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE specified, for endpoints not behind -// a NAT, there are a localhost candidate in addition to a STUN candidate. -TEST_F(PortAllocatorTest, - TestDisableAdapterEnumerationWithoutNatLocalhostCandidateRequested) { - AddInterfaceAsDefaultRoute(kClientAddr); +// PORTALLOCATOR_DISABLE_LOCALHOST_CANDIDATE specified, for endpoints not behind +// a NAT, there is no local candidate. However, this specified default route +// (kClientAddr) which was discovered when sending STUN requests, will become +// the srflx addresses. +TEST_F( + PortAllocatorTest, + TestDisableAdapterEnumerationWithoutNatLocalhostCandidateDisabledWithDifferentDefaultRoute) { ResetWithStunServerNoNat(kStunAddr); + AddInterfaceAsDefaultRoute(kClientAddr); EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->set_flags(cricket::PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE); + session_->set_flags(cricket::PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE); // Expect to see 2 ports: STUN and TCP ports, localhost candidate and STUN // candidate. - CheckDisableAdapterEnumeration(2U, rtc::GetLoopbackIP(AF_INET), - kClientAddr.ipaddr(), rtc::IPAddress(), - rtc::IPAddress()); + CheckDisableAdapterEnumeration(2U, rtc::IPAddress(), kClientAddr.ipaddr(), + rtc::IPAddress(), rtc::IPAddress()); +} + +// Test that when adapter enumeration is disabled, with +// PORTALLOCATOR_DISABLE_LOCALHOST_CANDIDATE specified, for endpoints behind a +// NAT, there is only one STUN candidate. +TEST_F(PortAllocatorTest, + TestDisableAdapterEnumerationWithNatLocalhostCandidateDisabled) { + ResetWithStunServerAndNat(kStunAddr); + EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); + session_->set_flags(cricket::PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE); + // Expect to see 2 ports: STUN and TCP ports, and single STUN candidate. + CheckDisableAdapterEnumeration(2U, rtc::IPAddress(), kNatUdpAddr.ipaddr(), + rtc::IPAddress(), rtc::IPAddress()); } // Test that we disable relay over UDP, and only TCP is used when connecting to @@ -1244,7 +1257,8 @@ TEST_F(PortAllocatorTest, TestSharedSocketNoUdpAllowed) { // adapters, the PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION is specified // automatically. TEST_F(PortAllocatorTest, TestNetworkPermissionBlocked) { - AddInterface(kClientAddr); + network_manager_.set_default_local_addresses(kPrivateAddr.ipaddr(), + rtc::IPAddress()); network_manager_.set_enumeration_permission( rtc::NetworkManager::ENUMERATION_BLOCKED); allocator().set_flags(allocator().flags() | @@ -1258,7 +1272,10 @@ TEST_F(PortAllocatorTest, TestNetworkPermissionBlocked) { cricket::PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION); session_->StartGettingPorts(); EXPECT_EQ_WAIT(1U, ports_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(0U, candidates_.size()); + EXPECT_EQ(1U, candidates_.size()); + EXPECT_PRED5(CheckCandidate, candidates_[0], + cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", + kPrivateAddr); EXPECT_TRUE((session_->flags() & cricket::PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) != 0); }