| Index: webrtc/p2p/client/basicportallocator.cc
|
| diff --git a/webrtc/p2p/client/basicportallocator.cc b/webrtc/p2p/client/basicportallocator.cc
|
| index bf61bc88fc9612074b6eaa5e387b026645027eb2..14f7b13212db920adbfd7bc957eb1894ef798e8d 100644
|
| --- a/webrtc/p2p/client/basicportallocator.cc
|
| +++ b/webrtc/p2p/client/basicportallocator.cc
|
| @@ -167,6 +167,29 @@ BasicPortAllocatorSession::~BasicPortAllocatorSession() {
|
| delete sequences_[i];
|
| }
|
|
|
| +void BasicPortAllocatorSession::SetCandidateFilter(uint32_t filter) {
|
| + if (filter == candidate_filter_) {
|
| + return;
|
| + }
|
| + // We assume the filter will only change from "ALL" to something else.
|
| + RTC_DCHECK(candidate_filter_ == CF_ALL);
|
| + candidate_filter_ = filter;
|
| + for (PortData& port : ports_) {
|
| + if (!port.has_pairable_candidate()) {
|
| + continue;
|
| + }
|
| + const auto& candidates = port.port()->Candidates();
|
| + // Setting a filter may cause a ready port to become non-ready
|
| + // if it no longer has any pairable candidates.
|
| + if (!std::any_of(candidates.begin(), candidates.end(),
|
| + [this, &port](const Candidate& candidate) {
|
| + return CandidatePairable(candidate, port.port());
|
| + })) {
|
| + port.set_has_pairable_candidate(false);
|
| + }
|
| + }
|
| +}
|
| +
|
| void BasicPortAllocatorSession::StartGettingPorts() {
|
| network_thread_ = rtc::Thread::Current();
|
| if (!socket_factory_) {
|
| @@ -195,7 +218,7 @@ void BasicPortAllocatorSession::ClearGettingPorts() {
|
| std::vector<PortInterface*> BasicPortAllocatorSession::ReadyPorts() const {
|
| std::vector<PortInterface*> ret;
|
| for (const PortData& port : ports_) {
|
| - if (port.ready() || port.complete()) {
|
| + if (port.has_pairable_candidate() && !port.error()) {
|
| ret.push_back(port.port());
|
| }
|
| }
|
| @@ -214,12 +237,32 @@ std::vector<Candidate> BasicPortAllocatorSession::ReadyCandidates() const {
|
| !data.sequence()->ProtocolEnabled(pvalue)) {
|
| continue;
|
| }
|
| - candidates.push_back(candidate);
|
| + candidates.push_back(SanitizeRelatedAddress(candidate));
|
| }
|
| }
|
| return candidates;
|
| }
|
|
|
| +Candidate BasicPortAllocatorSession::SanitizeRelatedAddress(
|
| + const Candidate& c) const {
|
| + Candidate copy = c;
|
| + // If adapter enumeration is disabled or host candidates are disabled,
|
| + // clear the raddr of STUN candidates to avoid local address leakage.
|
| + bool filter_stun_related_address =
|
| + ((flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) &&
|
| + (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) ||
|
| + !(candidate_filter_ & CF_HOST);
|
| + // If the candidate filter doesn't allow reflexive addresses, empty TURN raddr
|
| + // to avoid reflexive address leakage.
|
| + bool filter_turn_related_address = !(candidate_filter_ & CF_REFLEXIVE);
|
| + if ((c.type() == STUN_PORT_TYPE && filter_stun_related_address) ||
|
| + (c.type() == RELAY_PORT_TYPE && filter_turn_related_address)) {
|
| + copy.set_related_address(
|
| + rtc::EmptySocketAddressWithFamily(copy.address().family()));
|
| + }
|
| + return copy;
|
| +}
|
| +
|
| bool BasicPortAllocatorSession::CandidatesAllocationDone() const {
|
| // Done only if all required AllocationSequence objects
|
| // are created.
|
| @@ -483,17 +526,6 @@ void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
|
| port->set_send_retransmit_count_attribute(
|
| (flags() & PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0);
|
|
|
| - // Push down the candidate_filter to individual port.
|
| - uint32_t candidate_filter = allocator_->candidate_filter();
|
| -
|
| - // 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) &&
|
| - (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) {
|
| - candidate_filter &= ~CF_HOST;
|
| - }
|
| - port->set_candidate_filter(candidate_filter);
|
| -
|
| PortData data(port, seq);
|
| ports_.push_back(data);
|
|
|
| @@ -529,44 +561,29 @@ void BasicPortAllocatorSession::OnCandidateReady(
|
| }
|
|
|
| ProtocolType pvalue;
|
| - bool candidate_signalable = CheckCandidateFilter(c);
|
| -
|
| - // When device enumeration is disabled (to prevent non-default IP addresses
|
| - // from leaking), we ping from some local candidates even though we don't
|
| - // signal them. However, if host candidates are also disabled (for example, to
|
| - // prevent even default IP addresses from leaking), we still don't want to
|
| - // ping from them, even if device enumeration is disabled. Thus, we check for
|
| - // both device enumeration and host candidates being disabled.
|
| - bool network_enumeration_disabled = c.address().IsAnyIP();
|
| - bool can_ping_from_candidate =
|
| - (port->SharedSocket() || c.protocol() == TCP_PROTOCOL_NAME);
|
| - bool host_canidates_disabled = !(allocator_->candidate_filter() & CF_HOST);
|
| -
|
| - bool candidate_pairable =
|
| - candidate_signalable ||
|
| - (network_enumeration_disabled && can_ping_from_candidate &&
|
| - !host_canidates_disabled);
|
| bool candidate_protocol_enabled =
|
| StringToProto(c.protocol().c_str(), &pvalue) &&
|
| data->sequence()->ProtocolEnabled(pvalue);
|
|
|
| - if (candidate_signalable && candidate_protocol_enabled) {
|
| + if (CheckCandidateFilter(c) && candidate_protocol_enabled) {
|
| std::vector<Candidate> candidates;
|
| - candidates.push_back(c);
|
| + candidates.push_back(SanitizeRelatedAddress(c));
|
| SignalCandidatesReady(this, candidates);
|
| }
|
|
|
| - // Port has been made ready. Nothing to do here.
|
| - if (data->ready()) {
|
| + // Port has already been marked as having a pairable candidate.
|
| + // Nothing to do here.
|
| + if (data->has_pairable_candidate()) {
|
| return;
|
| }
|
|
|
| - // Move the port to the READY state, either because we have a usable candidate
|
| - // from the port, or simply because the port is bound to the any address and
|
| - // therefore has no host candidate. This will trigger the port to start
|
| - // creating candidate pairs (connections) and issue connectivity checks.
|
| - if (candidate_pairable) {
|
| - data->set_ready();
|
| + // Mark that the port has a pairable candidate, either because we have a
|
| + // usable candidate from the port, or simply because the port is bound to the
|
| + // any address and therefore has no host candidate. This will trigger the port
|
| + // to start creating candidate pairs (connections) and issue connectivity
|
| + // checks.
|
| + if (CandidatePairable(c, port)) {
|
| + data->set_has_pairable_candidate(true);
|
| SignalPortReady(this, port);
|
| }
|
| }
|
| @@ -613,8 +630,9 @@ void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq,
|
|
|
| const std::vector<Candidate>& potentials = it->port()->Candidates();
|
| for (size_t i = 0; i < potentials.size(); ++i) {
|
| - if (!CheckCandidateFilter(potentials[i]))
|
| + if (!CheckCandidateFilter(potentials[i])) {
|
| continue;
|
| + }
|
| ProtocolType pvalue;
|
| bool candidate_protocol_enabled =
|
| StringToProto(potentials[i].protocol().c_str(), &pvalue) &&
|
| @@ -631,7 +649,7 @@ void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq,
|
| }
|
|
|
| bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) const {
|
| - uint32_t filter = allocator_->candidate_filter();
|
| + uint32_t filter = candidate_filter_;
|
|
|
| // When binding to any address, before sending packets out, the getsockname
|
| // returns all 0s, but after sending packets, it'll be the NIC used to
|
| @@ -661,6 +679,26 @@ bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) const {
|
| return false;
|
| }
|
|
|
| +bool BasicPortAllocatorSession::CandidatePairable(const Candidate& c,
|
| + const Port* port) const {
|
| + bool candidate_signalable = CheckCandidateFilter(c);
|
| +
|
| + // When device enumeration is disabled (to prevent non-default IP addresses
|
| + // from leaking), we ping from some local candidates even though we don't
|
| + // signal them. However, if host candidates are also disabled (for example, to
|
| + // prevent even default IP addresses from leaking), we still don't want to
|
| + // ping from them, even if device enumeration is disabled. Thus, we check for
|
| + // both device enumeration and host candidates being disabled.
|
| + bool network_enumeration_disabled = c.address().IsAnyIP();
|
| + bool can_ping_from_candidate =
|
| + (port->SharedSocket() || c.protocol() == TCP_PROTOCOL_NAME);
|
| + bool host_candidates_disabled = !(candidate_filter_ & CF_HOST);
|
| +
|
| + return candidate_signalable ||
|
| + (network_enumeration_disabled && can_ping_from_candidate &&
|
| + !host_candidates_disabled);
|
| +}
|
| +
|
| void BasicPortAllocatorSession::OnPortAllocationComplete(
|
| AllocationSequence* seq) {
|
| // Send candidate allocation complete signal if all ports are done.
|
|
|