blob: 16f5afe36ccbd93ea53dbe691771540cbbced455 [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:111/*
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
Steve Anton10542f22019-01-11 17:11:0011#include "p2p/base/port_allocator.h"
Steve Anton6c38cc72017-11-29 18:25:5812
Jonas Oreland1cd39fa2018-10-11 05:47:1213#include <iterator>
Yves Gerey3e707812018-11-28 15:47:4914#include <set>
Steve Anton6c38cc72017-11-29 18:25:5815#include <utility>
16
Ali Tofigh1b984212022-06-14 13:29:3517#include "absl/strings/string_view.h"
Steve Anton10542f22019-01-11 17:11:0018#include "p2p/base/ice_credentials_iterator.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3119#include "rtc_base/checks.h"
Yves Gerey3e707812018-11-28 15:47:4920#include "rtc_base/logging.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:1121
henrike@webrtc.org269fb4b2014-10-28 22:20:1122namespace cricket {
23
Niels Möller191e38f2019-11-04 07:49:1224RelayServerConfig::RelayServerConfig() {}
Steve Anton7995d8c2017-10-30 23:23:3825
26RelayServerConfig::RelayServerConfig(const rtc::SocketAddress& address,
Ali Tofighde2ac5a2022-06-30 09:58:2627 absl::string_view username,
28 absl::string_view password,
Steve Anton7995d8c2017-10-30 23:23:3829 ProtocolType proto)
Niels Möller191e38f2019-11-04 07:49:1230 : credentials(username, password) {
Steve Anton7995d8c2017-10-30 23:23:3831 ports.push_back(ProtocolAddress(address, proto));
32}
33
Ali Tofighde2ac5a2022-06-30 09:58:2634RelayServerConfig::RelayServerConfig(absl::string_view address,
Steve Anton7995d8c2017-10-30 23:23:3835 int port,
Ali Tofighde2ac5a2022-06-30 09:58:2636 absl::string_view username,
37 absl::string_view password,
Steve Anton7995d8c2017-10-30 23:23:3838 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.
Ali Tofighde2ac5a2022-06-30 09:58:2645RelayServerConfig::RelayServerConfig(absl::string_view address,
Steve Anton7995d8c2017-10-30 23:23:3846 int port,
Ali Tofighde2ac5a2022-06-30 09:58:2647 absl::string_view username,
48 absl::string_view password,
Steve Anton7995d8c2017-10-30 23:23:3849 ProtocolType proto,
50 bool secure)
51 : RelayServerConfig(address,
52 port,
53 username,
54 password,
55 (proto == PROTO_TCP && secure ? PROTO_TLS : proto)) {}
56
57RelayServerConfig::RelayServerConfig(const RelayServerConfig&) = default;
58
59RelayServerConfig::~RelayServerConfig() = default;
60
Ali Tofighde2ac5a2022-06-30 09:58:2661PortAllocatorSession::PortAllocatorSession(absl::string_view content_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:1162 int component,
Ali Tofighde2ac5a2022-06-30 09:58:2663 absl::string_view ice_ufrag,
64 absl::string_view ice_pwd,
Peter Boström0c4e06b2015-10-07 10:23:2165 uint32_t flags)
Taylor Brandstettera1c30352016-05-13 15:15:1166 : flags_(flags),
deadbeefc55fb302016-05-12 19:51:3867 generation_(0),
Taylor Brandstettera1c30352016-05-13 15:15:1168 content_name_(content_name),
69 component_(component),
deadbeefcbecd352015-09-23 18:50:2770 ice_ufrag_(ice_ufrag),
Philipp Hancke08b882d2022-10-27 07:56:0871 ice_pwd_(ice_pwd),
72 tiebreaker_(0) {
Taylor Brandstettera1c30352016-05-13 15:15:1173 // 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());
henrike@webrtc.org269fb4b2014-10-28 22:20:1176}
77
Steve Anton7995d8c2017-10-30 23:23:3878PortAllocatorSession::~PortAllocatorSession() = default;
79
80bool PortAllocatorSession::IsCleared() const {
81 return false;
82}
83
84bool PortAllocatorSession::IsStopped() const {
85 return false;
86}
87
88uint32_t PortAllocatorSession::generation() {
89 return generation_;
90}
91
92void PortAllocatorSession::set_generation(uint32_t generation) {
93 generation_ = generation;
94}
95
96PortAllocator::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),
Philipp Hancke08b882d2022-10-27 07:56:08103 candidate_filter_(CF_ALL),
104 tiebreaker_(0) {
Qingsi Wanga2d60672018-04-11 23:57:45105 // The allocator will be attached to a thread in Initialize.
Sebastian Janssonc01367d2019-04-08 13:20:44106 thread_checker_.Detach();
Qingsi Wanga2d60672018-04-11 23:57:45107}
Steve Anton7995d8c2017-10-30 23:23:38108
Qingsi Wanga2d60672018-04-11 23:57:45109void PortAllocator::Initialize() {
Sebastian Janssonc01367d2019-04-08 13:20:44110 RTC_DCHECK(thread_checker_.IsCurrent());
Qingsi Wanga2d60672018-04-11 23:57:45111 initialized_ = true;
112}
113
114PortAllocator::~PortAllocator() {
115 CheckRunOnValidThreadIfInitialized();
116}
Steve Anton7995d8c2017-10-30 23:23:38117
Jonas Oreland1cd39fa2018-10-11 05:47:12118void PortAllocator::set_restrict_ice_credentials_change(bool value) {
119 restrict_ice_credentials_change_ = value;
120}
121
Honghai Zhangf8998cf2019-10-14 18:27:50122// Deprecated
deadbeef6de92f92016-12-13 02:49:32123bool PortAllocator::SetConfiguration(
Taylor Brandstettera1c30352016-05-13 15:15:11124 const ServerAddresses& stun_servers,
125 const std::vector<RelayServerConfig>& turn_servers,
Honghai Zhangb9e7b4a2016-07-01 03:52:02126 int candidate_pool_size,
Jonas Orelandbdcee282017-10-10 12:01:40127 bool prune_turn_ports,
Qingsi Wangdb53f8e2018-02-20 22:45:49128 webrtc::TurnCustomizer* turn_customizer,
Danil Chapovalov00c718362018-06-15 13:58:38129 const absl::optional<int>& stun_candidate_keepalive_interval) {
Honghai Zhangf8998cf2019-10-14 18:27:50130 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
137bool 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) {
Tommiaea49c92023-10-22 11:00:14144 RTC_DCHECK_GE(candidate_pool_size, 0);
145 RTC_DCHECK_LE(candidate_pool_size, static_cast<int>(UINT16_MAX));
Qingsi Wanga2d60672018-04-11 23:57:45146 CheckRunOnValidThreadIfInitialized();
Qingsi Wange6ded162018-10-02 23:00:41147 // A positive candidate pool size would lead to the creation of a pooled
148 // allocator session and starting getting ports, which we should only do on
149 // the network thread.
Sebastian Janssonc01367d2019-04-08 13:20:44150 RTC_DCHECK(candidate_pool_size == 0 || thread_checker_.IsCurrent());
Taylor Brandstettera1c30352016-05-13 15:15:11151 bool ice_servers_changed =
152 (stun_servers != stun_servers_ || turn_servers != turn_servers_);
153 stun_servers_ = stun_servers;
154 turn_servers_ = turn_servers;
Honghai Zhangf8998cf2019-10-14 18:27:50155 turn_port_prune_policy_ = turn_port_prune_policy;
Taylor Brandstettera1c30352016-05-13 15:15:11156
deadbeef42a42632017-03-10 23:18:00157 candidate_pool_size_ = candidate_pool_size;
deadbeef6de92f92016-12-13 02:49:32158
Taylor Brandstettera1c30352016-05-13 15:15:11159 // If ICE servers changed, throw away any existing pooled sessions and create
160 // new ones.
161 if (ice_servers_changed) {
162 pooled_sessions_.clear();
Taylor Brandstettera1c30352016-05-13 15:15:11163 }
164
Jonas Orelandbdcee282017-10-10 12:01:40165 turn_customizer_ = turn_customizer;
166
Artem Titov2dbb4c92021-07-26 13:12:41167 // If `candidate_pool_size_` is less than the number of pooled sessions, get
deadbeef42a42632017-03-10 23:18:00168 // rid of the extras.
169 while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) {
Jonas Oreland1cd39fa2018-10-11 05:47:12170 pooled_sessions_.back().reset(nullptr);
171 pooled_sessions_.pop_back();
Taylor Brandstettera1c30352016-05-13 15:15:11172 }
deadbeef6de92f92016-12-13 02:49:32173
Artem Titov2dbb4c92021-07-26 13:12:41174 // `stun_candidate_keepalive_interval_` will be used in STUN port allocation
Qingsi Wangdb53f8e2018-02-20 22:45:49175 // in future sessions. We also update the ready ports in the pooled sessions.
176 // Ports in sessions that are taken and owned by P2PTransportChannel will be
177 // updated there via IceConfig.
178 stun_candidate_keepalive_interval_ = stun_candidate_keepalive_interval;
179 for (const auto& session : pooled_sessions_) {
180 session->SetStunKeepaliveIntervalForReadyPorts(
181 stun_candidate_keepalive_interval_);
182 }
183
Artem Titov2dbb4c92021-07-26 13:12:41184 // If `candidate_pool_size_` is greater than the number of pooled sessions,
deadbeef6de92f92016-12-13 02:49:32185 // create new sessions.
deadbeef42a42632017-03-10 23:18:00186 while (static_cast<int>(pooled_sessions_.size()) < candidate_pool_size_) {
Jonas Oreland1cd39fa2018-10-11 05:47:12187 IceParameters iceCredentials =
188 IceCredentialsIterator::CreateRandomIceCredentials();
189 PortAllocatorSession* pooled_session =
190 CreateSessionInternal("", 0, iceCredentials.ufrag, iceCredentials.pwd);
191 pooled_session->set_pooled(true);
Philipp Hancke08b882d2022-10-27 07:56:08192 pooled_session->set_ice_tiebreaker(tiebreaker_);
Taylor Brandstettera1c30352016-05-13 15:15:11193 pooled_session->StartGettingPorts();
194 pooled_sessions_.push_back(
195 std::unique_ptr<PortAllocatorSession>(pooled_session));
Taylor Brandstettera1c30352016-05-13 15:15:11196 }
deadbeef6de92f92016-12-13 02:49:32197 return true;
Taylor Brandstettera1c30352016-05-13 15:15:11198}
199
Philipp Hancke08b882d2022-10-27 07:56:08200void PortAllocator::SetIceTiebreaker(uint64_t tiebreaker) {
201 tiebreaker_ = tiebreaker;
202 for (auto& pooled_session : pooled_sessions_) {
203 pooled_session->set_ice_tiebreaker(tiebreaker_);
204 }
205}
206
Taylor Brandstettera1c30352016-05-13 15:15:11207std::unique_ptr<PortAllocatorSession> PortAllocator::CreateSession(
Ali Tofighde2ac5a2022-06-30 09:58:26208 absl::string_view content_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11209 int component,
Ali Tofighde2ac5a2022-06-30 09:58:26210 absl::string_view ice_ufrag,
211 absl::string_view ice_pwd) {
Qingsi Wanga2d60672018-04-11 23:57:45212 CheckRunOnValidThreadAndInitialized();
Taylor Brandstetter417eebe2016-05-23 23:02:19213 auto session = std::unique_ptr<PortAllocatorSession>(
Taylor Brandstettera1c30352016-05-13 15:15:11214 CreateSessionInternal(content_name, component, ice_ufrag, ice_pwd));
Taylor Brandstetter417eebe2016-05-23 23:02:19215 session->SetCandidateFilter(candidate_filter());
Philipp Hancke08b882d2022-10-27 07:56:08216 session->set_ice_tiebreaker(tiebreaker_);
Taylor Brandstetter417eebe2016-05-23 23:02:19217 return session;
Taylor Brandstettera1c30352016-05-13 15:15:11218}
219
220std::unique_ptr<PortAllocatorSession> PortAllocator::TakePooledSession(
Ali Tofighde2ac5a2022-06-30 09:58:26221 absl::string_view content_name,
Taylor Brandstettera1c30352016-05-13 15:15:11222 int component,
Ali Tofighde2ac5a2022-06-30 09:58:26223 absl::string_view ice_ufrag,
224 absl::string_view ice_pwd) {
Qingsi Wanga2d60672018-04-11 23:57:45225 CheckRunOnValidThreadAndInitialized();
Taylor Brandstettera1c30352016-05-13 15:15:11226 RTC_DCHECK(!ice_ufrag.empty());
227 RTC_DCHECK(!ice_pwd.empty());
228 if (pooled_sessions_.empty()) {
229 return nullptr;
230 }
Jonas Oreland1cd39fa2018-10-11 05:47:12231
232 IceParameters credentials(ice_ufrag, ice_pwd, false);
233 // If restrict_ice_credentials_change_ is TRUE, then call FindPooledSession
234 // with ice credentials. Otherwise call it with nullptr which means
235 // "find any" pooled session.
236 auto cit = FindPooledSession(restrict_ice_credentials_change_ ? &credentials
237 : nullptr);
238 if (cit == pooled_sessions_.end()) {
239 return nullptr;
240 }
241
242 auto it =
243 pooled_sessions_.begin() + std::distance(pooled_sessions_.cbegin(), cit);
244 std::unique_ptr<PortAllocatorSession> ret = std::move(*it);
Taylor Brandstettera1c30352016-05-13 15:15:11245 ret->SetIceParameters(content_name, component, ice_ufrag, ice_pwd);
Jonas Oreland1cd39fa2018-10-11 05:47:12246 ret->set_pooled(false);
247 // According to JSEP, a pooled session should filter candidates only
248 // after it's taken out of the pool.
Taylor Brandstetter417eebe2016-05-23 23:02:19249 ret->SetCandidateFilter(candidate_filter());
Jonas Oreland1cd39fa2018-10-11 05:47:12250 pooled_sessions_.erase(it);
Taylor Brandstettera1c30352016-05-13 15:15:11251 return ret;
252}
253
Jonas Oreland1cd39fa2018-10-11 05:47:12254const PortAllocatorSession* PortAllocator::GetPooledSession(
255 const IceParameters* ice_credentials) const {
Qingsi Wanga2d60672018-04-11 23:57:45256 CheckRunOnValidThreadAndInitialized();
Jonas Oreland1cd39fa2018-10-11 05:47:12257 auto it = FindPooledSession(ice_credentials);
258 if (it == pooled_sessions_.end()) {
Taylor Brandstettera1c30352016-05-13 15:15:11259 return nullptr;
Jonas Oreland1cd39fa2018-10-11 05:47:12260 } else {
261 return it->get();
Taylor Brandstettera1c30352016-05-13 15:15:11262 }
Jonas Oreland1cd39fa2018-10-11 05:47:12263}
264
265std::vector<std::unique_ptr<PortAllocatorSession>>::const_iterator
266PortAllocator::FindPooledSession(const IceParameters* ice_credentials) const {
267 for (auto it = pooled_sessions_.begin(); it != pooled_sessions_.end(); ++it) {
268 if (ice_credentials == nullptr ||
269 ((*it)->ice_ufrag() == ice_credentials->ufrag &&
270 (*it)->ice_pwd() == ice_credentials->pwd)) {
271 return it;
272 }
273 }
274 return pooled_sessions_.end();
henrike@webrtc.org269fb4b2014-10-28 22:20:11275}
276
deadbeef42a42632017-03-10 23:18:00277void PortAllocator::DiscardCandidatePool() {
Qingsi Wanga2d60672018-04-11 23:57:45278 CheckRunOnValidThreadIfInitialized();
deadbeef42a42632017-03-10 23:18:00279 pooled_sessions_.clear();
280}
281
Qingsi Wangc129c352019-04-18 17:41:58282void PortAllocator::SetCandidateFilter(uint32_t filter) {
283 CheckRunOnValidThreadIfInitialized();
284 if (candidate_filter_ == filter) {
285 return;
286 }
287 uint32_t prev_filter = candidate_filter_;
288 candidate_filter_ = filter;
289 SignalCandidateFilterChanged(prev_filter, filter);
290}
291
Qingsi Wang72a43a12018-02-21 00:03:18292void PortAllocator::GetCandidateStatsFromPooledSessions(
293 CandidateStatsList* candidate_stats_list) {
Qingsi Wanga2d60672018-04-11 23:57:45294 CheckRunOnValidThreadAndInitialized();
Qingsi Wang72a43a12018-02-21 00:03:18295 for (const auto& session : pooled_sessions()) {
296 session->GetCandidateStatsFromReadyPorts(candidate_stats_list);
297 }
298}
299
Jonas Oreland1cd39fa2018-10-11 05:47:12300std::vector<IceParameters> PortAllocator::GetPooledIceCredentials() {
301 CheckRunOnValidThreadAndInitialized();
302 std::vector<IceParameters> list;
303 for (const auto& session : pooled_sessions_) {
304 list.push_back(
305 IceParameters(session->ice_ufrag(), session->ice_pwd(), false));
306 }
307 return list;
308}
309
Qingsi Wang7627fdd2019-08-19 23:07:40310Candidate PortAllocator::SanitizeCandidate(const Candidate& c) const {
311 CheckRunOnValidThreadAndInitialized();
312 // For a local host candidate, we need to conceal its IP address candidate if
313 // the mDNS obfuscation is enabled.
314 bool use_hostname_address =
Tommi0a7fc842024-01-19 12:11:37315 (c.is_local() || c.is_prflx()) && MdnsObfuscationEnabled();
Qingsi Wang7627fdd2019-08-19 23:07:40316 // If adapter enumeration is disabled or host candidates are disabled,
317 // clear the raddr of STUN candidates to avoid local address leakage.
318 bool filter_stun_related_address =
319 ((flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) &&
320 (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) ||
321 !(candidate_filter_ & CF_HOST) || MdnsObfuscationEnabled();
322 // If the candidate filter doesn't allow reflexive addresses, empty TURN raddr
323 // to avoid reflexive address leakage.
324 bool filter_turn_related_address = !(candidate_filter_ & CF_REFLEXIVE);
Philipp Hanckea8e31112023-09-08 09:31:30325 // Sanitize related_address when using MDNS.
326 bool filter_prflx_related_address = MdnsObfuscationEnabled();
Qingsi Wang7627fdd2019-08-19 23:07:40327 bool filter_related_address =
Tommi0a7fc842024-01-19 12:11:37328 ((c.is_stun() && filter_stun_related_address) ||
329 (c.is_relay() && filter_turn_related_address) ||
330 (c.is_prflx() && filter_prflx_related_address));
Qingsi Wang7627fdd2019-08-19 23:07:40331 return c.ToSanitizedCopy(use_hostname_address, filter_related_address);
332}
333
henrike@webrtc.org269fb4b2014-10-28 22:20:11334} // namespace cricket