• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "p2p/base/port_allocator.h"
12 
13 #include <iterator>
14 #include <set>
15 #include <utility>
16 
17 #include "absl/strings/string_view.h"
18 #include "p2p/base/ice_credentials_iterator.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 
22 namespace cricket {
23 
RelayServerConfig()24 RelayServerConfig::RelayServerConfig() {}
25 
RelayServerConfig(const rtc::SocketAddress & address,absl::string_view username,absl::string_view password,ProtocolType proto)26 RelayServerConfig::RelayServerConfig(const rtc::SocketAddress& address,
27                                      absl::string_view username,
28                                      absl::string_view password,
29                                      ProtocolType proto)
30     : credentials(username, password) {
31   ports.push_back(ProtocolAddress(address, proto));
32 }
33 
RelayServerConfig(absl::string_view address,int port,absl::string_view username,absl::string_view password,ProtocolType proto)34 RelayServerConfig::RelayServerConfig(absl::string_view address,
35                                      int port,
36                                      absl::string_view username,
37                                      absl::string_view password,
38                                      ProtocolType proto)
39     : RelayServerConfig(rtc::SocketAddress(address, port),
40                         username,
41                         password,
42                         proto) {}
43 
44 // Legacy constructor where "secure" and PROTO_TCP implies PROTO_TLS.
RelayServerConfig(absl::string_view address,int port,absl::string_view username,absl::string_view password,ProtocolType proto,bool secure)45 RelayServerConfig::RelayServerConfig(absl::string_view address,
46                                      int port,
47                                      absl::string_view username,
48                                      absl::string_view password,
49                                      ProtocolType proto,
50                                      bool secure)
51     : RelayServerConfig(address,
52                         port,
53                         username,
54                         password,
55                         (proto == PROTO_TCP && secure ? PROTO_TLS : proto)) {}
56 
57 RelayServerConfig::RelayServerConfig(const RelayServerConfig&) = default;
58 
59 RelayServerConfig::~RelayServerConfig() = default;
60 
PortAllocatorSession(absl::string_view content_name,int component,absl::string_view ice_ufrag,absl::string_view ice_pwd,uint32_t flags)61 PortAllocatorSession::PortAllocatorSession(absl::string_view content_name,
62                                            int component,
63                                            absl::string_view ice_ufrag,
64                                            absl::string_view ice_pwd,
65                                            uint32_t flags)
66     : flags_(flags),
67       generation_(0),
68       content_name_(content_name),
69       component_(component),
70       ice_ufrag_(ice_ufrag),
71       ice_pwd_(ice_pwd),
72       tiebreaker_(0) {
73   // Pooled sessions are allowed to be created with empty content name,
74   // component, ufrag and password.
75   RTC_DCHECK(ice_ufrag.empty() == ice_pwd.empty());
76 }
77 
78 PortAllocatorSession::~PortAllocatorSession() = default;
79 
IsCleared() const80 bool PortAllocatorSession::IsCleared() const {
81   return false;
82 }
83 
IsStopped() const84 bool PortAllocatorSession::IsStopped() const {
85   return false;
86 }
87 
generation()88 uint32_t PortAllocatorSession::generation() {
89   return generation_;
90 }
91 
set_generation(uint32_t generation)92 void PortAllocatorSession::set_generation(uint32_t generation) {
93   generation_ = generation;
94 }
95 
PortAllocator()96 PortAllocator::PortAllocator()
97     : flags_(kDefaultPortAllocatorFlags),
98       min_port_(0),
99       max_port_(0),
100       max_ipv6_networks_(kDefaultMaxIPv6Networks),
101       step_delay_(kDefaultStepDelay),
102       allow_tcp_listen_(true),
103       candidate_filter_(CF_ALL),
104       tiebreaker_(0) {
105   // The allocator will be attached to a thread in Initialize.
106   thread_checker_.Detach();
107 }
108 
Initialize()109 void PortAllocator::Initialize() {
110   RTC_DCHECK(thread_checker_.IsCurrent());
111   initialized_ = true;
112 }
113 
~PortAllocator()114 PortAllocator::~PortAllocator() {
115   CheckRunOnValidThreadIfInitialized();
116 }
117 
set_restrict_ice_credentials_change(bool value)118 void PortAllocator::set_restrict_ice_credentials_change(bool value) {
119   restrict_ice_credentials_change_ = value;
120 }
121 
122 // Deprecated
SetConfiguration(const ServerAddresses & stun_servers,const std::vector<RelayServerConfig> & turn_servers,int candidate_pool_size,bool prune_turn_ports,webrtc::TurnCustomizer * turn_customizer,const absl::optional<int> & stun_candidate_keepalive_interval)123 bool PortAllocator::SetConfiguration(
124     const ServerAddresses& stun_servers,
125     const std::vector<RelayServerConfig>& turn_servers,
126     int candidate_pool_size,
127     bool prune_turn_ports,
128     webrtc::TurnCustomizer* turn_customizer,
129     const absl::optional<int>& stun_candidate_keepalive_interval) {
130   webrtc::PortPrunePolicy turn_port_prune_policy =
131       prune_turn_ports ? webrtc::PRUNE_BASED_ON_PRIORITY : webrtc::NO_PRUNE;
132   return SetConfiguration(stun_servers, turn_servers, candidate_pool_size,
133                           turn_port_prune_policy, turn_customizer,
134                           stun_candidate_keepalive_interval);
135 }
136 
SetConfiguration(const ServerAddresses & stun_servers,const std::vector<RelayServerConfig> & turn_servers,int candidate_pool_size,webrtc::PortPrunePolicy turn_port_prune_policy,webrtc::TurnCustomizer * turn_customizer,const absl::optional<int> & stun_candidate_keepalive_interval)137 bool PortAllocator::SetConfiguration(
138     const ServerAddresses& stun_servers,
139     const std::vector<RelayServerConfig>& turn_servers,
140     int candidate_pool_size,
141     webrtc::PortPrunePolicy turn_port_prune_policy,
142     webrtc::TurnCustomizer* turn_customizer,
143     const absl::optional<int>& stun_candidate_keepalive_interval) {
144   CheckRunOnValidThreadIfInitialized();
145   // A positive candidate pool size would lead to the creation of a pooled
146   // allocator session and starting getting ports, which we should only do on
147   // the network thread.
148   RTC_DCHECK(candidate_pool_size == 0 || thread_checker_.IsCurrent());
149   bool ice_servers_changed =
150       (stun_servers != stun_servers_ || turn_servers != turn_servers_);
151   stun_servers_ = stun_servers;
152   turn_servers_ = turn_servers;
153   turn_port_prune_policy_ = turn_port_prune_policy;
154 
155   if (candidate_pool_frozen_) {
156     if (candidate_pool_size != candidate_pool_size_) {
157       RTC_LOG(LS_ERROR)
158           << "Trying to change candidate pool size after pool was frozen.";
159       return false;
160     }
161     return true;
162   }
163 
164   if (candidate_pool_size < 0) {
165     RTC_LOG(LS_ERROR) << "Can't set negative pool size.";
166     return false;
167   }
168 
169   candidate_pool_size_ = candidate_pool_size;
170 
171   // If ICE servers changed, throw away any existing pooled sessions and create
172   // new ones.
173   if (ice_servers_changed) {
174     pooled_sessions_.clear();
175   }
176 
177   turn_customizer_ = turn_customizer;
178 
179   // If `candidate_pool_size_` is less than the number of pooled sessions, get
180   // rid of the extras.
181   while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) {
182     pooled_sessions_.back().reset(nullptr);
183     pooled_sessions_.pop_back();
184   }
185 
186   // `stun_candidate_keepalive_interval_` will be used in STUN port allocation
187   // in future sessions. We also update the ready ports in the pooled sessions.
188   // Ports in sessions that are taken and owned by P2PTransportChannel will be
189   // updated there via IceConfig.
190   stun_candidate_keepalive_interval_ = stun_candidate_keepalive_interval;
191   for (const auto& session : pooled_sessions_) {
192     session->SetStunKeepaliveIntervalForReadyPorts(
193         stun_candidate_keepalive_interval_);
194   }
195 
196   // If `candidate_pool_size_` is greater than the number of pooled sessions,
197   // create new sessions.
198   while (static_cast<int>(pooled_sessions_.size()) < candidate_pool_size_) {
199     IceParameters iceCredentials =
200         IceCredentialsIterator::CreateRandomIceCredentials();
201     PortAllocatorSession* pooled_session =
202         CreateSessionInternal("", 0, iceCredentials.ufrag, iceCredentials.pwd);
203     pooled_session->set_pooled(true);
204     pooled_session->set_ice_tiebreaker(tiebreaker_);
205     pooled_session->StartGettingPorts();
206     pooled_sessions_.push_back(
207         std::unique_ptr<PortAllocatorSession>(pooled_session));
208   }
209   return true;
210 }
211 
SetIceTiebreaker(uint64_t tiebreaker)212 void PortAllocator::SetIceTiebreaker(uint64_t tiebreaker) {
213   tiebreaker_ = tiebreaker;
214   for (auto& pooled_session : pooled_sessions_) {
215     pooled_session->set_ice_tiebreaker(tiebreaker_);
216   }
217 }
218 
CreateSession(absl::string_view content_name,int component,absl::string_view ice_ufrag,absl::string_view ice_pwd)219 std::unique_ptr<PortAllocatorSession> PortAllocator::CreateSession(
220     absl::string_view content_name,
221     int component,
222     absl::string_view ice_ufrag,
223     absl::string_view ice_pwd) {
224   CheckRunOnValidThreadAndInitialized();
225   auto session = std::unique_ptr<PortAllocatorSession>(
226       CreateSessionInternal(content_name, component, ice_ufrag, ice_pwd));
227   session->SetCandidateFilter(candidate_filter());
228   session->set_ice_tiebreaker(tiebreaker_);
229   return session;
230 }
231 
TakePooledSession(absl::string_view content_name,int component,absl::string_view ice_ufrag,absl::string_view ice_pwd)232 std::unique_ptr<PortAllocatorSession> PortAllocator::TakePooledSession(
233     absl::string_view content_name,
234     int component,
235     absl::string_view ice_ufrag,
236     absl::string_view ice_pwd) {
237   CheckRunOnValidThreadAndInitialized();
238   RTC_DCHECK(!ice_ufrag.empty());
239   RTC_DCHECK(!ice_pwd.empty());
240   if (pooled_sessions_.empty()) {
241     return nullptr;
242   }
243 
244   IceParameters credentials(ice_ufrag, ice_pwd, false);
245   // If restrict_ice_credentials_change_ is TRUE, then call FindPooledSession
246   // with ice credentials. Otherwise call it with nullptr which means
247   // "find any" pooled session.
248   auto cit = FindPooledSession(restrict_ice_credentials_change_ ? &credentials
249                                                                 : nullptr);
250   if (cit == pooled_sessions_.end()) {
251     return nullptr;
252   }
253 
254   auto it =
255       pooled_sessions_.begin() + std::distance(pooled_sessions_.cbegin(), cit);
256   std::unique_ptr<PortAllocatorSession> ret = std::move(*it);
257   ret->SetIceParameters(content_name, component, ice_ufrag, ice_pwd);
258   ret->set_pooled(false);
259   // According to JSEP, a pooled session should filter candidates only
260   // after it's taken out of the pool.
261   ret->SetCandidateFilter(candidate_filter());
262   pooled_sessions_.erase(it);
263   return ret;
264 }
265 
GetPooledSession(const IceParameters * ice_credentials) const266 const PortAllocatorSession* PortAllocator::GetPooledSession(
267     const IceParameters* ice_credentials) const {
268   CheckRunOnValidThreadAndInitialized();
269   auto it = FindPooledSession(ice_credentials);
270   if (it == pooled_sessions_.end()) {
271     return nullptr;
272   } else {
273     return it->get();
274   }
275 }
276 
277 std::vector<std::unique_ptr<PortAllocatorSession>>::const_iterator
FindPooledSession(const IceParameters * ice_credentials) const278 PortAllocator::FindPooledSession(const IceParameters* ice_credentials) const {
279   for (auto it = pooled_sessions_.begin(); it != pooled_sessions_.end(); ++it) {
280     if (ice_credentials == nullptr ||
281         ((*it)->ice_ufrag() == ice_credentials->ufrag &&
282          (*it)->ice_pwd() == ice_credentials->pwd)) {
283       return it;
284     }
285   }
286   return pooled_sessions_.end();
287 }
288 
FreezeCandidatePool()289 void PortAllocator::FreezeCandidatePool() {
290   CheckRunOnValidThreadAndInitialized();
291   candidate_pool_frozen_ = true;
292 }
293 
DiscardCandidatePool()294 void PortAllocator::DiscardCandidatePool() {
295   CheckRunOnValidThreadIfInitialized();
296   pooled_sessions_.clear();
297 }
298 
SetCandidateFilter(uint32_t filter)299 void PortAllocator::SetCandidateFilter(uint32_t filter) {
300   CheckRunOnValidThreadIfInitialized();
301   if (candidate_filter_ == filter) {
302     return;
303   }
304   uint32_t prev_filter = candidate_filter_;
305   candidate_filter_ = filter;
306   SignalCandidateFilterChanged(prev_filter, filter);
307 }
308 
GetCandidateStatsFromPooledSessions(CandidateStatsList * candidate_stats_list)309 void PortAllocator::GetCandidateStatsFromPooledSessions(
310     CandidateStatsList* candidate_stats_list) {
311   CheckRunOnValidThreadAndInitialized();
312   for (const auto& session : pooled_sessions()) {
313     session->GetCandidateStatsFromReadyPorts(candidate_stats_list);
314   }
315 }
316 
GetPooledIceCredentials()317 std::vector<IceParameters> PortAllocator::GetPooledIceCredentials() {
318   CheckRunOnValidThreadAndInitialized();
319   std::vector<IceParameters> list;
320   for (const auto& session : pooled_sessions_) {
321     list.push_back(
322         IceParameters(session->ice_ufrag(), session->ice_pwd(), false));
323   }
324   return list;
325 }
326 
SanitizeCandidate(const Candidate & c) const327 Candidate PortAllocator::SanitizeCandidate(const Candidate& c) const {
328   CheckRunOnValidThreadAndInitialized();
329   // For a local host candidate, we need to conceal its IP address candidate if
330   // the mDNS obfuscation is enabled.
331   bool use_hostname_address =
332       (c.type() == LOCAL_PORT_TYPE || c.type() == PRFLX_PORT_TYPE) &&
333       MdnsObfuscationEnabled();
334   // If adapter enumeration is disabled or host candidates are disabled,
335   // clear the raddr of STUN candidates to avoid local address leakage.
336   bool filter_stun_related_address =
337       ((flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) &&
338        (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) ||
339       !(candidate_filter_ & CF_HOST) || MdnsObfuscationEnabled();
340   // If the candidate filter doesn't allow reflexive addresses, empty TURN raddr
341   // to avoid reflexive address leakage.
342   bool filter_turn_related_address = !(candidate_filter_ & CF_REFLEXIVE);
343   bool filter_related_address =
344       ((c.type() == STUN_PORT_TYPE && filter_stun_related_address) ||
345        (c.type() == RELAY_PORT_TYPE && filter_turn_related_address));
346   return c.ToSanitizedCopy(use_hostname_address, filter_related_address);
347 }
348 
349 }  // namespace cricket
350