blob: 301ae24003b8bf61eda8b09fdbd9d06dc99163bc [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
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
zhihuangb2cdd932017-01-19 16:54:25 -080011#include "webrtc/p2p/base/jseptransport.h"
12
jbauch555604a2016-04-26 03:13:22 -070013#include <memory>
deadbeefcbecd352015-09-23 11:50:27 -070014#include <utility> // for std::pair
15
zhihuangb2cdd932017-01-19 16:54:25 -080016#include "webrtc/base/bind.h"
17#include "webrtc/base/checks.h"
18#include "webrtc/base/logging.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000019#include "webrtc/p2p/base/candidate.h"
deadbeef49f34fd2016-12-06 16:22:06 -080020#include "webrtc/p2p/base/dtlstransportchannel.h"
kjellanderf4752772016-03-02 05:42:30 -080021#include "webrtc/p2p/base/p2pconstants.h"
deadbeef49f34fd2016-12-06 16:22:06 -080022#include "webrtc/p2p/base/p2ptransportchannel.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000023#include "webrtc/p2p/base/port.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024
25namespace cricket {
26
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000027static bool VerifyIceParams(const TransportDescription& desc) {
28 // For legacy protocols.
29 if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
30 return true;
31
32 if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH ||
33 desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) {
34 return false;
35 }
36 if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
37 desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
38 return false;
39 }
40 return true;
41}
42
hbos06495bc2017-01-02 08:08:18 -080043ConnectionInfo::ConnectionInfo()
44 : best_connection(false),
45 writable(false),
46 receiving(false),
47 timeout(false),
48 new_connection(false),
49 rtt(0),
50 sent_total_bytes(0),
51 sent_bytes_second(0),
52 sent_discarded_packets(0),
53 sent_total_packets(0),
54 sent_ping_requests_total(0),
55 sent_ping_requests_before_first_response(0),
56 sent_ping_responses(0),
57 recv_total_bytes(0),
58 recv_bytes_second(0),
59 recv_ping_requests(0),
60 recv_ping_responses(0),
61 key(nullptr),
62 state(IceCandidatePairState::WAITING),
hbos92eaec62017-02-27 01:38:08 -080063 priority(0),
hbosbf8d3e52017-02-28 06:34:47 -080064 nominated(false),
65 total_round_trip_time_ms(0) {}
hbos06495bc2017-01-02 08:08:18 -080066
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000067bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
68 if (err_desc) {
69 *err_desc = desc;
70 }
71 LOG(LS_ERROR) << desc;
72 return false;
73}
74
75bool IceCredentialsChanged(const std::string& old_ufrag,
76 const std::string& old_pwd,
77 const std::string& new_ufrag,
78 const std::string& new_pwd) {
deadbeef0ed85b22016-02-23 17:24:52 -080079 // The standard (RFC 5245 Section 9.1.1.1) says that ICE restarts MUST change
80 // both the ufrag and password. However, section 9.2.1.1 says changing the
81 // ufrag OR password indicates an ICE restart. So, to keep compatibility with
82 // endpoints that only change one, we'll treat this as an ICE restart.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000083 return (old_ufrag != new_ufrag) || (old_pwd != new_pwd);
84}
85
deadbeef49f34fd2016-12-06 16:22:06 -080086bool VerifyCandidate(const Candidate& cand, std::string* error) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000087 // No address zero.
tfarina8ac544e2015-10-08 07:15:44 -070088 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000089 *error = "candidate has address of zero";
90 return false;
91 }
92
93 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
94 int port = cand.address().port();
95 if (cand.protocol() == TCP_PROTOCOL_NAME &&
96 (cand.tcptype() == TCPTYPE_ACTIVE_STR || port == 0)) {
97 // Expected for active-only candidates per
98 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
99 // Libjingle clients emit port 0, in "active" mode.
100 return true;
101 }
102 if (port < 1024) {
103 if ((port != 80) && (port != 443)) {
104 *error = "candidate has port below 1024, but not 80 or 443";
105 return false;
106 }
107
108 if (cand.address().IsPrivateIP()) {
109 *error = "candidate has port of 80 or 443 with private IP address";
110 return false;
111 }
112 }
113
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700114 return true;
115}
116
deadbeef49f34fd2016-12-06 16:22:06 -0800117bool VerifyCandidates(const Candidates& candidates, std::string* error) {
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700118 for (const Candidate& candidate : candidates) {
119 if (!VerifyCandidate(candidate, error)) {
120 return false;
121 }
122 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000123 return true;
124}
125
deadbeef49f34fd2016-12-06 16:22:06 -0800126JsepTransport::JsepTransport(
127 const std::string& mid,
128 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate)
129 : mid_(mid), certificate_(certificate) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000130
zhihuangb2cdd932017-01-19 16:54:25 -0800131bool JsepTransport::AddChannel(DtlsTransportInternal* dtls, int component) {
deadbeef49f34fd2016-12-06 16:22:06 -0800132 if (channels_.find(component) != channels_.end()) {
133 LOG(LS_ERROR) << "Adding channel for component " << component << " twice.";
134 return false;
135 }
136 channels_[component] = dtls;
137 // Something's wrong if a channel is being added after a description is set.
138 // This may currently occur if rtcp-mux is negotiated, then a new m= section
139 // is added in a later offer/answer. But this is suboptimal and should be
140 // changed; we shouldn't support going from muxed to non-muxed.
141 // TODO(deadbeef): Once this is fixed, make the warning an error, and remove
142 // the calls to "ApplyXTransportDescription" below.
143 if (local_description_set_ || remote_description_set_) {
144 LOG(LS_WARNING) << "Adding new transport channel after "
145 "transport description already applied.";
146 }
147 bool ret = true;
148 std::string err;
149 if (local_description_set_) {
150 ret &= ApplyLocalTransportDescription(channels_[component], &err);
151 }
152 if (remote_description_set_) {
153 ret &= ApplyRemoteTransportDescription(channels_[component], &err);
154 }
155 if (local_description_set_ && remote_description_set_) {
156 ret &= ApplyNegotiatedTransportDescription(channels_[component], &err);
157 }
158 return ret;
159}
160
161bool JsepTransport::RemoveChannel(int component) {
162 auto it = channels_.find(component);
163 if (it == channels_.end()) {
164 LOG(LS_ERROR) << "Trying to remove channel for component " << component
165 << ", which doesn't exist.";
166 return false;
167 }
168 channels_.erase(component);
169 return true;
170}
171
172bool JsepTransport::HasChannels() const {
173 return !channels_.empty();
174}
175
176void JsepTransport::SetLocalCertificate(
177 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
178 certificate_ = certificate;
179}
180
181bool JsepTransport::GetLocalCertificate(
182 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const {
183 if (!certificate_) {
184 return false;
185 }
186
187 *certificate = certificate_;
188 return true;
189}
190
191bool JsepTransport::SetLocalTransportDescription(
192 const TransportDescription& description,
193 ContentAction action,
194 std::string* error_desc) {
195 bool ret = true;
196
197 if (!VerifyIceParams(description)) {
198 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
199 error_desc);
200 }
201
deadbeefd1a38b52016-12-10 13:15:33 -0800202 bool ice_restarting =
203 local_description_set_ &&
204 IceCredentialsChanged(local_description_->ice_ufrag,
205 local_description_->ice_pwd, description.ice_ufrag,
206 description.ice_pwd);
deadbeef49f34fd2016-12-06 16:22:06 -0800207 local_description_.reset(new TransportDescription(description));
208
209 rtc::SSLFingerprint* local_fp =
210 local_description_->identity_fingerprint.get();
211
212 if (!local_fp) {
213 certificate_ = nullptr;
214 } else if (!VerifyCertificateFingerprint(certificate_.get(), local_fp,
215 error_desc)) {
216 return false;
217 }
218
219 for (const auto& kv : channels_) {
220 ret &= ApplyLocalTransportDescription(kv.second, error_desc);
221 }
222 if (!ret) {
223 return false;
224 }
225
226 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
227 if (action == CA_PRANSWER || action == CA_ANSWER) {
228 ret &= NegotiateTransportDescription(action, error_desc);
229 }
deadbeefd1a38b52016-12-10 13:15:33 -0800230 if (!ret) {
231 return false;
deadbeef49f34fd2016-12-06 16:22:06 -0800232 }
233
deadbeefd1a38b52016-12-10 13:15:33 -0800234 if (needs_ice_restart_ && ice_restarting) {
235 needs_ice_restart_ = false;
236 LOG(LS_VERBOSE) << "needs-ice-restart flag cleared for transport " << mid();
237 }
238
239 local_description_set_ = true;
240 return true;
deadbeef49f34fd2016-12-06 16:22:06 -0800241}
242
243bool JsepTransport::SetRemoteTransportDescription(
244 const TransportDescription& description,
245 ContentAction action,
246 std::string* error_desc) {
247 bool ret = true;
248
249 if (!VerifyIceParams(description)) {
250 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
251 error_desc);
252 }
253
254 remote_description_.reset(new TransportDescription(description));
255 for (const auto& kv : channels_) {
256 ret &= ApplyRemoteTransportDescription(kv.second, error_desc);
257 }
258
259 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
260 if (action == CA_PRANSWER || action == CA_ANSWER) {
261 ret = NegotiateTransportDescription(CA_OFFER, error_desc);
262 }
263 if (ret) {
264 remote_description_set_ = true;
265 }
266
267 return ret;
268}
269
deadbeefd1a38b52016-12-10 13:15:33 -0800270void JsepTransport::SetNeedsIceRestartFlag() {
271 if (!needs_ice_restart_) {
272 needs_ice_restart_ = true;
273 LOG(LS_VERBOSE) << "needs-ice-restart flag set for transport " << mid();
274 }
275}
276
277bool JsepTransport::NeedsIceRestart() const {
278 return needs_ice_restart_;
279}
280
deadbeefd8cfa1a2017-03-27 10:33:26 -0700281rtc::Optional<rtc::SSLRole> JsepTransport::GetSslRole() const {
282 return ssl_role_;
deadbeef49f34fd2016-12-06 16:22:06 -0800283}
284
285bool JsepTransport::GetStats(TransportStats* stats) {
286 stats->transport_name = mid();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000287 stats->channel_stats.clear();
deadbeef49f34fd2016-12-06 16:22:06 -0800288 for (auto& kv : channels_) {
zhihuangb2cdd932017-01-19 16:54:25 -0800289 DtlsTransportInternal* dtls_transport = kv.second;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000290 TransportChannelStats substats;
deadbeef49f34fd2016-12-06 16:22:06 -0800291 substats.component = kv.first;
zhihuangb2cdd932017-01-19 16:54:25 -0800292 dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
293 dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
294 substats.dtls_state = dtls_transport->dtls_state();
295 if (!dtls_transport->ice_transport()->GetStats(
296 &substats.connection_infos)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000297 return false;
298 }
299 stats->channel_stats.push_back(substats);
300 }
301 return true;
302}
303
deadbeef49f34fd2016-12-06 16:22:06 -0800304bool JsepTransport::VerifyCertificateFingerprint(
mikescarlette7748672016-04-29 20:20:54 -0700305 const rtc::RTCCertificate* certificate,
306 const rtc::SSLFingerprint* fingerprint,
307 std::string* error_desc) const {
308 if (!fingerprint) {
309 return BadTransportDescription("No fingerprint.", error_desc);
310 }
311 if (!certificate) {
312 return BadTransportDescription(
313 "Fingerprint provided but no identity available.", error_desc);
314 }
kwibergbfefb032016-05-01 14:53:46 -0700315 std::unique_ptr<rtc::SSLFingerprint> fp_tmp(rtc::SSLFingerprint::Create(
mikescarlette7748672016-04-29 20:20:54 -0700316 fingerprint->algorithm, certificate->identity()));
nisseede5da42017-01-12 05:15:36 -0800317 RTC_DCHECK(fp_tmp.get() != NULL);
mikescarlette7748672016-04-29 20:20:54 -0700318 if (*fp_tmp == *fingerprint) {
319 return true;
320 }
321 std::ostringstream desc;
322 desc << "Local fingerprint does not match identity. Expected: ";
323 desc << fp_tmp->ToString();
324 desc << " Got: " << fingerprint->ToString();
325 return BadTransportDescription(desc.str(), error_desc);
326}
327
deadbeef49f34fd2016-12-06 16:22:06 -0800328bool JsepTransport::ApplyLocalTransportDescription(
zhihuangb2cdd932017-01-19 16:54:25 -0800329 DtlsTransportInternal* dtls_transport,
deadbeef49f34fd2016-12-06 16:22:06 -0800330 std::string* error_desc) {
zhihuangb2cdd932017-01-19 16:54:25 -0800331 dtls_transport->ice_transport()->SetIceParameters(
332 local_description_->GetIceParameters());
deadbeef8662f942017-01-20 21:20:51 -0800333 bool ret = true;
334 if (certificate_) {
335 ret = dtls_transport->SetLocalCertificate(certificate_);
336 RTC_DCHECK(ret);
337 }
338 return ret;
deadbeef49f34fd2016-12-06 16:22:06 -0800339}
340
341bool JsepTransport::ApplyRemoteTransportDescription(
zhihuangb2cdd932017-01-19 16:54:25 -0800342 DtlsTransportInternal* dtls_transport,
deadbeef49f34fd2016-12-06 16:22:06 -0800343 std::string* error_desc) {
zhihuangb2cdd932017-01-19 16:54:25 -0800344 dtls_transport->ice_transport()->SetRemoteIceParameters(
345 remote_description_->GetIceParameters());
346 dtls_transport->ice_transport()->SetRemoteIceMode(
347 remote_description_->ice_mode);
deadbeef49f34fd2016-12-06 16:22:06 -0800348 return true;
349}
350
351bool JsepTransport::ApplyNegotiatedTransportDescription(
zhihuangb2cdd932017-01-19 16:54:25 -0800352 DtlsTransportInternal* dtls_transport,
deadbeef49f34fd2016-12-06 16:22:06 -0800353 std::string* error_desc) {
354 // Set SSL role. Role must be set before fingerprint is applied, which
355 // initiates DTLS setup.
deadbeefd8cfa1a2017-03-27 10:33:26 -0700356 if (ssl_role_ && !dtls_transport->SetSslRole(*ssl_role_)) {
deadbeef49f34fd2016-12-06 16:22:06 -0800357 return BadTransportDescription("Failed to set SSL role for the channel.",
358 error_desc);
359 }
360 // Apply remote fingerprint.
zhihuangb2cdd932017-01-19 16:54:25 -0800361 if (!dtls_transport->SetRemoteFingerprint(
deadbeef49f34fd2016-12-06 16:22:06 -0800362 remote_fingerprint_->algorithm,
363 reinterpret_cast<const uint8_t*>(remote_fingerprint_->digest.data()),
364 remote_fingerprint_->digest.size())) {
365 return BadTransportDescription("Failed to apply remote fingerprint.",
366 error_desc);
367 }
368 return true;
369}
370
deadbeefd8cfa1a2017-03-27 10:33:26 -0700371bool JsepTransport::NegotiateTransportDescription(
372 ContentAction local_description_type,
373 std::string* error_desc) {
deadbeef49f34fd2016-12-06 16:22:06 -0800374 if (!local_description_ || !remote_description_) {
375 const std::string msg =
376 "Applying an answer transport description "
377 "without applying any offer.";
378 return BadTransportDescription(msg, error_desc);
379 }
380 rtc::SSLFingerprint* local_fp =
381 local_description_->identity_fingerprint.get();
382 rtc::SSLFingerprint* remote_fp =
383 remote_description_->identity_fingerprint.get();
384 if (remote_fp && local_fp) {
385 remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp));
deadbeefd8cfa1a2017-03-27 10:33:26 -0700386 if (!NegotiateRole(local_description_type, error_desc)) {
deadbeef49f34fd2016-12-06 16:22:06 -0800387 return false;
388 }
deadbeefd8cfa1a2017-03-27 10:33:26 -0700389 } else if (local_fp && (local_description_type == CA_ANSWER)) {
deadbeef49f34fd2016-12-06 16:22:06 -0800390 return BadTransportDescription(
391 "Local fingerprint supplied when caller didn't offer DTLS.",
392 error_desc);
393 } else {
394 // We are not doing DTLS
395 remote_fingerprint_.reset(new rtc::SSLFingerprint("", nullptr, 0));
396 }
397 // Now that we have negotiated everything, push it downward.
398 // Note that we cache the result so that if we have race conditions
399 // between future SetRemote/SetLocal invocations and new channel
400 // creation, we have the negotiation state saved until a new
401 // negotiation happens.
402 for (const auto& kv : channels_) {
403 if (!ApplyNegotiatedTransportDescription(kv.second, error_desc)) {
404 return false;
405 }
406 }
407 return true;
408}
409
deadbeefd8cfa1a2017-03-27 10:33:26 -0700410bool JsepTransport::NegotiateRole(ContentAction local_description_type,
411 std::string* error_desc) {
deadbeef49f34fd2016-12-06 16:22:06 -0800412 if (!local_description_ || !remote_description_) {
mikescarlette7748672016-04-29 20:20:54 -0700413 const std::string msg =
414 "Local and Remote description must be set before "
415 "transport descriptions are negotiated";
416 return BadTransportDescription(msg, error_desc);
417 }
418
419 // From RFC 4145, section-4.1, The following are the values that the
420 // 'setup' attribute can take in an offer/answer exchange:
421 // Offer Answer
422 // ________________
423 // active passive / holdconn
424 // passive active / holdconn
425 // actpass active / passive / holdconn
426 // holdconn holdconn
427 //
428 // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
429 // The endpoint MUST use the setup attribute defined in [RFC4145].
430 // The endpoint that is the offerer MUST use the setup attribute
431 // value of setup:actpass and be prepared to receive a client_hello
432 // before it receives the answer. The answerer MUST use either a
433 // setup attribute value of setup:active or setup:passive. Note that
434 // if the answerer uses setup:passive, then the DTLS handshake will
435 // not begin until the answerer is received, which adds additional
436 // latency. setup:active allows the answer and the DTLS handshake to
437 // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever
438 // party is active MUST initiate a DTLS handshake by sending a
439 // ClientHello over each flow (host/port quartet).
440 // IOW - actpass and passive modes should be treated as server and
441 // active as client.
deadbeef49f34fd2016-12-06 16:22:06 -0800442 ConnectionRole local_connection_role = local_description_->connection_role;
443 ConnectionRole remote_connection_role = remote_description_->connection_role;
mikescarlette7748672016-04-29 20:20:54 -0700444
445 bool is_remote_server = false;
deadbeefd8cfa1a2017-03-27 10:33:26 -0700446 if (local_description_type == CA_OFFER) {
mikescarlette7748672016-04-29 20:20:54 -0700447 if (local_connection_role != CONNECTIONROLE_ACTPASS) {
448 return BadTransportDescription(
449 "Offerer must use actpass value for setup attribute.", error_desc);
450 }
451
452 if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
453 remote_connection_role == CONNECTIONROLE_PASSIVE ||
454 remote_connection_role == CONNECTIONROLE_NONE) {
455 is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
456 } else {
457 const std::string msg =
458 "Answerer must use either active or passive value "
459 "for setup attribute.";
460 return BadTransportDescription(msg, error_desc);
461 }
462 // If remote is NONE or ACTIVE it will act as client.
463 } else {
464 if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
465 remote_connection_role != CONNECTIONROLE_NONE) {
deadbeefd8cfa1a2017-03-27 10:33:26 -0700466 // Accept a remote role attribute that's not "actpass", but matches the
467 // current negotiated role. This is allowed by dtls-sdp, though our
468 // implementation will never generate such an offer as it's not
469 // recommended.
470 //
471 // See https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-dtls-sdp,
472 // section 5.5.
473 if (!ssl_role_ ||
474 (*ssl_role_ == rtc::SSL_CLIENT &&
475 remote_connection_role == CONNECTIONROLE_ACTIVE) ||
476 (*ssl_role_ == rtc::SSL_SERVER &&
477 remote_connection_role == CONNECTIONROLE_PASSIVE)) {
478 return BadTransportDescription(
479 "Offerer must use actpass value or current negotiated role for "
480 "setup attribute.",
481 error_desc);
482 }
mikescarlette7748672016-04-29 20:20:54 -0700483 }
484
485 if (local_connection_role == CONNECTIONROLE_ACTIVE ||
486 local_connection_role == CONNECTIONROLE_PASSIVE) {
487 is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
488 } else {
489 const std::string msg =
490 "Answerer must use either active or passive value "
491 "for setup attribute.";
492 return BadTransportDescription(msg, error_desc);
493 }
494
495 // If local is passive, local will act as server.
496 }
497
deadbeefd8cfa1a2017-03-27 10:33:26 -0700498 ssl_role_.emplace(is_remote_server ? rtc::SSL_CLIENT : rtc::SSL_SERVER);
mikescarlette7748672016-04-29 20:20:54 -0700499 return true;
500}
501
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000502} // namespace cricket