• 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.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