mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1219557 - don't pair candidates from different reserved networks. r=mt r=bwc
--HG-- extra : transplant_source : %19xT%C2%94C%92%8C%F7%16%FA%5C%CE%3A%C5A%DB%D5%B1%29
This commit is contained in:
parent
ed99b00bec
commit
2e19c2bfed
@ -95,6 +95,24 @@ const unsigned int ICE_TEST_PEER_HIDE_NON_DEFAULT = (1 << 4);
|
||||
|
||||
typedef std::string (*CandidateFilter)(const std::string& candidate);
|
||||
|
||||
std::vector<std::string> split(const std::string &s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim)) {
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
static std::string IsSrflxCandidate(const std::string& candidate) {
|
||||
std::vector<std::string> tokens = split(candidate, ' ');
|
||||
if ((tokens.at(6) == "typ") && (tokens.at(7) == "srflx")) {
|
||||
return candidate;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static std::string IsRelayCandidate(const std::string& candidate) {
|
||||
if (candidate.find("typ relay") != std::string::npos) {
|
||||
return candidate;
|
||||
@ -123,6 +141,14 @@ static std::string IsLoopbackCandidate(const std::string& candidate) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static std::string IsIpv4Candidate(const std::string& candidate) {
|
||||
std::vector<std::string> tokens = split(candidate, ' ');
|
||||
if (tokens.at(4).find(":") == std::string::npos) {
|
||||
return candidate;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static std::string SabotageHostCandidateAndDropReflexive(
|
||||
const std::string& candidate) {
|
||||
if (candidate.find("typ srflx") != std::string::npos) {
|
||||
@ -448,7 +474,7 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetCandidates(size_t stream) {
|
||||
std::vector<std::string> GetCandidates(size_t stream) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
RUN_ON_THREAD(
|
||||
@ -500,6 +526,32 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
expected_remote_addr_ = addr;
|
||||
}
|
||||
|
||||
int GetCandidatesPrivateIpv4Range(size_t stream) {
|
||||
std::vector<std::string> candidates = GetCandidates(stream);
|
||||
|
||||
int host_net = 0;
|
||||
for (auto c : candidates) {
|
||||
if (c.find("typ host") != std::string::npos) {
|
||||
nr_transport_addr addr;
|
||||
std::vector<std::string> tokens = split(c, ' ');
|
||||
int r = nr_str_port_to_transport_addr(tokens.at(4).c_str(), 0, IPPROTO_UDP, &addr);
|
||||
MOZ_ASSERT(!r);
|
||||
if (!r && (addr.ip_version == NR_IPV4)) {
|
||||
int n = nr_transport_addr_get_private_addr_range(&addr);
|
||||
if (n) {
|
||||
if (host_net) {
|
||||
// TODO: add support for multiple private interfaces
|
||||
std::cerr << "This test doesn't support multiple private interfaces";
|
||||
return -1;
|
||||
}
|
||||
host_net = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return host_net;
|
||||
}
|
||||
|
||||
bool gathering_complete() { return gathering_complete_; }
|
||||
int ready_ct() { return ready_ct_; }
|
||||
bool is_ready_s(size_t stream) {
|
||||
@ -2466,6 +2518,40 @@ void DelayRelayCandidates(
|
||||
}
|
||||
}
|
||||
|
||||
void AddNonPairableCandidates(
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates,
|
||||
IceTestPeer *peer, size_t stream, int net_type) {
|
||||
for (int i=1; i<5; i++) {
|
||||
if (net_type == i)
|
||||
continue;
|
||||
switch (i) {
|
||||
case 1:
|
||||
candidates.push_back(new SchedulableTrickleCandidate(peer, stream,
|
||||
"candidate:0 1 UDP 2113601790 10.0.0.1 12345 typ host"));
|
||||
break;
|
||||
case 2:
|
||||
candidates.push_back(new SchedulableTrickleCandidate(peer, stream,
|
||||
"candidate:0 1 UDP 2113601791 172.16.1.1 12345 typ host"));
|
||||
break;
|
||||
case 3:
|
||||
candidates.push_back(new SchedulableTrickleCandidate(peer, stream,
|
||||
"candidate:0 1 UDP 2113601792 192.168.0.1 12345 typ host"));
|
||||
break;
|
||||
case 4:
|
||||
candidates.push_back(new SchedulableTrickleCandidate(peer, stream,
|
||||
"candidate:0 1 UDP 2113601793 100.64.1.1 12345 typ host"));
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = candidates.rbegin(); i != candidates.rend(); ++i) {
|
||||
std::cerr << "Scheduling candidate: " << (*i)->Candidate().c_str() << std::endl;
|
||||
(*i)->Schedule(0);
|
||||
}
|
||||
}
|
||||
|
||||
void DropTrickleCandidates(
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates) {
|
||||
}
|
||||
@ -2862,6 +2948,76 @@ TEST_F(IceConnectTest, TestPollCandPairsAfterConnect) {
|
||||
ASSERT_TRUE(ContainsSucceededPair(pairs));
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestHostCandPairingFilter) {
|
||||
AddStream("first", 1);
|
||||
ASSERT_TRUE(Gather(kDefaultTimeout, false));
|
||||
SetCandidateFilter(IsIpv4Candidate);
|
||||
|
||||
int host_net = p1_->GetCandidatesPrivateIpv4Range(0);
|
||||
if (host_net <= 0) {
|
||||
// TODO bug 1226838: make this work with multiple private IPs
|
||||
FAIL() << "This test needs exactly one private IPv4 host candidate to work" << std::endl;
|
||||
}
|
||||
|
||||
ConnectTrickle();
|
||||
AddNonPairableCandidates(p1_->ControlTrickle(0), p1_, 0, host_net);
|
||||
AddNonPairableCandidates(p2_->ControlTrickle(0), p2_, 0, host_net);
|
||||
|
||||
std::vector<NrIceCandidatePair> pairs;
|
||||
p1_->GetCandidatePairs(0, &pairs);
|
||||
for (auto p : pairs) {
|
||||
std::cerr << "Verifying pair:" << std::endl;
|
||||
p1_->DumpCandidatePair(p);
|
||||
nr_transport_addr addr;
|
||||
nr_str_port_to_transport_addr(p.local.local_addr.host.c_str(), 0, IPPROTO_UDP, &addr);
|
||||
ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) == host_net);
|
||||
nr_str_port_to_transport_addr(p.remote.cand_addr.host.c_str(), 0, IPPROTO_UDP, &addr);
|
||||
ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) == host_net);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestSrflxCandPairingFilter) {
|
||||
if (g_stun_server_address.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddStream("first", 1);
|
||||
ASSERT_TRUE(Gather(kDefaultTimeout));
|
||||
SetCandidateFilter(IsSrflxCandidate);
|
||||
|
||||
if (p1_->GetCandidatesPrivateIpv4Range(0) <= 0) {
|
||||
// TODO bug 1226838: make this work with public IP addresses
|
||||
std::cerr << "Don't run this test at IETF meetings!" << std::endl;
|
||||
FAIL() << "This test needs one private IPv4 host candidate to work" << std::endl;
|
||||
}
|
||||
|
||||
ConnectTrickle();
|
||||
SimulateTrickleP1(0);
|
||||
SimulateTrickleP2(0);
|
||||
|
||||
std::vector<NrIceCandidatePair> pairs;
|
||||
p1_->GetCandidatePairs(0, &pairs);
|
||||
for (auto p : pairs) {
|
||||
std::cerr << "Verifying P1 pair:" << std::endl;
|
||||
p1_->DumpCandidatePair(p);
|
||||
nr_transport_addr addr;
|
||||
nr_str_port_to_transport_addr(p.local.local_addr.host.c_str(), 0, IPPROTO_UDP, &addr);
|
||||
ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) != 0);
|
||||
nr_str_port_to_transport_addr(p.remote.cand_addr.host.c_str(), 0, IPPROTO_UDP, &addr);
|
||||
ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) == 0);
|
||||
}
|
||||
p2_->GetCandidatePairs(0, &pairs);
|
||||
for (auto p : pairs) {
|
||||
std::cerr << "Verifying P2 pair:" << std::endl;
|
||||
p2_->DumpCandidatePair(p);
|
||||
nr_transport_addr addr;
|
||||
nr_str_port_to_transport_addr(p.local.local_addr.host.c_str(), 0, IPPROTO_UDP, &addr);
|
||||
ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) != 0);
|
||||
nr_str_port_to_transport_addr(p.remote.cand_addr.host.c_str(), 0, IPPROTO_UDP, &addr);
|
||||
ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestPollCandPairsDuringConnect) {
|
||||
AddStream("first", 1);
|
||||
ASSERT_TRUE(Gather());
|
||||
|
@ -948,6 +948,46 @@ int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_c
|
||||
return(_status);
|
||||
}
|
||||
|
||||
int nr_ice_component_can_candidate_tcptype_pair(nr_socket_tcp_type left, nr_socket_tcp_type right)
|
||||
{
|
||||
if (left && !right)
|
||||
return(0);
|
||||
if (!left && right)
|
||||
return(0);
|
||||
if (left == TCP_TYPE_ACTIVE && right != TCP_TYPE_PASSIVE)
|
||||
return(0);
|
||||
if (left == TCP_TYPE_SO && right != TCP_TYPE_SO)
|
||||
return(0);
|
||||
if (left == TCP_TYPE_PASSIVE)
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* local vs. remote matters here because we allow private -> public pairing,
|
||||
* but discourage public -> private pairing. */
|
||||
int nr_ice_component_can_candidate_addr_pair(nr_transport_addr *local, nr_transport_addr *remote)
|
||||
{
|
||||
int remote_range;
|
||||
|
||||
if(local->ip_version != remote->ip_version)
|
||||
return(0);
|
||||
if(nr_transport_addr_is_link_local(local) !=
|
||||
nr_transport_addr_is_link_local(remote))
|
||||
return(0);
|
||||
/* This prevents our ice_unittest (or broken clients) from pairing a
|
||||
* loopback with a host candidate. */
|
||||
if(nr_transport_addr_is_loopback(local) !=
|
||||
nr_transport_addr_is_loopback(remote))
|
||||
return(0);
|
||||
remote_range = nr_transport_addr_get_private_addr_range(remote);
|
||||
if(remote_range && (nr_transport_addr_get_private_addr_range(local) !=
|
||||
remote_range))
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote)
|
||||
{
|
||||
int r, _status;
|
||||
@ -975,25 +1015,9 @@ int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pco
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(pcand, &pcomp->candidates, entry_comp){
|
||||
if (lcand->tcp_type && !pcand->tcp_type)
|
||||
if(!nr_ice_component_can_candidate_addr_pair(&lcand->addr, &pcand->addr))
|
||||
continue;
|
||||
if (!lcand->tcp_type && pcand->tcp_type)
|
||||
continue;
|
||||
if (lcand->tcp_type == TCP_TYPE_ACTIVE && pcand->tcp_type != TCP_TYPE_PASSIVE)
|
||||
continue;
|
||||
if (lcand->tcp_type == TCP_TYPE_SO && pcand->tcp_type != TCP_TYPE_SO)
|
||||
continue;
|
||||
if (lcand->tcp_type == TCP_TYPE_PASSIVE)
|
||||
continue;
|
||||
if(pcand->addr.ip_version != lcand->addr.ip_version)
|
||||
continue;
|
||||
/* This prevents our ice_unittest from pairing a loopback with a host
|
||||
* candidate. */
|
||||
if(nr_transport_addr_is_loopback(&lcand->addr) &&
|
||||
!nr_transport_addr_is_loopback(&pcand->addr))
|
||||
continue;
|
||||
if(!nr_transport_addr_is_loopback(&lcand->addr) &&
|
||||
nr_transport_addr_is_loopback(&pcand->addr))
|
||||
if(!nr_ice_component_can_candidate_tcptype_pair(lcand->tcp_type, pcand->tcp_type))
|
||||
continue;
|
||||
|
||||
/*
|
||||
|
@ -395,11 +395,21 @@ int nr_transport_addr_is_loopback(nr_transport_addr *addr)
|
||||
|
||||
int nr_transport_addr_is_link_local(nr_transport_addr *addr)
|
||||
{
|
||||
if(addr->ip_version == NR_IPV6){
|
||||
UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
|
||||
return ((*addrTop & htonl(0xFFC00000)) == htonl(0xFE800000));
|
||||
} else {
|
||||
assert(0);
|
||||
switch(addr->ip_version){
|
||||
case NR_IPV4:
|
||||
/* RFC3927: 169.254/16 */
|
||||
if ((ntohl(addr->u.addr4.sin_addr.s_addr) & 0xFFFF0000) == 0xA9FE0000)
|
||||
return(1);
|
||||
break;
|
||||
case NR_IPV6:
|
||||
{
|
||||
UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
|
||||
if ((*addrTop & htonl(0xFFC00000)) == htonl(0xFE800000))
|
||||
return(2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
return(0);
|
||||
@ -426,3 +436,37 @@ int nr_transport_addr_is_wildcard(nr_transport_addr *addr)
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
nr_transport_addr_mask nr_private_ipv4_addrs[] = {
|
||||
/* RFC1918: 10/8 */
|
||||
{0x0A000000, 0xFF000000},
|
||||
/* RFC1918: 172.16/12 */
|
||||
{0xAC100000, 0xFFF00000},
|
||||
/* RFC1918: 192.168/16 */
|
||||
{0xC0A80000, 0xFFFF0000},
|
||||
/* RFC6598: 100.64/10 */
|
||||
{0x64400000, 0xFFC00000}
|
||||
};
|
||||
|
||||
int nr_transport_addr_get_private_addr_range(nr_transport_addr *addr)
|
||||
{
|
||||
switch(addr->ip_version){
|
||||
case NR_IPV4:
|
||||
{
|
||||
UINT4 ip = ntohl(addr->u.addr4.sin_addr.s_addr);
|
||||
for (int i=0; i<(sizeof(nr_private_ipv4_addrs)/sizeof(nr_transport_addr_mask)); i++) {
|
||||
if ((ip & nr_private_ipv4_addrs[i].mask) == nr_private_ipv4_addrs[i].addr)
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NR_IPV6:
|
||||
return(0);
|
||||
default:
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,6 +71,11 @@ typedef struct nr_transport_addr_ {
|
||||
char as_string[56];
|
||||
} nr_transport_addr;
|
||||
|
||||
typedef struct nr_transport_addr_mask_ {
|
||||
UINT4 addr;
|
||||
UINT4 mask;
|
||||
} nr_transport_addr_mask;
|
||||
|
||||
int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr);
|
||||
|
||||
// addresses, ports in local byte order
|
||||
@ -88,6 +93,7 @@ int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int
|
||||
|
||||
int nr_transport_addr_is_wildcard(nr_transport_addr *addr);
|
||||
int nr_transport_addr_is_loopback(nr_transport_addr *addr);
|
||||
int nr_transport_addr_get_private_addr_range(nr_transport_addr *addr);
|
||||
int nr_transport_addr_is_link_local(nr_transport_addr *addr);
|
||||
int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from);
|
||||
int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, nr_transport_addr *from);
|
||||
|
Loading…
Reference in New Issue
Block a user