tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

candidate.cc (10617B)


      1 /*
      2 *  Copyright 2017 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 "api/candidate.h"
     12 
     13 #include <algorithm>  // IWYU pragma: keep
     14 #include <cstdint>
     15 #include <string>
     16 
     17 #include "absl/strings/str_cat.h"
     18 #include "absl/strings/string_view.h"
     19 #include "p2p/base/p2p_constants.h"
     20 #include "rtc_base/checks.h"
     21 #include "rtc_base/crc32.h"
     22 #include "rtc_base/crypto_random.h"
     23 #include "rtc_base/ip_address.h"
     24 #include "rtc_base/network_constants.h"
     25 #include "rtc_base/socket_address.h"
     26 #include "rtc_base/strings/string_builder.h"
     27 
     28 using webrtc::IceCandidateType;
     29 
     30 namespace webrtc {
     31 absl::string_view IceCandidateTypeToString(IceCandidateType type) {
     32  switch (type) {
     33    case IceCandidateType::kHost:
     34      return "host";
     35    case IceCandidateType::kSrflx:
     36      return "srflx";
     37    case IceCandidateType::kPrflx:
     38      return "prflx";
     39    case IceCandidateType::kRelay:
     40      return "relay";
     41  }
     42 }
     43 }  // namespace webrtc
     44 
     45 namespace webrtc {
     46 
     47 Candidate::Candidate()
     48    : id_(CreateRandomString(8)),
     49      component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
     50      priority_(0),
     51      network_type_(ADAPTER_TYPE_UNKNOWN),
     52      underlying_type_for_vpn_(ADAPTER_TYPE_UNKNOWN),
     53      generation_(0),
     54      network_id_(0),
     55      network_cost_(0) {}
     56 
     57 Candidate::Candidate(int component,
     58                     absl::string_view protocol,
     59                     const SocketAddress& address,
     60                     uint32_t priority,
     61                     absl::string_view username,
     62                     absl::string_view password,
     63                     IceCandidateType type,
     64                     uint32_t generation,
     65                     absl::string_view foundation,
     66                     uint16_t network_id /*= 0*/,
     67                     uint16_t network_cost /*= 0*/)
     68    : id_(CreateRandomString(8)),
     69      component_(component),
     70      protocol_(protocol),
     71      address_(address),
     72      priority_(priority),
     73      username_(username),
     74      password_(password),
     75      type_(type),
     76      network_type_(ADAPTER_TYPE_UNKNOWN),
     77      underlying_type_for_vpn_(ADAPTER_TYPE_UNKNOWN),
     78      generation_(generation),
     79      foundation_(foundation),
     80      network_id_(network_id),
     81      network_cost_(network_cost) {}
     82 
     83 Candidate::Candidate(const Candidate&) = default;
     84 
     85 Candidate::~Candidate() = default;
     86 
     87 void Candidate::generate_id() {
     88  id_ = CreateRandomString(8);
     89 }
     90 
     91 bool Candidate::is_local() const {
     92  return type_ == IceCandidateType::kHost;
     93 }
     94 bool Candidate::is_stun() const {
     95  return type_ == IceCandidateType::kSrflx;
     96 }
     97 bool Candidate::is_prflx() const {
     98  return type_ == IceCandidateType::kPrflx;
     99 }
    100 bool Candidate::is_relay() const {
    101  return type_ == IceCandidateType::kRelay;
    102 }
    103 
    104 absl::string_view Candidate::type_name() const {
    105  return IceCandidateTypeToString(type_);
    106 }
    107 
    108 bool Candidate::IsEquivalent(const Candidate& c) const {
    109  // We ignore the network name, since that is just debug information, and
    110  // the priority and the network cost, since they should be the same if the
    111  // rest are.
    112  return (component_ == c.component_) && (protocol_ == c.protocol_) &&
    113         (address_ == c.address_) && (username_ == c.username_) &&
    114         (password_ == c.password_) && (type_ == c.type_) &&
    115         (generation_ == c.generation_) && (foundation_ == c.foundation_) &&
    116         (related_address_ == c.related_address_) &&
    117         (network_id_ == c.network_id_);
    118 }
    119 
    120 bool Candidate::MatchesForRemoval(const Candidate& c) const {
    121  return component_ == c.component_ && protocol_ == c.protocol_ &&
    122         address_ == c.address_;
    123 }
    124 
    125 std::string Candidate::ToStringInternal(bool sensitive) const {
    126  StringBuilder ost;
    127  std::string address =
    128      sensitive ? address_.ToSensitiveString() : address_.ToString();
    129  std::string related_address = sensitive ? related_address_.ToSensitiveString()
    130                                          : related_address_.ToString();
    131  ost << "Cand[:" << foundation_ << ":" << component_ << ":" << protocol_ << ":"
    132      << priority_ << ":" << address << ":" << type_name() << ":"
    133      << related_address << ":" << username_ << ":" << password_ << ":"
    134      << network_id_ << ":" << network_cost_ << ":" << generation_ << "]";
    135  return ost.Release();
    136 }
    137 
    138 uint32_t Candidate::GetPriority(uint32_t type_preference,
    139                                int network_adapter_preference,
    140                                int relay_preference,
    141                                bool adjust_local_preference) const {
    142  // RFC 5245 - 4.1.2.1.
    143  // priority = (2^24)*(type preference) +
    144  //            (2^8)*(local preference) +
    145  //            (2^0)*(256 - component ID)
    146 
    147  // `local_preference` length is 2 bytes, 0-65535 inclusive.
    148  // In our implemenation we will partion local_preference into
    149  //              0                 1
    150  //       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
    151  //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    152  //      |  NIC Pref     |    Addr Pref  |
    153  //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    154  // NIC Type - Type of the network adapter e.g. 3G/Wifi/Wired.
    155  // Addr Pref - Address preference value as per RFC 3484.
    156  // local preference =  (NIC Type << 8 | Addr_Pref) + relay preference.
    157  // The relay preference is based on the number of TURN servers, the
    158  // first TURN server gets the highest preference.
    159  int addr_pref = IPAddressPrecedence(address_.ipaddr());
    160  int local_preference =
    161      ((network_adapter_preference << 8) | addr_pref) + relay_preference;
    162 
    163  // Ensure that the added relay preference will not result in a relay candidate
    164  // whose STUN priority attribute has a higher priority than a server-reflexive
    165  // candidate.
    166  // The STUN priority attribute is calculated as
    167  // (peer-reflexive type preference) << 24 | (priority & 0x00FFFFFF)
    168  // as described in
    169  // https://www.rfc-editor.org/rfc/rfc5245#section-7.1.2.1
    170  // To satisfy that condition, add kMaxTurnServers to the local preference.
    171  // This can not overflow the field width since the highest "NIC pref"
    172  // assigned is kHighestNetworkPreference = 127
    173  RTC_DCHECK_LT(local_preference + kMaxTurnServers, 0x10000);
    174  if (adjust_local_preference && relay_protocol_.empty()) {
    175    local_preference += kMaxTurnServers;
    176  }
    177 
    178  return (type_preference << 24) | (local_preference << 8) | (256 - component_);
    179 }
    180 
    181 bool Candidate::operator==(const Candidate& o) const {
    182  return id_ == o.id_ && component_ == o.component_ &&
    183         protocol_ == o.protocol_ && relay_protocol_ == o.relay_protocol_ &&
    184         address_ == o.address_ && priority_ == o.priority_ &&
    185         username_ == o.username_ && password_ == o.password_ &&
    186         type_ == o.type_ && network_name_ == o.network_name_ &&
    187         network_type_ == o.network_type_ && generation_ == o.generation_ &&
    188         foundation_ == o.foundation_ &&
    189         related_address_ == o.related_address_ && tcptype_ == o.tcptype_ &&
    190         network_id_ == o.network_id_;
    191 }
    192 
    193 bool Candidate::operator!=(const Candidate& o) const {
    194  return !(*this == o);
    195 }
    196 
    197 Candidate Candidate::ToSanitizedCopy(bool use_hostname_address,
    198                                     bool filter_related_address) const {
    199  return ToSanitizedCopy(use_hostname_address, filter_related_address, false);
    200 }
    201 
    202 Candidate Candidate::ToSanitizedCopy(bool use_hostname_address,
    203                                     bool filter_related_address,
    204                                     bool filter_ufrag) const {
    205  Candidate copy(*this);
    206  if (use_hostname_address) {
    207    IPAddress ip;
    208    if (address().hostname().empty()) {
    209      // IP needs to be redacted, but no hostname available.
    210      SocketAddress redacted_addr("redacted-ip.invalid", address().port());
    211      copy.set_address(redacted_addr);
    212    } else if (IPFromString(address().hostname(), &ip)) {
    213      // The hostname is an IP literal, and needs to be redacted too.
    214      SocketAddress redacted_addr("redacted-literal.invalid", address().port());
    215      copy.set_address(redacted_addr);
    216    } else {
    217      SocketAddress hostname_only_addr(address().hostname(), address().port());
    218      copy.set_address(hostname_only_addr);
    219    }
    220  }
    221  if (filter_related_address) {
    222    copy.set_related_address(
    223        EmptySocketAddressWithFamily(copy.address().family()));
    224  }
    225  if (filter_ufrag) {
    226    copy.set_username("");
    227  }
    228 
    229  return copy;
    230 }
    231 
    232 void Candidate::ComputeFoundation(const SocketAddress& base_address,
    233                                  uint64_t tie_breaker) {
    234  // https://www.rfc-editor.org/rfc/rfc5245#section-4.1.1.3
    235  // The foundation is an identifier, scoped within a session.  Two candidates
    236  // MUST have the same foundation ID when all of the following are true:
    237  //
    238  // o they are of the same type.
    239  // o their bases have the same IP address (the ports can be different).
    240  // o for reflexive and relayed candidates, the STUN or TURN servers used to
    241  //   obtain them have the same IP address.
    242  // o they were obtained using the same transport protocol (TCP, UDP, etc.).
    243  //
    244  // Similarly, two candidates MUST have different foundations if their
    245  // types are different, their bases have different IP addresses, the STUN or
    246  // TURN servers used to obtain them have different IP addresses, or their
    247  // transport protocols are different.
    248 
    249  StringBuilder sb;
    250  sb << type_name() << base_address.ipaddr().ToString() << protocol_
    251     << relay_protocol_;
    252 
    253  // https://www.rfc-editor.org/rfc/rfc5245#section-5.2
    254  // [...] it is possible for both agents to mistakenly believe they are
    255  // controlled or controlling. To resolve this, each agent MUST select a random
    256  // number, called the tie-breaker, uniformly distributed between 0 and (2**64)
    257  // - 1 (that is, a 64-bit positive integer).  This number is used in
    258  // connectivity checks to detect and repair this case [...]
    259  sb << absl::StrCat(tie_breaker);
    260  foundation_ = absl::StrCat(ComputeCrc32(sb.Release()));
    261 }
    262 
    263 void Candidate::ComputePrflxFoundation() {
    264  RTC_DCHECK(is_prflx());
    265  RTC_DCHECK(!id_.empty());
    266  foundation_ = absl::StrCat(ComputeCrc32(id_));
    267 }
    268 
    269 void Candidate::Assign(std::string& s, absl::string_view view) {
    270  // Assigning via a temporary object, like s = std::string(view), results in
    271  // binary size bloat. To avoid that, extract pointer and size from the
    272  // string view, and use std::string::assign method.
    273  s.assign(view.data(), view.size());
    274 }
    275 
    276 }  // namespace webrtc