1 /*
2  *  Copyright 2013 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/transport_description.h"
12 
13 #include "absl/strings/ascii.h"
14 #include "absl/strings/match.h"
15 #include "p2p/base/p2p_constants.h"
16 #include "rtc_base/arraysize.h"
17 #include "rtc_base/logging.h"
18 #include "rtc_base/strings/string_builder.h"
19 
20 using webrtc::RTCError;
21 using webrtc::RTCErrorOr;
22 using webrtc::RTCErrorType;
23 
24 namespace cricket {
25 namespace {
26 
IsIceChar(char c)27 bool IsIceChar(char c) {
28   // Note: '-', '=', '#' and '_' are *not* valid ice-chars but temporarily
29   // permitted in order to allow external software to upgrade.
30   if (c == '-' || c == '=' || c == '#' || c == '_') {
31     RTC_LOG(LS_WARNING)
32         << "'-', '=', '#' and '-' are not valid ice-char and thus not "
33         << "permitted in ufrag or pwd. This is a protocol violation that "
34         << "is permitted to allow upgrading but will be rejected in "
35         << "the future. See https://crbug.com/1053756";
36     return true;
37   }
38   return absl::ascii_isalnum(c) || c == '+' || c == '/';
39 }
40 
ValidateIceUfrag(absl::string_view raw_ufrag)41 RTCError ValidateIceUfrag(absl::string_view raw_ufrag) {
42   if (!(ICE_UFRAG_MIN_LENGTH <= raw_ufrag.size() &&
43         raw_ufrag.size() <= ICE_UFRAG_MAX_LENGTH)) {
44     rtc::StringBuilder sb;
45     sb << "ICE ufrag must be between " << ICE_UFRAG_MIN_LENGTH << " and "
46        << ICE_UFRAG_MAX_LENGTH << " characters long.";
47     return RTCError(RTCErrorType::SYNTAX_ERROR, sb.Release());
48   }
49 
50   if (!absl::c_all_of(raw_ufrag, IsIceChar)) {
51     return RTCError(
52         RTCErrorType::SYNTAX_ERROR,
53         "ICE ufrag must contain only alphanumeric characters, '+', and '/'.");
54   }
55 
56   return RTCError::OK();
57 }
58 
ValidateIcePwd(absl::string_view raw_pwd)59 RTCError ValidateIcePwd(absl::string_view raw_pwd) {
60   if (!(ICE_PWD_MIN_LENGTH <= raw_pwd.size() &&
61         raw_pwd.size() <= ICE_PWD_MAX_LENGTH)) {
62     rtc::StringBuilder sb;
63     sb << "ICE pwd must be between " << ICE_PWD_MIN_LENGTH << " and "
64        << ICE_PWD_MAX_LENGTH << " characters long.";
65     return RTCError(RTCErrorType::SYNTAX_ERROR, sb.Release());
66   }
67 
68   if (!absl::c_all_of(raw_pwd, IsIceChar)) {
69     return RTCError(
70         RTCErrorType::SYNTAX_ERROR,
71         "ICE pwd must contain only alphanumeric characters, '+', and '/'.");
72   }
73 
74   return RTCError::OK();
75 }
76 
77 }  // namespace
78 
Parse(absl::string_view raw_ufrag,absl::string_view raw_pwd)79 RTCErrorOr<IceParameters> IceParameters::Parse(absl::string_view raw_ufrag,
80                                                absl::string_view raw_pwd) {
81   IceParameters parameters(std::string(raw_ufrag), std::string(raw_pwd),
82                            /* renomination= */ false);
83   auto result = parameters.Validate();
84   if (!result.ok()) {
85     return result;
86   }
87   return parameters;
88 }
89 
Validate() const90 RTCError IceParameters::Validate() const {
91   // For legacy protocols.
92   // TODO(zhihuang): Remove this once the legacy protocol is no longer
93   // supported.
94   if (ufrag.empty() && pwd.empty()) {
95     return RTCError::OK();
96   }
97 
98   auto ufrag_result = ValidateIceUfrag(ufrag);
99   if (!ufrag_result.ok()) {
100     return ufrag_result;
101   }
102 
103   auto pwd_result = ValidateIcePwd(pwd);
104   if (!pwd_result.ok()) {
105     return pwd_result;
106   }
107 
108   return RTCError::OK();
109 }
110 
StringToConnectionRole(const std::string & role_str,ConnectionRole * role)111 bool StringToConnectionRole(const std::string& role_str, ConnectionRole* role) {
112   const char* const roles[] = {
113       CONNECTIONROLE_ACTIVE_STR, CONNECTIONROLE_PASSIVE_STR,
114       CONNECTIONROLE_ACTPASS_STR, CONNECTIONROLE_HOLDCONN_STR};
115 
116   for (size_t i = 0; i < arraysize(roles); ++i) {
117     if (absl::EqualsIgnoreCase(roles[i], role_str)) {
118       *role = static_cast<ConnectionRole>(CONNECTIONROLE_ACTIVE + i);
119       return true;
120     }
121   }
122   return false;
123 }
124 
ConnectionRoleToString(const ConnectionRole & role,std::string * role_str)125 bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str) {
126   switch (role) {
127     case cricket::CONNECTIONROLE_ACTIVE:
128       *role_str = cricket::CONNECTIONROLE_ACTIVE_STR;
129       break;
130     case cricket::CONNECTIONROLE_ACTPASS:
131       *role_str = cricket::CONNECTIONROLE_ACTPASS_STR;
132       break;
133     case cricket::CONNECTIONROLE_PASSIVE:
134       *role_str = cricket::CONNECTIONROLE_PASSIVE_STR;
135       break;
136     case cricket::CONNECTIONROLE_HOLDCONN:
137       *role_str = cricket::CONNECTIONROLE_HOLDCONN_STR;
138       break;
139     default:
140       return false;
141   }
142   return true;
143 }
144 
TransportDescription()145 TransportDescription::TransportDescription()
146     : ice_mode(ICEMODE_FULL), connection_role(CONNECTIONROLE_NONE) {}
147 
TransportDescription(const std::vector<std::string> & transport_options,const std::string & ice_ufrag,const std::string & ice_pwd,IceMode ice_mode,ConnectionRole role,const rtc::SSLFingerprint * identity_fingerprint)148 TransportDescription::TransportDescription(
149     const std::vector<std::string>& transport_options,
150     const std::string& ice_ufrag,
151     const std::string& ice_pwd,
152     IceMode ice_mode,
153     ConnectionRole role,
154     const rtc::SSLFingerprint* identity_fingerprint)
155     : transport_options(transport_options),
156       ice_ufrag(ice_ufrag),
157       ice_pwd(ice_pwd),
158       ice_mode(ice_mode),
159       connection_role(role),
160       identity_fingerprint(CopyFingerprint(identity_fingerprint)) {}
161 
TransportDescription(const std::string & ice_ufrag,const std::string & ice_pwd)162 TransportDescription::TransportDescription(const std::string& ice_ufrag,
163                                            const std::string& ice_pwd)
164     : ice_ufrag(ice_ufrag),
165       ice_pwd(ice_pwd),
166       ice_mode(ICEMODE_FULL),
167       connection_role(CONNECTIONROLE_NONE) {}
168 
TransportDescription(const TransportDescription & from)169 TransportDescription::TransportDescription(const TransportDescription& from)
170     : transport_options(from.transport_options),
171       ice_ufrag(from.ice_ufrag),
172       ice_pwd(from.ice_pwd),
173       ice_mode(from.ice_mode),
174       connection_role(from.connection_role),
175       identity_fingerprint(CopyFingerprint(from.identity_fingerprint.get())) {}
176 
177 TransportDescription::~TransportDescription() = default;
178 
operator =(const TransportDescription & from)179 TransportDescription& TransportDescription::operator=(
180     const TransportDescription& from) {
181   // Self-assignment
182   if (this == &from)
183     return *this;
184 
185   transport_options = from.transport_options;
186   ice_ufrag = from.ice_ufrag;
187   ice_pwd = from.ice_pwd;
188   ice_mode = from.ice_mode;
189   connection_role = from.connection_role;
190 
191   identity_fingerprint.reset(CopyFingerprint(from.identity_fingerprint.get()));
192   return *this;
193 }
194 
195 }  // namespace cricket
196