blob: 52fc8c1d396086593db28b236625cde5c5f44159 [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>
Harald Alvestrand9a953b22024-01-26 07:11:5014#include <optional>
Yves Gerey3e707812018-11-28 15:47:4915#include <set>
Steve Anton6c38cc72017-11-29 18:25:5816#include <utility>
17
Ali Tofigh1b984212022-06-14 13:29:3518#include "absl/strings/string_view.h"
Steve Anton10542f22019-01-11 17:11:0019#include "p2p/base/ice_credentials_iterator.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3120#include "rtc_base/checks.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 Hanckee3fb8122024-02-12 11:21:1671 ice_pwd_(ice_pwd) {
Taylor Brandstettera1c30352016-05-13 15:15:1172 // Pooled sessions are allowed to be created with empty content name,
73 // component, ufrag and password.
74 RTC_DCHECK(ice_ufrag.empty() == ice_pwd.empty());
henrike@webrtc.org269fb4b2014-10-28 22:20:1175}
76
Steve Anton7995d8c2017-10-30 23:23:3877PortAllocatorSession::~PortAllocatorSession() = default;
78
79bool PortAllocatorSession::IsCleared() const {
80 return false;
81}
82
83bool PortAllocatorSession::IsStopped() const {
84 return false;
85}
86
87uint32_t PortAllocatorSession::generation() {
88 return generation_;
89}
90
91void PortAllocatorSession::set_generation(uint32_t generation) {
92 generation_ = generation;
93}
94
95PortAllocator::PortAllocator()
96 : flags_(kDefaultPortAllocatorFlags),
97 min_port_(0),
98 max_port_(0),
99 max_ipv6_networks_(kDefaultMaxIPv6Networks),
100 step_delay_(kDefaultStepDelay),
101 allow_tcp_listen_(true),
Philipp Hancke08b882d2022-10-27 07:56:08102 candidate_filter_(CF_ALL),
Christoffer Dewerin7098d112024-02-26 14:38:44103 tiebreaker_(rtc::CreateRandomId64()) {
Qingsi Wanga2d60672018-04-11 23:57:45104 // The allocator will be attached to a thread in Initialize.
Sebastian Janssonc01367d2019-04-08 13:20:44105 thread_checker_.Detach();
Qingsi Wanga2d60672018-04-11 23:57:45106}
Steve Anton7995d8c2017-10-30 23:23:38107
Qingsi Wanga2d60672018-04-11 23:57:45108void PortAllocator::Initialize() {
Sebastian Janssonc01367d2019-04-08 13:20:44109 RTC_DCHECK(thread_checker_.IsCurrent());
Qingsi Wanga2d60672018-04-11 23:57:45110 initialized_ = true;
111}
112
113PortAllocator::~PortAllocator() {
114 CheckRunOnValidThreadIfInitialized();
115}
Steve Anton7995d8c2017-10-30 23:23:38116
Jonas Oreland1cd39fa2018-10-11 05:47:12117void PortAllocator::set_restrict_ice_credentials_change(bool value) {
118 restrict_ice_credentials_change_ = value;
119}
120
Honghai Zhangf8998cf2019-10-14 18:27:50121// Deprecated
deadbeef6de92f92016-12-13 02:49:32122bool PortAllocator::SetConfiguration(
Taylor Brandstettera1c30352016-05-13 15:15:11123 const ServerAddresses& stun_servers,
124 const std::vector<RelayServerConfig>& turn_servers,
Honghai Zhangb9e7b4a2016-07-01 03:52:02125 int candidate_pool_size,
Jonas Orelandbdcee282017-10-10 12:01:40126 bool prune_turn_ports,
Qingsi Wangdb53f8e2018-02-20 22:45:49127 webrtc::TurnCustomizer* turn_customizer,
Danil Chapovalov00c718362018-06-15 13:58:38128 const absl::optional<int>& stun_candidate_keepalive_interval) {
Honghai Zhangf8998cf2019-10-14 18:27:50129 webrtc::PortPrunePolicy turn_port_prune_policy =
130 prune_turn_ports ? webrtc::PRUNE_BASED_ON_PRIORITY : webrtc::NO_PRUNE;
131 return SetConfiguration(stun_servers, turn_servers, candidate_pool_size,
132 turn_port_prune_policy, turn_customizer,
133 stun_candidate_keepalive_interval);
134}
135
136bool PortAllocator::SetConfiguration(
137 const ServerAddresses& stun_servers,
138 const std::vector<RelayServerConfig>& turn_servers,
139 int candidate_pool_size,
140 webrtc::PortPrunePolicy turn_port_prune_policy,
141 webrtc::TurnCustomizer* turn_customizer,
142 const absl::optional<int>& stun_candidate_keepalive_interval) {
Tommiaea49c92023-10-22 11:00:14143 RTC_DCHECK_GE(candidate_pool_size, 0);
144 RTC_DCHECK_LE(candidate_pool_size, static_cast<int>(UINT16_MAX));
Qingsi Wanga2d60672018-04-11 23:57:45145 CheckRunOnValidThreadIfInitialized();
Qingsi Wange6ded162018-10-02 23:00:41146 // A positive candidate pool size would lead to the creation of a pooled
147 // allocator session and starting getting ports, which we should only do on
148 // the network thread.
Sebastian Janssonc01367d2019-04-08 13:20:44149 RTC_DCHECK(candidate_pool_size == 0 || thread_checker_.IsCurrent());
Taylor Brandstettera1c30352016-05-13 15:15:11150 bool ice_servers_changed =
151 (stun_servers != stun_servers_ || turn_servers != turn_servers_);
152 stun_servers_ = stun_servers;
153 turn_servers_ = turn_servers;
Honghai Zhangf8998cf2019-10-14 18:27:50154 turn_port_prune_policy_ = turn_port_prune_policy;
Taylor Brandstettera1c30352016-05-13 15:15:11155
deadbeef42a42632017-03-10 23:18:00156 candidate_pool_size_ = candidate_pool_size;
deadbeef6de92f92016-12-13 02:49:32157
Taylor Brandstettera1c30352016-05-13 15:15:11158 // If ICE servers changed, throw away any existing pooled sessions and create
159 // new ones.
160 if (ice_servers_changed) {
161 pooled_sessions_.clear();
Taylor Brandstettera1c30352016-05-13 15:15:11162 }
163
Jonas Orelandbdcee282017-10-10 12:01:40164 turn_customizer_ = turn_customizer;
165
Artem Titov2dbb4c92021-07-26 13:12:41166 // If `candidate_pool_size_` is less than the number of pooled sessions, get
deadbeef42a42632017-03-10 23:18:00167 // rid of the extras.
168 while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) {
Jonas Oreland1cd39fa2018-10-11 05:47:12169 pooled_sessions_.back().reset(nullptr);
170 pooled_sessions_.pop_back();
Taylor Brandstettera1c30352016-05-13 15:15:11171 }
deadbeef6de92f92016-12-13 02:49:32172
Artem Titov2dbb4c92021-07-26 13:12:41173 // `stun_candidate_keepalive_interval_` will be used in STUN port allocation
Qingsi Wangdb53f8e2018-02-20 22:45:49174 // in future sessions. We also update the ready ports in the pooled sessions.
175 // Ports in sessions that are taken and owned by P2PTransportChannel will be
176 // updated there via IceConfig.
177 stun_candidate_keepalive_interval_ = stun_candidate_keepalive_interval;
178 for (const auto& session : pooled_sessions_) {
179 session->SetStunKeepaliveIntervalForReadyPorts(
180 stun_candidate_keepalive_interval_);
181 }
182
Artem Titov2dbb4c92021-07-26 13:12:41183 // If `candidate_pool_size_` is greater than the number of pooled sessions,
deadbeef6de92f92016-12-13 02:49:32184 // create new sessions.
deadbeef42a42632017-03-10 23:18:00185 while (static_cast<int>(pooled_sessions_.size()) < candidate_pool_size_) {
Jonas Oreland1cd39fa2018-10-11 05:47:12186 IceParameters iceCredentials =
187 IceCredentialsIterator::CreateRandomIceCredentials();
188 PortAllocatorSession* pooled_session =
189 CreateSessionInternal("", 0, iceCredentials.ufrag, iceCredentials.pwd);
190 pooled_session->set_pooled(true);
Taylor Brandstettera1c30352016-05-13 15:15:11191 pooled_session->StartGettingPorts();
192 pooled_sessions_.push_back(
193 std::unique_ptr<PortAllocatorSession>(pooled_session));
Taylor Brandstettera1c30352016-05-13 15:15:11194 }
deadbeef6de92f92016-12-13 02:49:32195 return true;
Taylor Brandstettera1c30352016-05-13 15:15:11196}
197
198std::unique_ptr<PortAllocatorSession> PortAllocator::CreateSession(
Ali Tofighde2ac5a2022-06-30 09:58:26199 absl::string_view content_name,
henrike@webrtc.org269fb4b2014-10-28 22:20:11200 int component,
Ali Tofighde2ac5a2022-06-30 09:58:26201 absl::string_view ice_ufrag,
202 absl::string_view ice_pwd) {
Qingsi Wanga2d60672018-04-11 23:57:45203 CheckRunOnValidThreadAndInitialized();
Taylor Brandstetter417eebe2016-05-23 23:02:19204 auto session = std::unique_ptr<PortAllocatorSession>(
Taylor Brandstettera1c30352016-05-13 15:15:11205 CreateSessionInternal(content_name, component, ice_ufrag, ice_pwd));
Taylor Brandstetter417eebe2016-05-23 23:02:19206 session->SetCandidateFilter(candidate_filter());
207 return session;
Taylor Brandstettera1c30352016-05-13 15:15:11208}
209
210std::unique_ptr<PortAllocatorSession> PortAllocator::TakePooledSession(
Ali Tofighde2ac5a2022-06-30 09:58:26211 absl::string_view content_name,
Taylor Brandstettera1c30352016-05-13 15:15:11212 int component,
Ali Tofighde2ac5a2022-06-30 09:58:26213 absl::string_view ice_ufrag,
214 absl::string_view ice_pwd) {
Qingsi Wanga2d60672018-04-11 23:57:45215 CheckRunOnValidThreadAndInitialized();
Taylor Brandstettera1c30352016-05-13 15:15:11216 RTC_DCHECK(!ice_ufrag.empty());
217 RTC_DCHECK(!ice_pwd.empty());
218 if (pooled_sessions_.empty()) {
219 return nullptr;
220 }
Jonas Oreland1cd39fa2018-10-11 05:47:12221
222 IceParameters credentials(ice_ufrag, ice_pwd, false);
223 // If restrict_ice_credentials_change_ is TRUE, then call FindPooledSession
224 // with ice credentials. Otherwise call it with nullptr which means
225 // "find any" pooled session.
226 auto cit = FindPooledSession(restrict_ice_credentials_change_ ? &credentials
227 : nullptr);
228 if (cit == pooled_sessions_.end()) {
229 return nullptr;
230 }
231
232 auto it =
233 pooled_sessions_.begin() + std::distance(pooled_sessions_.cbegin(), cit);
234 std::unique_ptr<PortAllocatorSession> ret = std::move(*it);
Taylor Brandstettera1c30352016-05-13 15:15:11235 ret->SetIceParameters(content_name, component, ice_ufrag, ice_pwd);
Jonas Oreland1cd39fa2018-10-11 05:47:12236 ret->set_pooled(false);
237 // According to JSEP, a pooled session should filter candidates only
238 // after it's taken out of the pool.
Taylor Brandstetter417eebe2016-05-23 23:02:19239 ret->SetCandidateFilter(candidate_filter());
Jonas Oreland1cd39fa2018-10-11 05:47:12240 pooled_sessions_.erase(it);
Taylor Brandstettera1c30352016-05-13 15:15:11241 return ret;
242}
243
Jonas Oreland1cd39fa2018-10-11 05:47:12244const PortAllocatorSession* PortAllocator::GetPooledSession(
245 const IceParameters* ice_credentials) const {
Qingsi Wanga2d60672018-04-11 23:57:45246 CheckRunOnValidThreadAndInitialized();
Jonas Oreland1cd39fa2018-10-11 05:47:12247 auto it = FindPooledSession(ice_credentials);
248 if (it == pooled_sessions_.end()) {
Taylor Brandstettera1c30352016-05-13 15:15:11249 return nullptr;
Jonas Oreland1cd39fa2018-10-11 05:47:12250 } else {
251 return it->get();
Taylor Brandstettera1c30352016-05-13 15:15:11252 }
Jonas Oreland1cd39fa2018-10-11 05:47:12253}
254
255std::vector<std::unique_ptr<PortAllocatorSession>>::const_iterator
256PortAllocator::FindPooledSession(const IceParameters* ice_credentials) const {
257 for (auto it = pooled_sessions_.begin(); it != pooled_sessions_.end(); ++it) {
258 if (ice_credentials == nullptr ||
259 ((*it)->ice_ufrag() == ice_credentials->ufrag &&
260 (*it)->ice_pwd() == ice_credentials->pwd)) {
261 return it;
262 }
263 }
264 return pooled_sessions_.end();
henrike@webrtc.org269fb4b2014-10-28 22:20:11265}
266
deadbeef42a42632017-03-10 23:18:00267void PortAllocator::DiscardCandidatePool() {
Qingsi Wanga2d60672018-04-11 23:57:45268 CheckRunOnValidThreadIfInitialized();
deadbeef42a42632017-03-10 23:18:00269 pooled_sessions_.clear();
270}
271
Qingsi Wangc129c352019-04-18 17:41:58272void PortAllocator::SetCandidateFilter(uint32_t filter) {
273 CheckRunOnValidThreadIfInitialized();
274 if (candidate_filter_ == filter) {
275 return;
276 }
277 uint32_t prev_filter = candidate_filter_;
278 candidate_filter_ = filter;
279 SignalCandidateFilterChanged(prev_filter, filter);
280}
281
Qingsi Wang72a43a12018-02-21 00:03:18282void PortAllocator::GetCandidateStatsFromPooledSessions(
283 CandidateStatsList* candidate_stats_list) {
Qingsi Wanga2d60672018-04-11 23:57:45284 CheckRunOnValidThreadAndInitialized();
Qingsi Wang72a43a12018-02-21 00:03:18285 for (const auto& session : pooled_sessions()) {
286 session->GetCandidateStatsFromReadyPorts(candidate_stats_list);
287 }
288}
289
Jonas Oreland1cd39fa2018-10-11 05:47:12290std::vector<IceParameters> PortAllocator::GetPooledIceCredentials() {
291 CheckRunOnValidThreadAndInitialized();
292 std::vector<IceParameters> list;
293 for (const auto& session : pooled_sessions_) {
294 list.push_back(
295 IceParameters(session->ice_ufrag(), session->ice_pwd(), false));
296 }
297 return list;
298}
299
Qingsi Wang7627fdd2019-08-19 23:07:40300Candidate PortAllocator::SanitizeCandidate(const Candidate& c) const {
301 CheckRunOnValidThreadAndInitialized();
302 // For a local host candidate, we need to conceal its IP address candidate if
303 // the mDNS obfuscation is enabled.
304 bool use_hostname_address =
Tommi0a7fc842024-01-19 12:11:37305 (c.is_local() || c.is_prflx()) && MdnsObfuscationEnabled();
Qingsi Wang7627fdd2019-08-19 23:07:40306 // If adapter enumeration is disabled or host candidates are disabled,
307 // clear the raddr of STUN candidates to avoid local address leakage.
308 bool filter_stun_related_address =
309 ((flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) &&
310 (flags() & PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE)) ||
311 !(candidate_filter_ & CF_HOST) || MdnsObfuscationEnabled();
312 // If the candidate filter doesn't allow reflexive addresses, empty TURN raddr
313 // to avoid reflexive address leakage.
314 bool filter_turn_related_address = !(candidate_filter_ & CF_REFLEXIVE);
Philipp Hanckea8e31112023-09-08 09:31:30315 // Sanitize related_address when using MDNS.
316 bool filter_prflx_related_address = MdnsObfuscationEnabled();
Qingsi Wang7627fdd2019-08-19 23:07:40317 bool filter_related_address =
Tommi0a7fc842024-01-19 12:11:37318 ((c.is_stun() && filter_stun_related_address) ||
319 (c.is_relay() && filter_turn_related_address) ||
320 (c.is_prflx() && filter_prflx_related_address));
Qingsi Wang7627fdd2019-08-19 23:07:40321 return c.ToSanitizedCopy(use_hostname_address, filter_related_address);
322}
323
henrike@webrtc.org269fb4b2014-10-28 22:20:11324} // namespace cricket