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.h"
12
13 #include <math.h>
14
15 #include <algorithm>
16 #include <memory>
17 #include <utility>
18 #include <vector>
19
20 #include "absl/algorithm/container.h"
21 #include "absl/memory/memory.h"
22 #include "absl/strings/match.h"
23 #include "absl/strings/string_view.h"
24 #include "p2p/base/connection.h"
25 #include "p2p/base/port_allocator.h"
26 #include "rtc_base/checks.h"
27 #include "rtc_base/crc32.h"
28 #include "rtc_base/helpers.h"
29 #include "rtc_base/logging.h"
30 #include "rtc_base/mdns_responder_interface.h"
31 #include "rtc_base/message_digest.h"
32 #include "rtc_base/network.h"
33 #include "rtc_base/numerics/safe_minmax.h"
34 #include "rtc_base/string_encode.h"
35 #include "rtc_base/string_utils.h"
36 #include "rtc_base/strings/string_builder.h"
37 #include "rtc_base/third_party/base64/base64.h"
38 #include "rtc_base/trace_event.h"
39
40 namespace cricket {
41 namespace {
42
43 using ::webrtc::RTCError;
44 using ::webrtc::RTCErrorType;
45 using ::webrtc::TaskQueueBase;
46 using ::webrtc::TimeDelta;
47
ConvertProtocolTypeToPacketInfoProtocolType(cricket::ProtocolType type)48 rtc::PacketInfoProtocolType ConvertProtocolTypeToPacketInfoProtocolType(
49 cricket::ProtocolType type) {
50 switch (type) {
51 case cricket::ProtocolType::PROTO_UDP:
52 return rtc::PacketInfoProtocolType::kUdp;
53 case cricket::ProtocolType::PROTO_TCP:
54 return rtc::PacketInfoProtocolType::kTcp;
55 case cricket::ProtocolType::PROTO_SSLTCP:
56 return rtc::PacketInfoProtocolType::kSsltcp;
57 case cricket::ProtocolType::PROTO_TLS:
58 return rtc::PacketInfoProtocolType::kTls;
59 default:
60 return rtc::PacketInfoProtocolType::kUnknown;
61 }
62 }
63
64 // The delay before we begin checking if this port is useless. We set
65 // it to a little higher than a total STUN timeout.
66 const int kPortTimeoutDelay = cricket::STUN_TOTAL_TIMEOUT + 5000;
67
68 } // namespace
69
70 // TODO(ronghuawu): Use "local", "srflx", "prflx" and "relay". But this requires
71 // the signaling part be updated correspondingly as well.
72 const char LOCAL_PORT_TYPE[] = "local";
73 const char STUN_PORT_TYPE[] = "stun";
74 const char PRFLX_PORT_TYPE[] = "prflx";
75 const char RELAY_PORT_TYPE[] = "relay";
76
77 static const char* const PROTO_NAMES[] = {UDP_PROTOCOL_NAME, TCP_PROTOCOL_NAME,
78 SSLTCP_PROTOCOL_NAME,
79 TLS_PROTOCOL_NAME};
80
ProtoToString(ProtocolType proto)81 const char* ProtoToString(ProtocolType proto) {
82 return PROTO_NAMES[proto];
83 }
84
StringToProto(absl::string_view proto_name)85 absl::optional<ProtocolType> StringToProto(absl::string_view proto_name) {
86 for (size_t i = 0; i <= PROTO_LAST; ++i) {
87 if (absl::EqualsIgnoreCase(PROTO_NAMES[i], proto_name)) {
88 return static_cast<ProtocolType>(i);
89 }
90 }
91 return absl::nullopt;
92 }
93
94 // RFC 6544, TCP candidate encoding rules.
95 const int DISCARD_PORT = 9;
96 const char TCPTYPE_ACTIVE_STR[] = "active";
97 const char TCPTYPE_PASSIVE_STR[] = "passive";
98 const char TCPTYPE_SIMOPEN_STR[] = "so";
99
ComputeFoundation(absl::string_view type,absl::string_view protocol,absl::string_view relay_protocol,const rtc::SocketAddress & base_address)100 std::string Port::ComputeFoundation(absl::string_view type,
101 absl::string_view protocol,
102 absl::string_view relay_protocol,
103 const rtc::SocketAddress& base_address) {
104 // TODO(bugs.webrtc.org/14605): ensure IceTiebreaker() is set.
105 rtc::StringBuilder sb;
106 sb << type << base_address.ipaddr().ToString() << protocol << relay_protocol
107 << rtc::ToString(IceTiebreaker());
108 return rtc::ToString(rtc::ComputeCrc32(sb.Release()));
109 }
110
Port(TaskQueueBase * thread,absl::string_view type,rtc::PacketSocketFactory * factory,const rtc::Network * network,absl::string_view username_fragment,absl::string_view password,const webrtc::FieldTrialsView * field_trials)111 Port::Port(TaskQueueBase* thread,
112 absl::string_view type,
113 rtc::PacketSocketFactory* factory,
114 const rtc::Network* network,
115 absl::string_view username_fragment,
116 absl::string_view password,
117 const webrtc::FieldTrialsView* field_trials)
118 : thread_(thread),
119 factory_(factory),
120 type_(type),
121 send_retransmit_count_attribute_(false),
122 network_(network),
123 min_port_(0),
124 max_port_(0),
125 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
126 generation_(0),
127 ice_username_fragment_(username_fragment),
128 password_(password),
129 timeout_delay_(kPortTimeoutDelay),
130 enable_port_packets_(false),
131 ice_role_(ICEROLE_UNKNOWN),
132 tiebreaker_(0),
133 shared_socket_(true),
134 weak_factory_(this),
135 field_trials_(field_trials) {
136 RTC_DCHECK(factory_ != NULL);
137 Construct();
138 }
139
Port(TaskQueueBase * thread,absl::string_view type,rtc::PacketSocketFactory * factory,const rtc::Network * network,uint16_t min_port,uint16_t max_port,absl::string_view username_fragment,absl::string_view password,const webrtc::FieldTrialsView * field_trials)140 Port::Port(TaskQueueBase* thread,
141 absl::string_view type,
142 rtc::PacketSocketFactory* factory,
143 const rtc::Network* network,
144 uint16_t min_port,
145 uint16_t max_port,
146 absl::string_view username_fragment,
147 absl::string_view password,
148 const webrtc::FieldTrialsView* field_trials)
149 : thread_(thread),
150 factory_(factory),
151 type_(type),
152 send_retransmit_count_attribute_(false),
153 network_(network),
154 min_port_(min_port),
155 max_port_(max_port),
156 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
157 generation_(0),
158 ice_username_fragment_(username_fragment),
159 password_(password),
160 timeout_delay_(kPortTimeoutDelay),
161 enable_port_packets_(false),
162 ice_role_(ICEROLE_UNKNOWN),
163 tiebreaker_(0),
164 shared_socket_(false),
165 weak_factory_(this),
166 field_trials_(field_trials) {
167 RTC_DCHECK(factory_ != NULL);
168 Construct();
169 }
170
Construct()171 void Port::Construct() {
172 // TODO(pthatcher): Remove this old behavior once we're sure no one
173 // relies on it. If the username_fragment and password are empty,
174 // we should just create one.
175 if (ice_username_fragment_.empty()) {
176 RTC_DCHECK(password_.empty());
177 ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
178 password_ = rtc::CreateRandomString(ICE_PWD_LENGTH);
179 }
180 network_->SignalTypeChanged.connect(this, &Port::OnNetworkTypeChanged);
181 network_cost_ = network_->GetCost(field_trials());
182
183 PostDestroyIfDead(/*delayed=*/true);
184 RTC_LOG(LS_INFO) << ToString() << ": Port created with network cost "
185 << network_cost_;
186 }
187
~Port()188 Port::~Port() {
189 RTC_DCHECK_RUN_ON(thread_);
190 CancelPendingTasks();
191 DestroyAllConnections();
192 }
193
Type() const194 const std::string& Port::Type() const {
195 return type_;
196 }
Network() const197 const rtc::Network* Port::Network() const {
198 return network_;
199 }
200
GetIceRole() const201 IceRole Port::GetIceRole() const {
202 return ice_role_;
203 }
204
SetIceRole(IceRole role)205 void Port::SetIceRole(IceRole role) {
206 ice_role_ = role;
207 }
208
SetIceTiebreaker(uint64_t tiebreaker)209 void Port::SetIceTiebreaker(uint64_t tiebreaker) {
210 tiebreaker_ = tiebreaker;
211 }
212
IceTiebreaker() const213 uint64_t Port::IceTiebreaker() const {
214 return tiebreaker_;
215 }
216
SharedSocket() const217 bool Port::SharedSocket() const {
218 return shared_socket_;
219 }
220
SetIceParameters(int component,absl::string_view username_fragment,absl::string_view password)221 void Port::SetIceParameters(int component,
222 absl::string_view username_fragment,
223 absl::string_view password) {
224 RTC_DCHECK_RUN_ON(thread_);
225 component_ = component;
226 ice_username_fragment_ = std::string(username_fragment);
227 password_ = std::string(password);
228 for (Candidate& c : candidates_) {
229 c.set_component(component);
230 c.set_username(username_fragment);
231 c.set_password(password);
232 }
233
234 // In case any connections exist make sure we update them too.
235 for (auto& [unused, connection] : connections_) {
236 connection->UpdateLocalIceParameters(component, username_fragment,
237 password);
238 }
239 }
240
Candidates() const241 const std::vector<Candidate>& Port::Candidates() const {
242 return candidates_;
243 }
244
GetConnection(const rtc::SocketAddress & remote_addr)245 Connection* Port::GetConnection(const rtc::SocketAddress& remote_addr) {
246 AddressMap::const_iterator iter = connections_.find(remote_addr);
247 if (iter != connections_.end())
248 return iter->second;
249 else
250 return NULL;
251 }
252
AddAddress(const rtc::SocketAddress & address,const rtc::SocketAddress & base_address,const rtc::SocketAddress & related_address,absl::string_view protocol,absl::string_view relay_protocol,absl::string_view tcptype,absl::string_view type,uint32_t type_preference,uint32_t relay_preference,absl::string_view url,bool is_final)253 void Port::AddAddress(const rtc::SocketAddress& address,
254 const rtc::SocketAddress& base_address,
255 const rtc::SocketAddress& related_address,
256 absl::string_view protocol,
257 absl::string_view relay_protocol,
258 absl::string_view tcptype,
259 absl::string_view type,
260 uint32_t type_preference,
261 uint32_t relay_preference,
262 absl::string_view url,
263 bool is_final) {
264 RTC_DCHECK_RUN_ON(thread_);
265 if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) {
266 RTC_DCHECK(!tcptype.empty());
267 }
268
269 std::string foundation =
270 ComputeFoundation(type, protocol, relay_protocol, base_address);
271 Candidate c(component_, protocol, address, 0U, username_fragment(), password_,
272 type, generation_, foundation, network_->id(), network_cost_);
273 c.set_priority(
274 c.GetPriority(type_preference, network_->preference(), relay_preference));
275 c.set_relay_protocol(relay_protocol);
276 c.set_tcptype(tcptype);
277 c.set_network_name(network_->name());
278 c.set_network_type(network_->type());
279 c.set_underlying_type_for_vpn(network_->underlying_type_for_vpn());
280 c.set_url(url);
281 c.set_related_address(related_address);
282
283 bool pending = MaybeObfuscateAddress(&c, type, is_final);
284
285 if (!pending) {
286 FinishAddingAddress(c, is_final);
287 }
288 }
289
MaybeObfuscateAddress(Candidate * c,absl::string_view type,bool is_final)290 bool Port::MaybeObfuscateAddress(Candidate* c,
291 absl::string_view type,
292 bool is_final) {
293 // TODO(bugs.webrtc.org/9723): Use a config to control the feature of IP
294 // handling with mDNS.
295 if (network_->GetMdnsResponder() == nullptr) {
296 return false;
297 }
298 if (type != LOCAL_PORT_TYPE) {
299 return false;
300 }
301
302 auto copy = *c;
303 auto weak_ptr = weak_factory_.GetWeakPtr();
304 auto callback = [weak_ptr, copy, is_final](const rtc::IPAddress& addr,
305 absl::string_view name) mutable {
306 RTC_DCHECK(copy.address().ipaddr() == addr);
307 rtc::SocketAddress hostname_address(name, copy.address().port());
308 // In Port and Connection, we need the IP address information to
309 // correctly handle the update of candidate type to prflx. The removal
310 // of IP address when signaling this candidate will take place in
311 // BasicPortAllocatorSession::OnCandidateReady, via SanitizeCandidate.
312 hostname_address.SetResolvedIP(addr);
313 copy.set_address(hostname_address);
314 copy.set_related_address(rtc::SocketAddress());
315 if (weak_ptr != nullptr) {
316 RTC_DCHECK_RUN_ON(weak_ptr->thread_);
317 weak_ptr->set_mdns_name_registration_status(
318 MdnsNameRegistrationStatus::kCompleted);
319 weak_ptr->FinishAddingAddress(copy, is_final);
320 }
321 };
322 set_mdns_name_registration_status(MdnsNameRegistrationStatus::kInProgress);
323 network_->GetMdnsResponder()->CreateNameForAddress(copy.address().ipaddr(),
324 callback);
325 return true;
326 }
327
FinishAddingAddress(const Candidate & c,bool is_final)328 void Port::FinishAddingAddress(const Candidate& c, bool is_final) {
329 candidates_.push_back(c);
330 SignalCandidateReady(this, c);
331
332 PostAddAddress(is_final);
333 }
334
PostAddAddress(bool is_final)335 void Port::PostAddAddress(bool is_final) {
336 if (is_final) {
337 SignalPortComplete(this);
338 }
339 }
340
AddOrReplaceConnection(Connection * conn)341 void Port::AddOrReplaceConnection(Connection* conn) {
342 auto ret = connections_.insert(
343 std::make_pair(conn->remote_candidate().address(), conn));
344 // If there is a different connection on the same remote address, replace
345 // it with the new one and destroy the old one.
346 if (ret.second == false && ret.first->second != conn) {
347 RTC_LOG(LS_WARNING)
348 << ToString()
349 << ": A new connection was created on an existing remote address. "
350 "New remote candidate: "
351 << conn->remote_candidate().ToSensitiveString();
352 std::unique_ptr<Connection> old_conn = absl::WrapUnique(ret.first->second);
353 ret.first->second = conn;
354 HandleConnectionDestroyed(old_conn.get());
355 old_conn->Shutdown();
356 }
357 }
358
OnReadPacket(const char * data,size_t size,const rtc::SocketAddress & addr,ProtocolType proto)359 void Port::OnReadPacket(const char* data,
360 size_t size,
361 const rtc::SocketAddress& addr,
362 ProtocolType proto) {
363 // If the user has enabled port packets, just hand this over.
364 if (enable_port_packets_) {
365 SignalReadPacket(this, data, size, addr);
366 return;
367 }
368
369 // If this is an authenticated STUN request, then signal unknown address and
370 // send back a proper binding response.
371 std::unique_ptr<IceMessage> msg;
372 std::string remote_username;
373 if (!GetStunMessage(data, size, addr, &msg, &remote_username)) {
374 RTC_LOG(LS_ERROR) << ToString()
375 << ": Received non-STUN packet from unknown address: "
376 << addr.ToSensitiveString();
377 } else if (!msg) {
378 // STUN message handled already
379 } else if (msg->type() == STUN_BINDING_REQUEST) {
380 RTC_LOG(LS_INFO) << "Received " << StunMethodToString(msg->type())
381 << " id=" << rtc::hex_encode(msg->transaction_id())
382 << " from unknown address " << addr.ToSensitiveString();
383 // We need to signal an unknown address before we handle any role conflict
384 // below. Otherwise there would be no candidate pair and TURN entry created
385 // to send the error response in case of a role conflict.
386 SignalUnknownAddress(this, addr, proto, msg.get(), remote_username, false);
387 // Check for role conflicts.
388 if (!MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
389 RTC_LOG(LS_INFO) << "Received conflicting role from the peer.";
390 return;
391 }
392 } else if (msg->type() == GOOG_PING_REQUEST) {
393 // This is a PING sent to a connection that was destroyed.
394 // Send back that this is the case and a authenticated BINDING
395 // is needed.
396 SendBindingErrorResponse(msg.get(), addr, STUN_ERROR_BAD_REQUEST,
397 STUN_ERROR_REASON_BAD_REQUEST);
398 } else {
399 // NOTE(tschmelcher): STUN_BINDING_RESPONSE is benign. It occurs if we
400 // pruned a connection for this port while it had STUN requests in flight,
401 // because we then get back responses for them, which this code correctly
402 // does not handle.
403 if (msg->type() != STUN_BINDING_RESPONSE &&
404 msg->type() != GOOG_PING_RESPONSE &&
405 msg->type() != GOOG_PING_ERROR_RESPONSE) {
406 RTC_LOG(LS_ERROR) << ToString()
407 << ": Received unexpected STUN message type: "
408 << msg->type() << " from unknown address: "
409 << addr.ToSensitiveString();
410 }
411 }
412 }
413
OnReadyToSend()414 void Port::OnReadyToSend() {
415 AddressMap::iterator iter = connections_.begin();
416 for (; iter != connections_.end(); ++iter) {
417 iter->second->OnReadyToSend();
418 }
419 }
420
AddPrflxCandidate(const Candidate & local)421 void Port::AddPrflxCandidate(const Candidate& local) {
422 RTC_DCHECK_RUN_ON(thread_);
423 candidates_.push_back(local);
424 }
425
GetStunMessage(const char * data,size_t size,const rtc::SocketAddress & addr,std::unique_ptr<IceMessage> * out_msg,std::string * out_username)426 bool Port::GetStunMessage(const char* data,
427 size_t size,
428 const rtc::SocketAddress& addr,
429 std::unique_ptr<IceMessage>* out_msg,
430 std::string* out_username) {
431 // NOTE: This could clearly be optimized to avoid allocating any memory.
432 // However, at the data rates we'll be looking at on the client side,
433 // this probably isn't worth worrying about.
434 RTC_DCHECK(out_msg != NULL);
435 RTC_DCHECK(out_username != NULL);
436 out_username->clear();
437
438 // Don't bother parsing the packet if we can tell it's not STUN.
439 // In ICE mode, all STUN packets will have a valid fingerprint.
440 // Except GOOG_PING_REQUEST/RESPONSE that does not send fingerprint.
441 int types[] = {GOOG_PING_REQUEST, GOOG_PING_RESPONSE,
442 GOOG_PING_ERROR_RESPONSE};
443 if (!StunMessage::IsStunMethod(types, data, size) &&
444 !StunMessage::ValidateFingerprint(data, size)) {
445 return false;
446 }
447
448 // Parse the request message. If the packet is not a complete and correct
449 // STUN message, then ignore it.
450 std::unique_ptr<IceMessage> stun_msg(new IceMessage());
451 rtc::ByteBufferReader buf(data, size);
452 if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
453 return false;
454 }
455
456 // Get list of attributes in the "comprehension-required" range that were not
457 // comprehended. If one or more is found, the behavior differs based on the
458 // type of the incoming message; see below.
459 std::vector<uint16_t> unknown_attributes =
460 stun_msg->GetNonComprehendedAttributes();
461
462 if (stun_msg->type() == STUN_BINDING_REQUEST) {
463 // Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first.
464 // If not present, fail with a 400 Bad Request.
465 if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) ||
466 !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
467 RTC_LOG(LS_ERROR) << ToString() << ": Received "
468 << StunMethodToString(stun_msg->type())
469 << " without username/M-I from: "
470 << addr.ToSensitiveString();
471 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
472 STUN_ERROR_REASON_BAD_REQUEST);
473 return true;
474 }
475
476 // If the username is bad or unknown, fail with a 401 Unauthorized.
477 std::string local_ufrag;
478 std::string remote_ufrag;
479 if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag) ||
480 local_ufrag != username_fragment()) {
481 RTC_LOG(LS_ERROR) << ToString() << ": Received "
482 << StunMethodToString(stun_msg->type())
483 << " with bad local username " << local_ufrag
484 << " from " << addr.ToSensitiveString();
485 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
486 STUN_ERROR_REASON_UNAUTHORIZED);
487 return true;
488 }
489
490 // If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
491 if (stun_msg->ValidateMessageIntegrity(password_) !=
492 StunMessage::IntegrityStatus::kIntegrityOk) {
493 RTC_LOG(LS_ERROR) << ToString() << ": Received "
494 << StunMethodToString(stun_msg->type())
495 << " with bad M-I from " << addr.ToSensitiveString()
496 << ", password_=" << password_;
497 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
498 STUN_ERROR_REASON_UNAUTHORIZED);
499 return true;
500 }
501
502 // If a request contains unknown comprehension-required attributes, reply
503 // with an error. See RFC5389 section 7.3.1.
504 if (!unknown_attributes.empty()) {
505 SendUnknownAttributesErrorResponse(stun_msg.get(), addr,
506 unknown_attributes);
507 return true;
508 }
509
510 out_username->assign(remote_ufrag);
511 } else if ((stun_msg->type() == STUN_BINDING_RESPONSE) ||
512 (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
513 if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
514 if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
515 RTC_LOG(LS_ERROR) << ToString() << ": Received "
516 << StunMethodToString(stun_msg->type())
517 << ": class=" << error_code->eclass()
518 << " number=" << error_code->number() << " reason='"
519 << error_code->reason() << "' from "
520 << addr.ToSensitiveString();
521 // Return message to allow error-specific processing
522 } else {
523 RTC_LOG(LS_ERROR) << ToString() << ": Received "
524 << StunMethodToString(stun_msg->type())
525 << " without a error code from "
526 << addr.ToSensitiveString();
527 return true;
528 }
529 }
530 // If a response contains unknown comprehension-required attributes, it's
531 // simply discarded and the transaction is considered failed. See RFC5389
532 // sections 7.3.3 and 7.3.4.
533 if (!unknown_attributes.empty()) {
534 RTC_LOG(LS_ERROR) << ToString()
535 << ": Discarding STUN response due to unknown "
536 "comprehension-required attribute";
537 return true;
538 }
539 // NOTE: Username should not be used in verifying response messages.
540 out_username->clear();
541 } else if (stun_msg->type() == STUN_BINDING_INDICATION) {
542 RTC_LOG(LS_VERBOSE) << ToString() << ": Received "
543 << StunMethodToString(stun_msg->type()) << ": from "
544 << addr.ToSensitiveString();
545 out_username->clear();
546
547 // If an indication contains unknown comprehension-required attributes,[]
548 // it's simply discarded. See RFC5389 section 7.3.2.
549 if (!unknown_attributes.empty()) {
550 RTC_LOG(LS_ERROR) << ToString()
551 << ": Discarding STUN indication due to "
552 "unknown comprehension-required attribute";
553 return true;
554 }
555 // No stun attributes will be verified, if it's stun indication message.
556 // Returning from end of the this method.
557 } else if (stun_msg->type() == GOOG_PING_REQUEST) {
558 if (stun_msg->ValidateMessageIntegrity(password_) !=
559 StunMessage::IntegrityStatus::kIntegrityOk) {
560 RTC_LOG(LS_ERROR) << ToString() << ": Received "
561 << StunMethodToString(stun_msg->type())
562 << " with bad M-I from " << addr.ToSensitiveString()
563 << ", password_=" << password_;
564 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
565 STUN_ERROR_REASON_UNAUTHORIZED);
566 return true;
567 }
568 RTC_LOG(LS_VERBOSE) << ToString() << ": Received "
569 << StunMethodToString(stun_msg->type()) << " from "
570 << addr.ToSensitiveString();
571 out_username->clear();
572 } else if (stun_msg->type() == GOOG_PING_RESPONSE ||
573 stun_msg->type() == GOOG_PING_ERROR_RESPONSE) {
574 // note: the MessageIntegrity32 will be verified in Connection.cc
575 RTC_LOG(LS_VERBOSE) << ToString() << ": Received "
576 << StunMethodToString(stun_msg->type()) << " from "
577 << addr.ToSensitiveString();
578 out_username->clear();
579 } else {
580 RTC_LOG(LS_ERROR) << ToString()
581 << ": Received STUN packet with invalid type ("
582 << stun_msg->type() << ") from "
583 << addr.ToSensitiveString();
584 return true;
585 }
586
587 // Return the STUN message found.
588 *out_msg = std::move(stun_msg);
589 return true;
590 }
591
IsCompatibleAddress(const rtc::SocketAddress & addr)592 bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) {
593 // Get a representative IP for the Network this port is configured to use.
594 rtc::IPAddress ip = network_->GetBestIP();
595 // We use single-stack sockets, so families must match.
596 if (addr.family() != ip.family()) {
597 return false;
598 }
599 // Link-local IPv6 ports can only connect to other link-local IPv6 ports.
600 if (ip.family() == AF_INET6 &&
601 (IPIsLinkLocal(ip) != IPIsLinkLocal(addr.ipaddr()))) {
602 return false;
603 }
604 return true;
605 }
606
StunDscpValue() const607 rtc::DiffServCodePoint Port::StunDscpValue() const {
608 // By default, inherit from whatever the MediaChannel sends.
609 return rtc::DSCP_NO_CHANGE;
610 }
611
DestroyAllConnections()612 void Port::DestroyAllConnections() {
613 RTC_DCHECK_RUN_ON(thread_);
614 for (auto& [unused, connection] : connections_) {
615 connection->Shutdown();
616 delete connection;
617 }
618 connections_.clear();
619 }
620
set_timeout_delay(int delay)621 void Port::set_timeout_delay(int delay) {
622 RTC_DCHECK_RUN_ON(thread_);
623 // Although this method is meant to only be used by tests, some downstream
624 // projects have started using it. Ideally we should update our tests to not
625 // require to modify this state and instead use a testing harness that allows
626 // adjusting the clock and then just use the kPortTimeoutDelay constant
627 // directly.
628 timeout_delay_ = delay;
629 }
630
ParseStunUsername(const StunMessage * stun_msg,std::string * local_ufrag,std::string * remote_ufrag) const631 bool Port::ParseStunUsername(const StunMessage* stun_msg,
632 std::string* local_ufrag,
633 std::string* remote_ufrag) const {
634 // The packet must include a username that either begins or ends with our
635 // fragment. It should begin with our fragment if it is a request and it
636 // should end with our fragment if it is a response.
637 local_ufrag->clear();
638 remote_ufrag->clear();
639 const StunByteStringAttribute* username_attr =
640 stun_msg->GetByteString(STUN_ATTR_USERNAME);
641 if (username_attr == NULL)
642 return false;
643
644 // RFRAG:LFRAG
645 const absl::string_view username = username_attr->string_view();
646 size_t colon_pos = username.find(':');
647 if (colon_pos == absl::string_view::npos) {
648 return false;
649 }
650
651 *local_ufrag = std::string(username.substr(0, colon_pos));
652 *remote_ufrag = std::string(username.substr(colon_pos + 1, username.size()));
653 return true;
654 }
655
MaybeIceRoleConflict(const rtc::SocketAddress & addr,IceMessage * stun_msg,absl::string_view remote_ufrag)656 bool Port::MaybeIceRoleConflict(const rtc::SocketAddress& addr,
657 IceMessage* stun_msg,
658 absl::string_view remote_ufrag) {
659 // Validate ICE_CONTROLLING or ICE_CONTROLLED attributes.
660 bool ret = true;
661 IceRole remote_ice_role = ICEROLE_UNKNOWN;
662 uint64_t remote_tiebreaker = 0;
663 const StunUInt64Attribute* stun_attr =
664 stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
665 if (stun_attr) {
666 remote_ice_role = ICEROLE_CONTROLLING;
667 remote_tiebreaker = stun_attr->value();
668 }
669
670 // If `remote_ufrag` is same as port local username fragment and
671 // tie breaker value received in the ping message matches port
672 // tiebreaker value this must be a loopback call.
673 // We will treat this as valid scenario.
674 if (remote_ice_role == ICEROLE_CONTROLLING &&
675 username_fragment() == remote_ufrag &&
676 remote_tiebreaker == IceTiebreaker()) {
677 return true;
678 }
679
680 stun_attr = stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED);
681 if (stun_attr) {
682 remote_ice_role = ICEROLE_CONTROLLED;
683 remote_tiebreaker = stun_attr->value();
684 }
685
686 switch (ice_role_) {
687 case ICEROLE_CONTROLLING:
688 if (ICEROLE_CONTROLLING == remote_ice_role) {
689 if (remote_tiebreaker >= tiebreaker_) {
690 SignalRoleConflict(this);
691 } else {
692 // Send Role Conflict (487) error response.
693 SendBindingErrorResponse(stun_msg, addr, STUN_ERROR_ROLE_CONFLICT,
694 STUN_ERROR_REASON_ROLE_CONFLICT);
695 ret = false;
696 }
697 }
698 break;
699 case ICEROLE_CONTROLLED:
700 if (ICEROLE_CONTROLLED == remote_ice_role) {
701 if (remote_tiebreaker < tiebreaker_) {
702 SignalRoleConflict(this);
703 } else {
704 // Send Role Conflict (487) error response.
705 SendBindingErrorResponse(stun_msg, addr, STUN_ERROR_ROLE_CONFLICT,
706 STUN_ERROR_REASON_ROLE_CONFLICT);
707 ret = false;
708 }
709 }
710 break;
711 default:
712 RTC_DCHECK_NOTREACHED();
713 }
714 return ret;
715 }
716
CreateStunUsername(absl::string_view remote_username) const717 std::string Port::CreateStunUsername(absl::string_view remote_username) const {
718 return std::string(remote_username) + ":" + username_fragment();
719 }
720
HandleIncomingPacket(rtc::AsyncPacketSocket * socket,const char * data,size_t size,const rtc::SocketAddress & remote_addr,int64_t packet_time_us)721 bool Port::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,
722 const char* data,
723 size_t size,
724 const rtc::SocketAddress& remote_addr,
725 int64_t packet_time_us) {
726 RTC_DCHECK_NOTREACHED();
727 return false;
728 }
729
CanHandleIncomingPacketsFrom(const rtc::SocketAddress &) const730 bool Port::CanHandleIncomingPacketsFrom(const rtc::SocketAddress&) const {
731 return false;
732 }
733
SendBindingErrorResponse(StunMessage * message,const rtc::SocketAddress & addr,int error_code,absl::string_view reason)734 void Port::SendBindingErrorResponse(StunMessage* message,
735 const rtc::SocketAddress& addr,
736 int error_code,
737 absl::string_view reason) {
738 RTC_DCHECK(message->type() == STUN_BINDING_REQUEST ||
739 message->type() == GOOG_PING_REQUEST);
740
741 // Fill in the response message.
742 StunMessage response(message->type() == STUN_BINDING_REQUEST
743 ? STUN_BINDING_ERROR_RESPONSE
744 : GOOG_PING_ERROR_RESPONSE,
745 message->transaction_id());
746
747 // When doing GICE, we need to write out the error code incorrectly to
748 // maintain backwards compatiblility.
749 auto error_attr = StunAttribute::CreateErrorCode();
750 error_attr->SetCode(error_code);
751 error_attr->SetReason(std::string(reason));
752 response.AddAttribute(std::move(error_attr));
753
754 // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
755 // because we don't have enough information to determine the shared secret.
756 if (error_code != STUN_ERROR_BAD_REQUEST &&
757 error_code != STUN_ERROR_UNAUTHORIZED &&
758 message->type() != GOOG_PING_REQUEST) {
759 if (message->type() == STUN_BINDING_REQUEST) {
760 response.AddMessageIntegrity(password_);
761 } else {
762 response.AddMessageIntegrity32(password_);
763 }
764 }
765
766 if (message->type() == STUN_BINDING_REQUEST) {
767 response.AddFingerprint();
768 }
769
770 // Send the response message.
771 rtc::ByteBufferWriter buf;
772 response.Write(&buf);
773 rtc::PacketOptions options(StunDscpValue());
774 options.info_signaled_after_sent.packet_type =
775 rtc::PacketType::kIceConnectivityCheckResponse;
776 SendTo(buf.Data(), buf.Length(), addr, options, false);
777 RTC_LOG(LS_INFO) << ToString() << ": Sending STUN "
778 << StunMethodToString(response.type())
779 << ": reason=" << reason << " to "
780 << addr.ToSensitiveString();
781 }
782
SendUnknownAttributesErrorResponse(StunMessage * message,const rtc::SocketAddress & addr,const std::vector<uint16_t> & unknown_types)783 void Port::SendUnknownAttributesErrorResponse(
784 StunMessage* message,
785 const rtc::SocketAddress& addr,
786 const std::vector<uint16_t>& unknown_types) {
787 RTC_DCHECK(message->type() == STUN_BINDING_REQUEST);
788
789 // Fill in the response message.
790 StunMessage response(STUN_BINDING_ERROR_RESPONSE, message->transaction_id());
791
792 auto error_attr = StunAttribute::CreateErrorCode();
793 error_attr->SetCode(STUN_ERROR_UNKNOWN_ATTRIBUTE);
794 error_attr->SetReason(STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE);
795 response.AddAttribute(std::move(error_attr));
796
797 std::unique_ptr<StunUInt16ListAttribute> unknown_attr =
798 StunAttribute::CreateUnknownAttributes();
799 for (uint16_t type : unknown_types) {
800 unknown_attr->AddType(type);
801 }
802 response.AddAttribute(std::move(unknown_attr));
803
804 response.AddMessageIntegrity(password_);
805 response.AddFingerprint();
806
807 // Send the response message.
808 rtc::ByteBufferWriter buf;
809 response.Write(&buf);
810 rtc::PacketOptions options(StunDscpValue());
811 options.info_signaled_after_sent.packet_type =
812 rtc::PacketType::kIceConnectivityCheckResponse;
813 SendTo(buf.Data(), buf.Length(), addr, options, false);
814 RTC_LOG(LS_ERROR) << ToString() << ": Sending STUN binding error: reason="
815 << STUN_ERROR_UNKNOWN_ATTRIBUTE << " to "
816 << addr.ToSensitiveString();
817 }
818
KeepAliveUntilPruned()819 void Port::KeepAliveUntilPruned() {
820 // If it is pruned, we won't bring it up again.
821 if (state_ == State::INIT) {
822 state_ = State::KEEP_ALIVE_UNTIL_PRUNED;
823 }
824 }
825
Prune()826 void Port::Prune() {
827 state_ = State::PRUNED;
828 PostDestroyIfDead(/*delayed=*/false);
829 }
830
831 // Call to stop any currently pending operations from running.
CancelPendingTasks()832 void Port::CancelPendingTasks() {
833 TRACE_EVENT0("webrtc", "Port::CancelPendingTasks");
834 RTC_DCHECK_RUN_ON(thread_);
835 weak_factory_.InvalidateWeakPtrs();
836 }
837
PostDestroyIfDead(bool delayed)838 void Port::PostDestroyIfDead(bool delayed) {
839 rtc::WeakPtr<Port> weak_ptr = NewWeakPtr();
840 auto task = [weak_ptr = std::move(weak_ptr)] {
841 if (weak_ptr) {
842 weak_ptr->DestroyIfDead();
843 }
844 };
845 if (delayed) {
846 thread_->PostDelayedTask(std::move(task),
847 TimeDelta::Millis(timeout_delay_));
848 } else {
849 thread_->PostTask(std::move(task));
850 }
851 }
852
DestroyIfDead()853 void Port::DestroyIfDead() {
854 RTC_DCHECK_RUN_ON(thread_);
855 bool dead =
856 (state_ == State::INIT || state_ == State::PRUNED) &&
857 connections_.empty() &&
858 rtc::TimeMillis() - last_time_all_connections_removed_ >= timeout_delay_;
859 if (dead) {
860 Destroy();
861 }
862 }
863
SubscribePortDestroyed(std::function<void (PortInterface *)> callback)864 void Port::SubscribePortDestroyed(
865 std::function<void(PortInterface*)> callback) {
866 port_destroyed_callback_list_.AddReceiver(callback);
867 }
868
SendPortDestroyed(Port * port)869 void Port::SendPortDestroyed(Port* port) {
870 port_destroyed_callback_list_.Send(port);
871 }
OnNetworkTypeChanged(const rtc::Network * network)872 void Port::OnNetworkTypeChanged(const rtc::Network* network) {
873 RTC_DCHECK(network == network_);
874
875 UpdateNetworkCost();
876 }
877
ToString() const878 std::string Port::ToString() const {
879 rtc::StringBuilder ss;
880 ss << "Port[" << rtc::ToHex(reinterpret_cast<uintptr_t>(this)) << ":"
881 << content_name_ << ":" << component_ << ":" << generation_ << ":" << type_
882 << ":" << network_->ToString() << "]";
883 return ss.Release();
884 }
885
886 // TODO(honghaiz): Make the network cost configurable from user setting.
UpdateNetworkCost()887 void Port::UpdateNetworkCost() {
888 RTC_DCHECK_RUN_ON(thread_);
889 uint16_t new_cost = network_->GetCost(field_trials());
890 if (network_cost_ == new_cost) {
891 return;
892 }
893 RTC_LOG(LS_INFO) << "Network cost changed from " << network_cost_ << " to "
894 << new_cost
895 << ". Number of candidates created: " << candidates_.size()
896 << ". Number of connections created: "
897 << connections_.size();
898 network_cost_ = new_cost;
899 for (cricket::Candidate& candidate : candidates_)
900 candidate.set_network_cost(network_cost_);
901
902 for (auto& [unused, connection] : connections_)
903 connection->SetLocalCandidateNetworkCost(network_cost_);
904 }
905
EnablePortPackets()906 void Port::EnablePortPackets() {
907 enable_port_packets_ = true;
908 }
909
OnConnectionDestroyed(Connection * conn)910 bool Port::OnConnectionDestroyed(Connection* conn) {
911 if (connections_.erase(conn->remote_candidate().address()) == 0) {
912 // This could indicate a programmer error outside of webrtc so while we
913 // do have this check here to alert external developers, we also need to
914 // handle it since it might be a corner case not caught in tests.
915 RTC_DCHECK_NOTREACHED() << "Calling Destroy recursively?";
916 return false;
917 }
918
919 HandleConnectionDestroyed(conn);
920
921 // Ports time out after all connections fail if it is not marked as
922 // "keep alive until pruned."
923 // Note: If a new connection is added after this message is posted, but it
924 // fails and is removed before kPortTimeoutDelay, then this message will
925 // not cause the Port to be destroyed.
926 if (connections_.empty()) {
927 last_time_all_connections_removed_ = rtc::TimeMillis();
928 PostDestroyIfDead(/*delayed=*/true);
929 }
930
931 return true;
932 }
933
DestroyConnectionInternal(Connection * conn,bool async)934 void Port::DestroyConnectionInternal(Connection* conn, bool async) {
935 RTC_DCHECK_RUN_ON(thread_);
936 if (!OnConnectionDestroyed(conn))
937 return;
938
939 conn->Shutdown();
940 if (async) {
941 // Unwind the stack before deleting the object in case upstream callers
942 // need to refer to the Connection's state as part of teardown.
943 // NOTE: We move ownership of `conn` into the capture section of the lambda
944 // so that the object will always be deleted, including if PostTask fails.
945 // In such a case (only tests), deletion would happen inside of the call
946 // to `DestroyConnection()`.
947 thread_->PostTask([conn = absl::WrapUnique(conn)]() {});
948 } else {
949 delete conn;
950 }
951 }
952
Destroy()953 void Port::Destroy() {
954 RTC_DCHECK(connections_.empty());
955 RTC_LOG(LS_INFO) << ToString() << ": Port deleted";
956 SendPortDestroyed(this);
957 delete this;
958 }
959
username_fragment() const960 const std::string Port::username_fragment() const {
961 return ice_username_fragment_;
962 }
963
CopyPortInformationToPacketInfo(rtc::PacketInfo * info) const964 void Port::CopyPortInformationToPacketInfo(rtc::PacketInfo* info) const {
965 info->protocol = ConvertProtocolTypeToPacketInfoProtocolType(GetProtocol());
966 info->network_id = Network()->id();
967 }
968
969 } // namespace cricket
970