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 <utility> // for std::pair 12 13 #include "webrtc/p2p/base/transport.h" 14 15 #include "webrtc/p2p/base/candidate.h" 16 #include "webrtc/p2p/base/constants.h" 17 #include "webrtc/p2p/base/port.h" 18 #include "webrtc/p2p/base/transportchannelimpl.h" 19 #include "webrtc/base/bind.h" 20 #include "webrtc/base/checks.h" 21 #include "webrtc/base/logging.h" 22 23 namespace cricket { 24 25 static bool VerifyIceParams(const TransportDescription& desc) { 26 // For legacy protocols. 27 if (desc.ice_ufrag.empty() && desc.ice_pwd.empty()) 28 return true; 29 30 if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH || 31 desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) { 32 return false; 33 } 34 if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH || 35 desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) { 36 return false; 37 } 38 return true; 39 } 40 41 bool BadTransportDescription(const std::string& desc, std::string* err_desc) { 42 if (err_desc) { 43 *err_desc = desc; 44 } 45 LOG(LS_ERROR) << desc; 46 return false; 47 } 48 49 bool IceCredentialsChanged(const std::string& old_ufrag, 50 const std::string& old_pwd, 51 const std::string& new_ufrag, 52 const std::string& new_pwd) { 53 // TODO(jiayl): The standard (RFC 5245 Section 9.1.1.1) says that ICE should 54 // restart when both the ufrag and password are changed, but we do restart 55 // when either ufrag or passwrod is changed to keep compatible with GICE. We 56 // should clean this up when GICE is no longer used. 57 return (old_ufrag != new_ufrag) || (old_pwd != new_pwd); 58 } 59 60 static bool IceCredentialsChanged(const TransportDescription& old_desc, 61 const TransportDescription& new_desc) { 62 return IceCredentialsChanged(old_desc.ice_ufrag, old_desc.ice_pwd, 63 new_desc.ice_ufrag, new_desc.ice_pwd); 64 } 65 66 Transport::Transport(const std::string& name, PortAllocator* allocator) 67 : name_(name), allocator_(allocator) {} 68 69 Transport::~Transport() { 70 RTC_DCHECK(channels_destroyed_); 71 } 72 73 void Transport::SetIceRole(IceRole role) { 74 ice_role_ = role; 75 for (const auto& kv : channels_) { 76 kv.second->SetIceRole(ice_role_); 77 } 78 } 79 80 bool Transport::GetRemoteSSLCertificate(rtc::SSLCertificate** cert) { 81 if (channels_.empty()) { 82 return false; 83 } 84 85 auto iter = channels_.begin(); 86 return iter->second->GetRemoteSSLCertificate(cert); 87 } 88 89 void Transport::SetIceConfig(const IceConfig& config) { 90 ice_config_ = config; 91 for (const auto& kv : channels_) { 92 kv.second->SetIceConfig(ice_config_); 93 } 94 } 95 96 bool Transport::SetLocalTransportDescription( 97 const TransportDescription& description, 98 ContentAction action, 99 std::string* error_desc) { 100 bool ret = true; 101 102 if (!VerifyIceParams(description)) { 103 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", 104 error_desc); 105 } 106 107 if (local_description_ && 108 IceCredentialsChanged(*local_description_, description)) { 109 IceRole new_ice_role = 110 (action == CA_OFFER) ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED; 111 112 // It must be called before ApplyLocalTransportDescription, which may 113 // trigger an ICE restart and depends on the new ICE role. 114 SetIceRole(new_ice_role); 115 } 116 117 local_description_.reset(new TransportDescription(description)); 118 119 for (const auto& kv : channels_) { 120 ret &= ApplyLocalTransportDescription(kv.second, error_desc); 121 } 122 if (!ret) { 123 return false; 124 } 125 126 // If PRANSWER/ANSWER is set, we should decide transport protocol type. 127 if (action == CA_PRANSWER || action == CA_ANSWER) { 128 ret &= NegotiateTransportDescription(action, error_desc); 129 } 130 if (ret) { 131 local_description_set_ = true; 132 ConnectChannels(); 133 } 134 135 return ret; 136 } 137 138 bool Transport::SetRemoteTransportDescription( 139 const TransportDescription& description, 140 ContentAction action, 141 std::string* error_desc) { 142 bool ret = true; 143 144 if (!VerifyIceParams(description)) { 145 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", 146 error_desc); 147 } 148 149 remote_description_.reset(new TransportDescription(description)); 150 for (const auto& kv : channels_) { 151 ret &= ApplyRemoteTransportDescription(kv.second, error_desc); 152 } 153 154 // If PRANSWER/ANSWER is set, we should decide transport protocol type. 155 if (action == CA_PRANSWER || action == CA_ANSWER) { 156 ret = NegotiateTransportDescription(CA_OFFER, error_desc); 157 } 158 if (ret) { 159 remote_description_set_ = true; 160 } 161 162 return ret; 163 } 164 165 TransportChannelImpl* Transport::CreateChannel(int component) { 166 TransportChannelImpl* channel; 167 168 // Create the entry if it does not exist. 169 bool channel_exists = false; 170 auto iter = channels_.find(component); 171 if (iter == channels_.end()) { 172 channel = CreateTransportChannel(component); 173 channels_.insert(std::pair<int, TransportChannelImpl*>(component, channel)); 174 } else { 175 channel = iter->second; 176 channel_exists = true; 177 } 178 179 channels_destroyed_ = false; 180 181 if (channel_exists) { 182 // If this is an existing channel, we should just return it. 183 return channel; 184 } 185 186 // Push down our transport state to the new channel. 187 channel->SetIceRole(ice_role_); 188 channel->SetIceTiebreaker(tiebreaker_); 189 channel->SetIceConfig(ice_config_); 190 // TODO(ronghuawu): Change CreateChannel to be able to return error since 191 // below Apply**Description calls can fail. 192 if (local_description_) 193 ApplyLocalTransportDescription(channel, nullptr); 194 if (remote_description_) 195 ApplyRemoteTransportDescription(channel, nullptr); 196 if (local_description_ && remote_description_) 197 ApplyNegotiatedTransportDescription(channel, nullptr); 198 199 if (connect_requested_) { 200 channel->Connect(); 201 } 202 return channel; 203 } 204 205 TransportChannelImpl* Transport::GetChannel(int component) { 206 auto iter = channels_.find(component); 207 return (iter != channels_.end()) ? iter->second : nullptr; 208 } 209 210 bool Transport::HasChannels() { 211 return !channels_.empty(); 212 } 213 214 void Transport::DestroyChannel(int component) { 215 auto iter = channels_.find(component); 216 if (iter == channels_.end()) 217 return; 218 219 TransportChannelImpl* channel = iter->second; 220 channels_.erase(iter); 221 DestroyTransportChannel(channel); 222 } 223 224 void Transport::ConnectChannels() { 225 if (connect_requested_ || channels_.empty()) 226 return; 227 228 connect_requested_ = true; 229 230 if (!local_description_) { 231 // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here. 232 // As Transport must know TD is offer or answer and cricket::Transport 233 // doesn't have the capability to decide it. This should be set by the 234 // Session. 235 // Session must generate local TD before remote candidates pushed when 236 // initiate request initiated by the remote. 237 LOG(LS_INFO) << "Transport::ConnectChannels: No local description has " 238 << "been set. Will generate one."; 239 TransportDescription desc( 240 std::vector<std::string>(), rtc::CreateRandomString(ICE_UFRAG_LENGTH), 241 rtc::CreateRandomString(ICE_PWD_LENGTH), ICEMODE_FULL, 242 CONNECTIONROLE_NONE, nullptr, Candidates()); 243 SetLocalTransportDescription(desc, CA_OFFER, nullptr); 244 } 245 246 CallChannels(&TransportChannelImpl::Connect); 247 } 248 249 void Transport::MaybeStartGathering() { 250 if (connect_requested_) { 251 CallChannels(&TransportChannelImpl::MaybeStartGathering); 252 } 253 } 254 255 void Transport::DestroyAllChannels() { 256 for (const auto& kv : channels_) { 257 DestroyTransportChannel(kv.second); 258 } 259 channels_.clear(); 260 channels_destroyed_ = true; 261 } 262 263 void Transport::CallChannels(TransportChannelFunc func) { 264 for (const auto& kv : channels_) { 265 (kv.second->*func)(); 266 } 267 } 268 269 bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) { 270 // No address zero. 271 if (cand.address().IsNil() || cand.address().IsAnyIP()) { 272 *error = "candidate has address of zero"; 273 return false; 274 } 275 276 // Disallow all ports below 1024, except for 80 and 443 on public addresses. 277 int port = cand.address().port(); 278 if (cand.protocol() == TCP_PROTOCOL_NAME && 279 (cand.tcptype() == TCPTYPE_ACTIVE_STR || port == 0)) { 280 // Expected for active-only candidates per 281 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error. 282 // Libjingle clients emit port 0, in "active" mode. 283 return true; 284 } 285 if (port < 1024) { 286 if ((port != 80) && (port != 443)) { 287 *error = "candidate has port below 1024, but not 80 or 443"; 288 return false; 289 } 290 291 if (cand.address().IsPrivateIP()) { 292 *error = "candidate has port of 80 or 443 with private IP address"; 293 return false; 294 } 295 } 296 297 return true; 298 } 299 300 301 bool Transport::GetStats(TransportStats* stats) { 302 stats->transport_name = name(); 303 stats->channel_stats.clear(); 304 for (auto kv : channels_) { 305 TransportChannelImpl* channel = kv.second; 306 TransportChannelStats substats; 307 substats.component = channel->component(); 308 channel->GetSrtpCryptoSuite(&substats.srtp_crypto_suite); 309 channel->GetSslCipherSuite(&substats.ssl_cipher_suite); 310 if (!channel->GetStats(&substats.connection_infos)) { 311 return false; 312 } 313 stats->channel_stats.push_back(substats); 314 } 315 return true; 316 } 317 318 bool Transport::AddRemoteCandidates(const std::vector<Candidate>& candidates, 319 std::string* error) { 320 ASSERT(!channels_destroyed_); 321 // Verify each candidate before passing down to transport layer. 322 for (const Candidate& cand : candidates) { 323 if (!VerifyCandidate(cand, error)) { 324 return false; 325 } 326 if (!HasChannel(cand.component())) { 327 *error = "Candidate has unknown component: " + cand.ToString() + 328 " for content: " + name(); 329 return false; 330 } 331 } 332 333 for (const Candidate& candidate : candidates) { 334 TransportChannelImpl* channel = GetChannel(candidate.component()); 335 if (channel != nullptr) { 336 channel->AddRemoteCandidate(candidate); 337 } 338 } 339 return true; 340 } 341 342 bool Transport::ApplyLocalTransportDescription(TransportChannelImpl* ch, 343 std::string* error_desc) { 344 ch->SetIceCredentials(local_description_->ice_ufrag, 345 local_description_->ice_pwd); 346 return true; 347 } 348 349 bool Transport::ApplyRemoteTransportDescription(TransportChannelImpl* ch, 350 std::string* error_desc) { 351 ch->SetRemoteIceCredentials(remote_description_->ice_ufrag, 352 remote_description_->ice_pwd); 353 return true; 354 } 355 356 bool Transport::ApplyNegotiatedTransportDescription( 357 TransportChannelImpl* channel, 358 std::string* error_desc) { 359 channel->SetRemoteIceMode(remote_ice_mode_); 360 return true; 361 } 362 363 bool Transport::NegotiateTransportDescription(ContentAction local_role, 364 std::string* error_desc) { 365 // TODO(ekr (at) rtfm.com): This is ICE-specific stuff. Refactor into 366 // P2PTransport. 367 368 // If transport is in ICEROLE_CONTROLLED and remote end point supports only 369 // ice_lite, this local end point should take CONTROLLING role. 370 if (ice_role_ == ICEROLE_CONTROLLED && 371 remote_description_->ice_mode == ICEMODE_LITE) { 372 SetIceRole(ICEROLE_CONTROLLING); 373 } 374 375 // Update remote ice_mode to all existing channels. 376 remote_ice_mode_ = remote_description_->ice_mode; 377 378 // Now that we have negotiated everything, push it downward. 379 // Note that we cache the result so that if we have race conditions 380 // between future SetRemote/SetLocal invocations and new channel 381 // creation, we have the negotiation state saved until a new 382 // negotiation happens. 383 for (const auto& kv : channels_) { 384 if (!ApplyNegotiatedTransportDescription(kv.second, error_desc)) { 385 return false; 386 } 387 } 388 return true; 389 } 390 391 } // namespace cricket 392