WebRTC should generate default private address even when adapter enumeration is disabled.

Introduce a DefaultAddressProvider such that rtc::Network can't access other part of NetworkManager.

This also removes the hack of generating the loopback address. The dependency has been removed by https://codereview.chromium.org/1417023003/

BUG=webrtc:5061
R=pthatcher@webrtc.org

Review URL: https://codereview.webrtc.org/1411253008 .

Cr-Commit-Position: refs/heads/master@{#10590}
This commit is contained in:
Guo-wei Shieh
2015-11-10 14:47:39 -08:00
parent 542059ef10
commit 9af97f8910
14 changed files with 310 additions and 154 deletions

View File

@ -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),

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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> 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> network(new Network(name,
description,
prefix,
prefix_length,
adapter_type));
scoped_ptr<Network> 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<AsyncSocket> 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;

View File

@ -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<Network*> 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<std::string, Network*> 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<rtc::Network> ipv4_any_address_network_;
rtc::scoped_ptr<rtc::Network> 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_;

View File

@ -10,6 +10,7 @@
#include "webrtc/base/network.h"
#include "webrtc/base/nethelpers.h"
#include "webrtc/base/networkmonitor.h"
#include <vector>
#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<Network*> 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

View File

@ -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_);

View File

@ -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,

View File

@ -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.

View File

@ -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;
};

View File

@ -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) {

View File

@ -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);
}