blob: 0bd2d24fa51e566240bd730f0968dad492a42116 [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
Patrik Höglund56d94522019-11-18 15:53:32 +010011#include "api/transport/stun.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000012
13#include <string.h>
Tommi408143d2022-06-01 15:29:31 +020014
Yves Gerey665174f2018-06-19 15:03:05 +020015#include <algorithm>
Harald Alvestrandbee64082020-11-12 11:17:41 +000016#include <cstdint>
17#include <iterator>
kwiberg3ec46792016-04-27 07:22:53 -070018#include <memory>
Steve Anton6c38cc72017-11-29 10:25:58 -080019#include <utility>
kwiberg3ec46792016-04-27 07:22:53 -070020
Steve Anton10542f22019-01-11 09:11:00 -080021#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/checks.h"
23#include "rtc_base/crc32.h"
Tommi408143d2022-06-01 15:29:31 +020024#include "rtc_base/helpers.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/message_digest.h"
Harald Alvestrand38b3b5e2022-10-10 04:36:12 +000027#include "system_wrappers/include/metrics.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000028
jbauchf1f87202016-03-30 06:43:37 -070029using rtc::ByteBufferReader;
30using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000031
Harald Alvestrandbee64082020-11-12 11:17:41 +000032namespace cricket {
33
Zach Stein92c42892018-11-28 11:38:52 -080034namespace {
35
Harald Alvestrandbee64082020-11-12 11:17:41 +000036const int k127Utf8CharactersLengthInBytes = 508;
Harald Alvestrandbee64082020-11-12 11:17:41 +000037const int kMessageIntegrityAttributeLength = 20;
Harald Alvestrand837f13c2020-12-04 07:52:22 +000038const int kTheoreticalMaximumAttributeLength = 65535;
Harald Alvestrandbee64082020-11-12 11:17:41 +000039
Tommi408143d2022-06-01 15:29:31 +020040uint32_t ReduceTransactionId(absl::string_view transaction_id) {
Zach Stein92c42892018-11-28 11:38:52 -080041 RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
Tommi408143d2022-06-01 15:29:31 +020042 transaction_id.length() == cricket::kStunLegacyTransactionIdLength)
43 << transaction_id.length();
44 ByteBufferReader reader(transaction_id.data(), transaction_id.size());
Zach Stein92c42892018-11-28 11:38:52 -080045 uint32_t result = 0;
Zach Steinff71a492018-12-07 11:25:12 -080046 uint32_t next;
47 while (reader.ReadUInt32(&next)) {
48 result ^= next;
Zach Stein92c42892018-11-28 11:38:52 -080049 }
50 return result;
51}
52
Harald Alvestrandbee64082020-11-12 11:17:41 +000053// Check the maximum length of a BYTE_STRING attribute against specifications.
54bool LengthValid(int type, int length) {
55 // "Less than 509 bytes" is intended to indicate a maximum of 127
56 // UTF-8 characters, which may take up to 4 bytes per character.
57 switch (type) {
58 case STUN_ATTR_USERNAME:
59 return length <=
60 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.3
61 case STUN_ATTR_MESSAGE_INTEGRITY:
62 return length ==
63 kMessageIntegrityAttributeLength; // RFC 8489 section 14.5
64 case STUN_ATTR_REALM:
65 return length <=
66 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.9
67 case STUN_ATTR_NONCE:
68 return length <=
69 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.10
70 case STUN_ATTR_SOFTWARE:
71 return length <=
72 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.14
Harald Alvestrandbee64082020-11-12 11:17:41 +000073 case STUN_ATTR_DATA:
74 // No length restriction in RFC; it's the content of an UDP datagram,
75 // which in theory can be up to 65.535 bytes.
76 // TODO(bugs.webrtc.org/12179): Write a test to find the real limit.
Harald Alvestrand837f13c2020-12-04 07:52:22 +000077 return length <= kTheoreticalMaximumAttributeLength;
Harald Alvestrandbee64082020-11-12 11:17:41 +000078 default:
79 // Return an arbitrary restriction for all other types.
Harald Alvestrand837f13c2020-12-04 07:52:22 +000080 return length <= kTheoreticalMaximumAttributeLength;
Harald Alvestrandbee64082020-11-12 11:17:41 +000081 }
Artem Titovd3251962021-11-15 16:57:07 +010082 RTC_DCHECK_NOTREACHED();
Harald Alvestrandbee64082020-11-12 11:17:41 +000083 return true;
84}
Zach Stein92c42892018-11-28 11:38:52 -080085
Harald Alvestrandbee64082020-11-12 11:17:41 +000086} // namespace
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000087
88const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
89const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
90const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -070091const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[] = "Unknown Attribute";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000092const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000093const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
94const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
95const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
96const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
97const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
98const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
99
Yves Gerey665174f2018-06-19 15:03:05 +0200100const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000101const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200102const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
Eldar Relloda13ea22019-06-01 12:23:43 +0300103const int SERVER_NOT_REACHABLE_ERROR = 701;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000104
105// StunMessage
106
107StunMessage::StunMessage()
Tommi408143d2022-06-01 15:29:31 +0200108 : StunMessage(STUN_INVALID_MESSAGE_TYPE, EMPTY_TRANSACTION_ID) {}
109
110StunMessage::StunMessage(uint16_t type)
111 : StunMessage(type, GenerateTransactionId()) {}
112
113StunMessage::StunMessage(uint16_t type, absl::string_view transaction_id)
114 : type_(type),
115 transaction_id_(transaction_id),
116 reduced_transaction_id_(ReduceTransactionId(transaction_id_)) {
nisseede5da42017-01-12 05:15:36 -0800117 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000118}
119
Steve Antonca7d54e2017-10-25 14:42:51 -0700120StunMessage::~StunMessage() = default;
121
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000122bool StunMessage::IsLegacy() const {
123 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
124 return true;
nisseede5da42017-01-12 05:15:36 -0800125 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000126 return false;
127}
128
Jonas Oreland16ccef72018-03-27 09:02:43 +0200129static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200130 return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
131 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200132}
133
zsteinf42cc9d2017-03-27 16:17:19 -0700134void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200135 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +0200136 // but allow any type for the range that in the RFC is reserved for
137 // the "designated experts".
138 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200139 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
140 }
nissecc99bc22017-02-02 01:31:30 -0800141
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000142 attr->SetOwner(this);
143 size_t attr_length = attr->length();
144 if (attr_length % 4 != 0) {
145 attr_length += (4 - (attr_length % 4));
146 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200147 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -0700148
149 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000150}
151
Jonas Oreland202994c2017-12-18 12:10:43 +0100152std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
153 std::unique_ptr<StunAttribute> attribute;
154 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
Yves Gerey665174f2018-06-19 15:03:05 +0200155 if ((*it)->type() == type) {
156 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100157 attrs_.erase(std::next(it).base());
158 break;
159 }
160 }
161 if (attribute) {
162 attribute->SetOwner(nullptr);
163 size_t attr_length = attribute->length();
164 if (attr_length % 4 != 0) {
165 attr_length += (4 - (attr_length % 4));
166 }
167 length_ -= static_cast<uint16_t>(attr_length + 4);
168 }
169 return attribute;
170}
171
Jonas Oreland63737a92019-11-21 15:12:14 +0100172void StunMessage::ClearAttributes() {
173 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
174 (*it)->SetOwner(nullptr);
175 }
176 attrs_.clear();
177 length_ = 0;
178}
179
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700180std::vector<uint16_t> StunMessage::GetNonComprehendedAttributes() const {
181 std::vector<uint16_t> unknown_attributes;
182 for (auto& attr : attrs_) {
183 // "comprehension-required" range is 0x0000-0x7FFF.
184 if (attr->type() >= 0x0000 && attr->type() <= 0x7FFF &&
185 GetAttributeValueType(attr->type()) == STUN_VALUE_UNKNOWN) {
186 unknown_attributes.push_back(attr->type());
187 }
188 }
189 return unknown_attributes;
190}
191
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000192const StunAddressAttribute* StunMessage::GetAddress(int type) const {
193 switch (type) {
194 case STUN_ATTR_MAPPED_ADDRESS: {
195 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
196 // missing.
197 const StunAttribute* mapped_address =
198 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
199 if (!mapped_address)
200 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
201 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
202 }
203
204 default:
205 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
206 }
207}
208
209const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
210 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
211}
212
213const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
214 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
215}
216
217const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
218 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
219}
220
Jonas Oreland1721de12019-11-20 12:10:39 +0100221const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
222 return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
223}
224
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000225const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
226 return static_cast<const StunErrorCodeAttribute*>(
227 GetAttribute(STUN_ATTR_ERROR_CODE));
228}
229
deadbeef996fc6b2017-04-26 09:21:22 -0700230int StunMessage::GetErrorCodeValue() const {
231 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
232 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
233}
234
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000235const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
236 return static_cast<const StunUInt16ListAttribute*>(
237 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
238}
239
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000240StunMessage::IntegrityStatus StunMessage::ValidateMessageIntegrity(
241 const std::string& password) {
242 password_ = password;
243 if (GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
244 if (ValidateMessageIntegrityOfType(
245 STUN_ATTR_MESSAGE_INTEGRITY, kStunMessageIntegritySize,
246 buffer_.c_str(), buffer_.size(), password)) {
247 integrity_ = IntegrityStatus::kIntegrityOk;
248 } else {
249 integrity_ = IntegrityStatus::kIntegrityBad;
250 }
251 } else if (GetByteString(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32)) {
252 if (ValidateMessageIntegrityOfType(
253 STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32, kStunMessageIntegrity32Size,
254 buffer_.c_str(), buffer_.size(), password)) {
255 integrity_ = IntegrityStatus::kIntegrityOk;
256 } else {
257 integrity_ = IntegrityStatus::kIntegrityBad;
258 }
259 } else {
260 integrity_ = IntegrityStatus::kNoIntegrity;
261 }
Harald Alvestrand38b3b5e2022-10-10 04:36:12 +0000262 // Log the result of integrity checking. See crbug.com/1177125 for background.
263 // Convert args to integer for the benefit of the macros.
264 int bucket_count = static_cast<int>(IntegrityStatus::kMaxValue) + 1;
265 int integrity = static_cast<int>(integrity_);
266 if (IsStunRequestType(type_)) {
267 RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Request", integrity,
268 bucket_count);
269 } else if (IsStunSuccessResponseType(type_)) {
270 RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Response", integrity,
271 bucket_count);
272 } else if (IsStunIndicationType(type_)) {
273 RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Indication", integrity,
274 bucket_count);
275 } else {
276 RTC_DCHECK(IsStunErrorResponseType(type_));
277 auto* error_attribute = GetErrorCode();
278 if (!error_attribute) {
279 RTC_HISTOGRAM_ENUMERATION(
280 "WebRTC.Stun.Integrity.ErrorResponse.NoErrorAttribute", integrity,
281 bucket_count);
282 } else {
283 switch (error_attribute->code()) {
284 case STUN_ERROR_TRY_ALTERNATE:
285 RTC_HISTOGRAM_ENUMERATION(
286 "WebRTC.Stun.Integrity.ErrorResponse.TryAlternate", integrity,
287 bucket_count);
288 break;
289 case STUN_ERROR_BAD_REQUEST:
290 RTC_HISTOGRAM_ENUMERATION(
291 "WebRTC.Stun.Integrity.ErrorResponse.BadRequest", integrity,
292 bucket_count);
293 break;
294 case STUN_ERROR_UNAUTHORIZED:
295 RTC_HISTOGRAM_ENUMERATION(
296 "WebRTC.Stun.Integrity.ErrorResponse.Unauthorized", integrity,
297 bucket_count);
298 break;
299 case STUN_ERROR_UNKNOWN_ATTRIBUTE:
300 RTC_HISTOGRAM_ENUMERATION(
301 "WebRTC.Stun.Integrity.ErrorResponse.UnknownAttribute", integrity,
302 bucket_count);
303 break;
304 case STUN_ERROR_STALE_NONCE:
305 RTC_HISTOGRAM_ENUMERATION(
306 "WebRTC.Stun.Integrity.ErrorResponse.StaleNonce", integrity,
307 bucket_count);
308 break;
309 case STUN_ERROR_SERVER_ERROR:
310 RTC_HISTOGRAM_ENUMERATION(
311 "WebRTC.Stun.Integrity.ErrorResponse.ServerError", integrity,
312 bucket_count);
313 break;
314 case STUN_ERROR_GLOBAL_FAILURE:
315 RTC_HISTOGRAM_ENUMERATION(
316 "WebRTC.Stun.Integrity.ErrorResponse.GlobalFailure", integrity,
317 bucket_count);
318 break;
319 default:
320 RTC_HISTOGRAM_ENUMERATION(
321 "WebRTC.Stun.Integrity.ErrorResponse.ErrorOther", integrity,
322 bucket_count);
323 break;
324 }
325 }
326 }
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000327 return integrity_;
328}
329
Harald Alvestrand4b255b12022-10-10 10:22:39 +0000330bool StunMessage::ValidateMessageIntegrityForTesting(
331 const char* data,
332 size_t size,
333 const std::string& password) {
334 return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
335 kStunMessageIntegritySize, data, size,
336 password);
337}
338
339bool StunMessage::ValidateMessageIntegrity32ForTesting(
340 const char* data,
341 size_t size,
342 const std::string& password) {
343 return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
344 kStunMessageIntegrity32Size, data, size,
345 password);
346}
347
348// Deprecated
Yves Gerey665174f2018-06-19 15:03:05 +0200349bool StunMessage::ValidateMessageIntegrity(const char* data,
350 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100352 return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
353 kStunMessageIntegritySize, data, size,
354 password);
355}
356
Harald Alvestrand4b255b12022-10-10 10:22:39 +0000357// Deprecated
Jonas Oreland63737a92019-11-21 15:12:14 +0100358bool StunMessage::ValidateMessageIntegrity32(const char* data,
359 size_t size,
360 const std::string& password) {
361 return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
362 kStunMessageIntegrity32Size, data, size,
363 password);
364}
365
366// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
367// procedure outlined in RFC 5389, section 15.4.
368bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
369 size_t mi_attr_size,
370 const char* data,
371 size_t size,
372 const std::string& password) {
373 RTC_DCHECK(mi_attr_size <= kStunMessageIntegritySize);
374
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000375 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700376 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000377 return false;
378 }
379
380 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200381 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000382 if (size != (msg_length + kStunHeaderSize)) {
383 return false;
384 }
385
386 // Finding Message Integrity attribute in stun message.
387 size_t current_pos = kStunHeaderSize;
388 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700389 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200390 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000391 // Getting attribute type and length.
392 attr_type = rtc::GetBE16(&data[current_pos]);
393 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
394
395 // If M-I, sanity check it, and break out.
Jonas Oreland63737a92019-11-21 15:12:14 +0100396 if (attr_type == mi_attr_type) {
397 if (attr_length != mi_attr_size ||
katrielc1a206102016-06-20 05:13:16 -0700398 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
399 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000400 return false;
401 }
402 has_message_integrity_attr = true;
403 break;
404 }
405
406 // Otherwise, skip to the next attribute.
407 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
408 if ((attr_length % 4) != 0) {
409 current_pos += (4 - (attr_length % 4));
410 }
411 }
412
413 if (!has_message_integrity_attr) {
414 return false;
415 }
416
417 // Getting length of the message to calculate Message Integrity.
418 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700419 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000420 memcpy(temp_data.get(), data, current_pos);
Jonas Oreland63737a92019-11-21 15:12:14 +0100421 if (size > mi_pos + kStunAttributeHeaderSize + mi_attr_size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000422 // Stun message has other attributes after message integrity.
423 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200424 size_t extra_offset =
Jonas Oreland63737a92019-11-21 15:12:14 +0100425 size - (mi_pos + kStunAttributeHeaderSize + mi_attr_size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000426 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
427
428 // Writing new length of the STUN message @ Message Length in temp buffer.
429 // 0 1 2 3
430 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
431 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
432 // |0 0| STUN Message Type | Message Length |
433 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200434 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000435 }
436
437 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200438 size_t ret =
439 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
440 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800441 RTC_DCHECK(ret == sizeof(hmac));
Jonas Oreland63737a92019-11-21 15:12:14 +0100442 if (ret != sizeof(hmac)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000443 return false;
Jonas Oreland63737a92019-11-21 15:12:14 +0100444 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000445
446 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200447 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
Jonas Oreland63737a92019-11-21 15:12:14 +0100448 mi_attr_size) == 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000449}
450
Tommie83500e2022-06-03 14:28:59 +0200451bool StunMessage::AddMessageIntegrity(absl::string_view password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100452 return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
Tommie83500e2022-06-03 14:28:59 +0200453 kStunMessageIntegritySize, password);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000454}
455
Jonas Oreland63737a92019-11-21 15:12:14 +0100456bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
457 return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
Tommie83500e2022-06-03 14:28:59 +0200458 kStunMessageIntegrity32Size, password);
Jonas Oreland63737a92019-11-21 15:12:14 +0100459}
460
461bool StunMessage::AddMessageIntegrityOfType(int attr_type,
462 size_t attr_size,
Tommie83500e2022-06-03 14:28:59 +0200463 absl::string_view key) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000464 // Add the attribute with a dummy value. Since this is a known attribute, it
465 // can't fail.
Jonas Oreland63737a92019-11-21 15:12:14 +0100466 RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200467 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
Jonas Oreland63737a92019-11-21 15:12:14 +0100468 attr_type, std::string(attr_size, '0'));
zsteinf42cc9d2017-03-27 16:17:19 -0700469 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
470 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000471
472 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700473 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000474 if (!Write(&buf))
475 return false;
476
477 int msg_len_for_hmac = static_cast<int>(
478 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
479 char hmac[kStunMessageIntegritySize];
Tommie83500e2022-06-03 14:28:59 +0200480 size_t ret =
481 rtc::ComputeHmac(rtc::DIGEST_SHA_1, key.data(), key.size(), buf.Data(),
482 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800483 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000484 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100485 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200486 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000487 return false;
488 }
489
490 // Insert correct HMAC into the attribute.
Jonas Oreland63737a92019-11-21 15:12:14 +0100491 msg_integrity_attr->CopyBytes(hmac, attr_size);
Tommie83500e2022-06-03 14:28:59 +0200492 password_ = std::string(key);
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000493 integrity_ = IntegrityStatus::kIntegrityOk;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000494 return true;
495}
496
497// Verifies a message is in fact a STUN message, by performing the checks
498// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
499// in section 15.5.
500bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
501 // Check the message length.
502 size_t fingerprint_attr_size =
503 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
504 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
505 return false;
506
507 // Skip the rest if the magic cookie isn't present.
508 const char* magic_cookie =
509 data + kStunTransactionIdOffset - kStunMagicCookieLength;
510 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
511 return false;
512
513 // Check the fingerprint type and length.
514 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
515 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200516 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000517 StunUInt32Attribute::SIZE)
518 return false;
519
520 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200521 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000522 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
523 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200524 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000525}
526
Tommi408143d2022-06-01 15:29:31 +0200527// static
528std::string StunMessage::GenerateTransactionId() {
529 return rtc::CreateRandomString(kStunTransactionIdLength);
530}
531
Jonas Oreland253d50f2019-11-28 17:08:07 +0100532bool StunMessage::IsStunMethod(rtc::ArrayView<int> methods,
533 const char* data,
534 size_t size) {
535 // Check the message length.
536 if (size % 4 != 0 || size < kStunHeaderSize)
537 return false;
538
539 // Skip the rest if the magic cookie isn't present.
540 const char* magic_cookie =
541 data + kStunTransactionIdOffset - kStunMagicCookieLength;
542 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
543 return false;
544
545 int method = rtc::GetBE16(data);
546 for (int m : methods) {
547 if (m == method) {
548 return true;
549 }
550 }
551 return false;
552}
553
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000554bool StunMessage::AddFingerprint() {
555 // Add the attribute with a dummy value. Since this is a known attribute,
556 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700557 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200558 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700559 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700560 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000561
562 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700563 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564 if (!Write(&buf))
565 return false;
566
567 int msg_len_for_crc32 = static_cast<int>(
568 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200569 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000570
571 // Insert the correct CRC-32, XORed with a constant, into the attribute.
572 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
573 return true;
574}
575
jbauchf1f87202016-03-30 06:43:37 -0700576bool StunMessage::Read(ByteBufferReader* buf) {
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000577 // Keep a copy of the buffer data around for later verification.
578 buffer_.assign(buf->Data(), buf->Length());
579
Jonas Oreland1721de12019-11-20 12:10:39 +0100580 if (!buf->ReadUInt16(&type_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000581 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100582 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000583
584 if (type_ & 0x8000) {
585 // RTP and RTCP set the MSB of first byte, since first two bits are version,
586 // and version is always 2 (10). If set, this is not a STUN packet.
587 return false;
588 }
589
Jonas Oreland1721de12019-11-20 12:10:39 +0100590 if (!buf->ReadUInt16(&length_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000591 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100592 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000593
594 std::string magic_cookie;
Jonas Oreland1721de12019-11-20 12:10:39 +0100595 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000596 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100597 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000598
599 std::string transaction_id;
Jonas Oreland1721de12019-11-20 12:10:39 +0100600 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000601 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100602 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000603
Andrew Royes154d8392019-03-14 10:38:31 -0700604 uint32_t magic_cookie_int;
605 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
606 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
607 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000608 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
609 // If magic cookie is invalid it means that the peer implements
610 // RFC3489 instead of RFC5389.
611 transaction_id.insert(0, magic_cookie);
612 }
nisseede5da42017-01-12 05:15:36 -0800613 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000614 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800615 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000616
Jonas Oreland1721de12019-11-20 12:10:39 +0100617 if (length_ != buf->Length()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000618 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100619 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000620
zsteinad94c4c2017-03-06 13:36:05 -0800621 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000622
623 size_t rest = buf->Length() - length_;
624 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200625 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000626 if (!buf->ReadUInt16(&attr_type))
627 return false;
628 if (!buf->ReadUInt16(&attr_length))
629 return false;
630
Honghai Zhang3e024302016-09-22 09:52:16 -0700631 std::unique_ptr<StunAttribute> attr(
632 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000633 if (!attr) {
634 // Skip any unknown or malformed attributes.
635 if ((attr_length % 4) != 0) {
636 attr_length += (4 - (attr_length % 4));
637 }
Jonas Oreland1721de12019-11-20 12:10:39 +0100638 if (!buf->Consume(attr_length)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000639 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100640 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000641 } else {
Jonas Oreland1721de12019-11-20 12:10:39 +0100642 if (!attr->Read(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000643 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100644 }
zsteinad94c4c2017-03-06 13:36:05 -0800645 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000646 }
647 }
648
nisseede5da42017-01-12 05:15:36 -0800649 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000650 return true;
651}
652
jbauchf1f87202016-03-30 06:43:37 -0700653bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000654 buf->WriteUInt16(type_);
655 buf->WriteUInt16(length_);
656 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100657 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000658 buf->WriteString(transaction_id_);
659
zsteinad94c4c2017-03-06 13:36:05 -0800660 for (const auto& attr : attrs_) {
661 buf->WriteUInt16(attr->type());
662 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
663 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000664 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800665 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000666 }
667
668 return true;
669}
670
Steve Antonca7d54e2017-10-25 14:42:51 -0700671StunMessage* StunMessage::CreateNew() const {
672 return new StunMessage();
673}
674
Jonas Oreland7ca63112018-02-27 08:45:13 +0100675void StunMessage::SetStunMagicCookie(uint32_t val) {
676 stun_magic_cookie_ = val;
677}
678
Tommi408143d2022-06-01 15:29:31 +0200679void StunMessage::SetTransactionIdForTesting(absl::string_view transaction_id) {
680 RTC_DCHECK(IsValidTransactionId(transaction_id));
681 transaction_id_ = std::string(transaction_id);
682 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
683}
684
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000685StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
686 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200687 case STUN_ATTR_MAPPED_ADDRESS:
688 return STUN_VALUE_ADDRESS;
689 case STUN_ATTR_USERNAME:
690 return STUN_VALUE_BYTE_STRING;
691 case STUN_ATTR_MESSAGE_INTEGRITY:
692 return STUN_VALUE_BYTE_STRING;
693 case STUN_ATTR_ERROR_CODE:
694 return STUN_VALUE_ERROR_CODE;
695 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
696 return STUN_VALUE_UINT16_LIST;
697 case STUN_ATTR_REALM:
698 return STUN_VALUE_BYTE_STRING;
699 case STUN_ATTR_NONCE:
700 return STUN_VALUE_BYTE_STRING;
701 case STUN_ATTR_XOR_MAPPED_ADDRESS:
702 return STUN_VALUE_XOR_ADDRESS;
703 case STUN_ATTR_SOFTWARE:
704 return STUN_VALUE_BYTE_STRING;
705 case STUN_ATTR_ALTERNATE_SERVER:
706 return STUN_VALUE_ADDRESS;
707 case STUN_ATTR_FINGERPRINT:
708 return STUN_VALUE_UINT32;
Yves Gerey665174f2018-06-19 15:03:05 +0200709 case STUN_ATTR_RETRANSMIT_COUNT:
710 return STUN_VALUE_UINT32;
Jonas Orelandfa543642020-09-16 10:44:54 +0200711 case STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED:
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700712 return STUN_VALUE_BYTE_STRING;
Jonas Oreland1721de12019-11-20 12:10:39 +0100713 case STUN_ATTR_GOOG_MISC_INFO:
714 return STUN_VALUE_UINT16_LIST;
Yves Gerey665174f2018-06-19 15:03:05 +0200715 default:
716 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000717 }
718}
719
720StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
721 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200722 if (value_type != STUN_VALUE_UNKNOWN) {
723 return StunAttribute::Create(value_type, type,
724 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200725 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200726 // Read unknown attributes as STUN_VALUE_BYTE_STRING
727 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
728 static_cast<uint16_t>(length), this);
729 } else {
730 return NULL;
731 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000732}
733
734const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800735 for (const auto& attr : attrs_) {
736 if (attr->type() == type) {
737 return attr.get();
738 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000739 }
740 return NULL;
741}
742
Tommi408143d2022-06-01 15:29:31 +0200743bool StunMessage::IsValidTransactionId(absl::string_view transaction_id) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000744 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200745 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000746}
747
Jonas Oreland253d50f2019-11-28 17:08:07 +0100748bool StunMessage::EqualAttributes(
749 const StunMessage* other,
750 std::function<bool(int type)> attribute_type_mask) const {
751 RTC_DCHECK(other != nullptr);
752 rtc::ByteBufferWriter tmp_buffer_ptr1;
753 rtc::ByteBufferWriter tmp_buffer_ptr2;
754 for (const auto& attr : attrs_) {
755 if (attribute_type_mask(attr->type())) {
756 const StunAttribute* other_attr = other->GetAttribute(attr->type());
757 if (other_attr == nullptr) {
758 return false;
759 }
760 tmp_buffer_ptr1.Clear();
761 tmp_buffer_ptr2.Clear();
762 attr->Write(&tmp_buffer_ptr1);
763 other_attr->Write(&tmp_buffer_ptr2);
764 if (tmp_buffer_ptr1.Length() != tmp_buffer_ptr2.Length()) {
765 return false;
766 }
767 if (memcmp(tmp_buffer_ptr1.Data(), tmp_buffer_ptr2.Data(),
768 tmp_buffer_ptr1.Length()) != 0) {
769 return false;
770 }
771 }
772 }
773
774 for (const auto& attr : other->attrs_) {
775 if (attribute_type_mask(attr->type())) {
776 const StunAttribute* own_attr = GetAttribute(attr->type());
777 if (own_attr == nullptr) {
778 return false;
779 }
780 // we have already compared all values...
781 }
782 }
783 return true;
784}
785
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000786// StunAttribute
787
Peter Boström0c4e06b2015-10-07 12:23:21 +0200788StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200789 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000790
jbauchf1f87202016-03-30 06:43:37 -0700791void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000792 int remainder = length_ % 4;
793 if (remainder > 0) {
794 buf->Consume(4 - remainder);
795 }
796}
797
jbauchf1f87202016-03-30 06:43:37 -0700798void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000799 int remainder = length_ % 4;
800 if (remainder > 0) {
801 char zeroes[4] = {0};
802 buf->WriteBytes(zeroes, 4 - remainder);
803 }
804}
805
806StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200807 uint16_t type,
808 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000809 StunMessage* owner) {
810 switch (value_type) {
811 case STUN_VALUE_ADDRESS:
812 return new StunAddressAttribute(type, length);
813 case STUN_VALUE_XOR_ADDRESS:
814 return new StunXorAddressAttribute(type, length, owner);
815 case STUN_VALUE_UINT32:
816 return new StunUInt32Attribute(type);
817 case STUN_VALUE_UINT64:
818 return new StunUInt64Attribute(type);
819 case STUN_VALUE_BYTE_STRING:
820 return new StunByteStringAttribute(type, length);
821 case STUN_VALUE_ERROR_CODE:
822 return new StunErrorCodeAttribute(type, length);
823 case STUN_VALUE_UINT16_LIST:
824 return new StunUInt16ListAttribute(type, length);
825 default:
826 return NULL;
827 }
828}
829
zsteinf42cc9d2017-03-27 16:17:19 -0700830std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
831 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200832 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000833}
834
zsteinf42cc9d2017-03-27 16:17:19 -0700835std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
836 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200837 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000838}
839
zsteinf42cc9d2017-03-27 16:17:19 -0700840std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
841 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200842 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000843}
844
zsteinf42cc9d2017-03-27 16:17:19 -0700845std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
846 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200847 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000848}
849
zsteinf42cc9d2017-03-27 16:17:19 -0700850std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
851 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200852 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000853}
854
zsteinf42cc9d2017-03-27 16:17:19 -0700855std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200856 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000857 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
858}
859
zsteinf42cc9d2017-03-27 16:17:19 -0700860std::unique_ptr<StunUInt16ListAttribute>
Jonas Oreland1721de12019-11-20 12:10:39 +0100861StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
862 return std::make_unique<StunUInt16ListAttribute>(type, 0);
863}
864
865std::unique_ptr<StunUInt16ListAttribute>
zsteinf42cc9d2017-03-27 16:17:19 -0700866StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200867 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
868 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000869}
870
Peter Boström0c4e06b2015-10-07 12:23:21 +0200871StunAddressAttribute::StunAddressAttribute(uint16_t type,
872 const rtc::SocketAddress& addr)
873 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000874 SetAddress(addr);
875}
876
Peter Boström0c4e06b2015-10-07 12:23:21 +0200877StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200878 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000879
Steve Antonca7d54e2017-10-25 14:42:51 -0700880StunAttributeValueType StunAddressAttribute::value_type() const {
881 return STUN_VALUE_ADDRESS;
882}
883
jbauchf1f87202016-03-30 06:43:37 -0700884bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200885 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000886 if (!buf->ReadUInt8(&dummy))
887 return false;
888
Peter Boström0c4e06b2015-10-07 12:23:21 +0200889 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000890 if (!buf->ReadUInt8(&stun_family)) {
891 return false;
892 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200893 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000894 if (!buf->ReadUInt16(&port))
895 return false;
896 if (stun_family == STUN_ADDRESS_IPV4) {
897 in_addr v4addr;
898 if (length() != SIZE_IP4) {
899 return false;
900 }
901 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
902 return false;
903 }
904 rtc::IPAddress ipaddr(v4addr);
905 SetAddress(rtc::SocketAddress(ipaddr, port));
906 } else if (stun_family == STUN_ADDRESS_IPV6) {
907 in6_addr v6addr;
908 if (length() != SIZE_IP6) {
909 return false;
910 }
911 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
912 return false;
913 }
914 rtc::IPAddress ipaddr(v6addr);
915 SetAddress(rtc::SocketAddress(ipaddr, port));
916 } else {
917 return false;
918 }
919 return true;
920}
921
jbauchf1f87202016-03-30 06:43:37 -0700922bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000923 StunAddressFamily address_family = family();
924 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100925 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000926 return false;
927 }
928 buf->WriteUInt8(0);
929 buf->WriteUInt8(address_family);
930 buf->WriteUInt16(address_.port());
931 switch (address_.family()) {
932 case AF_INET: {
933 in_addr v4addr = address_.ipaddr().ipv4_address();
934 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
935 break;
936 }
937 case AF_INET6: {
938 in6_addr v6addr = address_.ipaddr().ipv6_address();
939 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
940 break;
941 }
942 }
943 return true;
944}
945
Peter Boström0c4e06b2015-10-07 12:23:21 +0200946StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
947 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200948 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000949
Peter Boström0c4e06b2015-10-07 12:23:21 +0200950StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
951 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000952 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200953 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000954
Steve Antonca7d54e2017-10-25 14:42:51 -0700955StunAttributeValueType StunXorAddressAttribute::value_type() const {
956 return STUN_VALUE_XOR_ADDRESS;
957}
958
959void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
960 owner_ = owner;
961}
962
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000963rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
964 if (owner_) {
965 rtc::IPAddress ip = ipaddr();
966 switch (ip.family()) {
967 case AF_INET: {
968 in_addr v4addr = ip.ipv4_address();
969 v4addr.s_addr =
970 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
971 return rtc::IPAddress(v4addr);
972 }
973 case AF_INET6: {
974 in6_addr v6addr = ip.ipv6_address();
975 const std::string& transaction_id = owner_->transaction_id();
976 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200977 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000978 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
979 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200980 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000981 // Transaction ID is in network byte order, but magic cookie
982 // is stored in host byte order.
983 ip_as_ints[0] =
984 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
985 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
986 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
987 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
988 return rtc::IPAddress(v6addr);
989 }
990 break;
991 }
992 }
993 }
994 // Invalid ip family or transaction ID, or missing owner.
995 // Return an AF_UNSPEC address.
996 return rtc::IPAddress();
997}
998
jbauchf1f87202016-03-30 06:43:37 -0700999bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001000 if (!StunAddressAttribute::Read(buf))
1001 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +02001002 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001003 rtc::IPAddress xored_ip = GetXoredIP();
1004 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
1005 return true;
1006}
1007
jbauchf1f87202016-03-30 06:43:37 -07001008bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001009 StunAddressFamily address_family = family();
1010 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001011 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001012 return false;
1013 }
1014 rtc::IPAddress xored_ip = GetXoredIP();
1015 if (xored_ip.family() == AF_UNSPEC) {
1016 return false;
1017 }
1018 buf->WriteUInt8(0);
1019 buf->WriteUInt8(family());
1020 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
1021 switch (xored_ip.family()) {
1022 case AF_INET: {
1023 in_addr v4addr = xored_ip.ipv4_address();
1024 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
1025 break;
1026 }
1027 case AF_INET6: {
1028 in6_addr v6addr = xored_ip.ipv6_address();
1029 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
1030 break;
1031 }
1032 }
1033 return true;
1034}
1035
Peter Boström0c4e06b2015-10-07 12:23:21 +02001036StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +02001037 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001038
Peter Boström0c4e06b2015-10-07 12:23:21 +02001039StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +02001040 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001041
Steve Antonca7d54e2017-10-25 14:42:51 -07001042StunAttributeValueType StunUInt32Attribute::value_type() const {
1043 return STUN_VALUE_UINT32;
1044}
1045
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001046bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -08001047 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001048 return static_cast<bool>((bits_ >> index) & 0x1);
1049}
1050
1051void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -08001052 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001053 bits_ &= ~(1 << index);
1054 bits_ |= value ? (1 << index) : 0;
1055}
1056
jbauchf1f87202016-03-30 06:43:37 -07001057bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001058 if (length() != SIZE || !buf->ReadUInt32(&bits_))
1059 return false;
1060 return true;
1061}
1062
jbauchf1f87202016-03-30 06:43:37 -07001063bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001064 buf->WriteUInt32(bits_);
1065 return true;
1066}
1067
Peter Boström0c4e06b2015-10-07 12:23:21 +02001068StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +02001069 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001070
Peter Boström0c4e06b2015-10-07 12:23:21 +02001071StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +02001072 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001073
Steve Antonca7d54e2017-10-25 14:42:51 -07001074StunAttributeValueType StunUInt64Attribute::value_type() const {
1075 return STUN_VALUE_UINT64;
1076}
1077
jbauchf1f87202016-03-30 06:43:37 -07001078bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001079 if (length() != SIZE || !buf->ReadUInt64(&bits_))
1080 return false;
1081 return true;
1082}
1083
jbauchf1f87202016-03-30 06:43:37 -07001084bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001085 buf->WriteUInt64(bits_);
1086 return true;
1087}
1088
Peter Boström0c4e06b2015-10-07 12:23:21 +02001089StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +02001090 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001091
Peter Boström0c4e06b2015-10-07 12:23:21 +02001092StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
Tommie83500e2022-06-03 14:28:59 +02001093 absl::string_view str)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001094 : StunAttribute(type, 0), bytes_(NULL) {
Tommie83500e2022-06-03 14:28:59 +02001095 CopyBytes(str);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001096}
1097
Peter Boström0c4e06b2015-10-07 12:23:21 +02001098StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001099 const void* bytes,
1100 size_t length)
1101 : StunAttribute(type, 0), bytes_(NULL) {
1102 CopyBytes(bytes, length);
1103}
1104
Peter Boström0c4e06b2015-10-07 12:23:21 +02001105StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001106 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001107
1108StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +02001109 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001110}
1111
Steve Antonca7d54e2017-10-25 14:42:51 -07001112StunAttributeValueType StunByteStringAttribute::value_type() const {
1113 return STUN_VALUE_BYTE_STRING;
1114}
1115
Tommie83500e2022-06-03 14:28:59 +02001116void StunByteStringAttribute::CopyBytes(absl::string_view bytes) {
1117 char* new_bytes = new char[bytes.size()];
1118 memcpy(new_bytes, bytes.data(), bytes.size());
1119 SetBytes(new_bytes, bytes.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001120}
1121
1122void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
1123 char* new_bytes = new char[length];
1124 memcpy(new_bytes, bytes, length);
1125 SetBytes(new_bytes, length);
1126}
1127
Peter Boström0c4e06b2015-10-07 12:23:21 +02001128uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -08001129 RTC_DCHECK(bytes_ != NULL);
1130 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +02001131 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001132}
1133
Peter Boström0c4e06b2015-10-07 12:23:21 +02001134void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -08001135 RTC_DCHECK(bytes_ != NULL);
1136 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001137 bytes_[index] = value;
1138}
1139
jbauchf1f87202016-03-30 06:43:37 -07001140bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001141 bytes_ = new char[length()];
1142 if (!buf->ReadBytes(bytes_, length())) {
1143 return false;
1144 }
1145
1146 ConsumePadding(buf);
1147 return true;
1148}
1149
jbauchf1f87202016-03-30 06:43:37 -07001150bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
Harald Alvestrandbee64082020-11-12 11:17:41 +00001151 // Check that length is legal according to specs
1152 if (!LengthValid(type(), length())) {
1153 return false;
1154 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001155 buf->WriteBytes(bytes_, length());
1156 WritePadding(buf);
1157 return true;
1158}
1159
1160void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +02001161 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001162 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +02001163 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001164}
1165
zsteinf42cc9d2017-03-27 16:17:19 -07001166const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
1167
Peter Boström0c4e06b2015-10-07 12:23:21 +02001168StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
1169 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001170 const std::string& reason)
1171 : StunAttribute(type, 0) {
1172 SetCode(code);
1173 SetReason(reason);
1174}
1175
Peter Boström0c4e06b2015-10-07 12:23:21 +02001176StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001177 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001178
Yves Gerey665174f2018-06-19 15:03:05 +02001179StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001180
Steve Antonca7d54e2017-10-25 14:42:51 -07001181StunAttributeValueType StunErrorCodeAttribute::value_type() const {
1182 return STUN_VALUE_ERROR_CODE;
1183}
1184
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001185int StunErrorCodeAttribute::code() const {
1186 return class_ * 100 + number_;
1187}
1188
1189void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001190 class_ = static_cast<uint8_t>(code / 100);
1191 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001192}
1193
1194void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001195 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001196 reason_ = reason;
1197}
1198
jbauchf1f87202016-03-30 06:43:37 -07001199bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001200 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001201 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
1202 return false;
1203
1204 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +01001205 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001206
1207 class_ = ((val >> 8) & 0x7);
1208 number_ = (val & 0xff);
1209
1210 if (!buf->ReadString(&reason_, length() - 4))
1211 return false;
1212
1213 ConsumePadding(buf);
1214 return true;
1215}
1216
jbauchf1f87202016-03-30 06:43:37 -07001217bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001218 buf->WriteUInt32(class_ << 8 | number_);
1219 buf->WriteString(reason_);
1220 WritePadding(buf);
1221 return true;
1222}
1223
Peter Boström0c4e06b2015-10-07 12:23:21 +02001224StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001225 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001226 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001227}
1228
1229StunUInt16ListAttribute::~StunUInt16ListAttribute() {
1230 delete attr_types_;
1231}
1232
Steve Antonca7d54e2017-10-25 14:42:51 -07001233StunAttributeValueType StunUInt16ListAttribute::value_type() const {
1234 return STUN_VALUE_UINT16_LIST;
1235}
1236
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001237size_t StunUInt16ListAttribute::Size() const {
1238 return attr_types_->size();
1239}
1240
Peter Boström0c4e06b2015-10-07 12:23:21 +02001241uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001242 return (*attr_types_)[index];
1243}
1244
Peter Boström0c4e06b2015-10-07 12:23:21 +02001245void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001246 (*attr_types_)[index] = value;
1247}
1248
Peter Boström0c4e06b2015-10-07 12:23:21 +02001249void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001250 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001251 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001252}
1253
Jonas Oreland63737a92019-11-21 15:12:14 +01001254void StunUInt16ListAttribute::AddTypeAtIndex(uint16_t index, uint16_t value) {
1255 if (attr_types_->size() < static_cast<size_t>(index + 1)) {
1256 attr_types_->resize(index + 1);
1257 }
1258 (*attr_types_)[index] = value;
1259 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
1260}
1261
jbauchf1f87202016-03-30 06:43:37 -07001262bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +01001263 if (length() % 2) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001264 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +01001265 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001266
1267 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001268 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001269 if (!buf->ReadUInt16(&attr))
1270 return false;
1271 attr_types_->push_back(attr);
1272 }
1273 // Padding of these attributes is done in RFC 5389 style. This is
1274 // slightly different from RFC3489, but it shouldn't be important.
1275 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
1276 // entries in the list (not necessarily the last one - it's unspecified).
1277 // RFC5389 pads on the end, and the bytes are always ignored.
1278 ConsumePadding(buf);
1279 return true;
1280}
1281
jbauchf1f87202016-03-30 06:43:37 -07001282bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001283 for (size_t i = 0; i < attr_types_->size(); ++i) {
1284 buf->WriteUInt16((*attr_types_)[i]);
1285 }
1286 WritePadding(buf);
1287 return true;
1288}
1289
Jonas Oreland9a52bd72019-12-11 11:35:48 +01001290std::string StunMethodToString(int msg_type) {
1291 switch (msg_type) {
1292 case STUN_BINDING_REQUEST:
1293 return "STUN BINDING request";
1294 case STUN_BINDING_INDICATION:
1295 return "STUN BINDING indication";
1296 case STUN_BINDING_RESPONSE:
1297 return "STUN BINDING response";
1298 case STUN_BINDING_ERROR_RESPONSE:
1299 return "STUN BINDING error response";
1300 case GOOG_PING_REQUEST:
1301 return "GOOG PING request";
1302 case GOOG_PING_RESPONSE:
1303 return "GOOG PING response";
1304 case GOOG_PING_ERROR_RESPONSE:
1305 return "GOOG PING error response";
1306 case STUN_ALLOCATE_REQUEST:
1307 return "TURN ALLOCATE request";
1308 case STUN_ALLOCATE_RESPONSE:
1309 return "TURN ALLOCATE response";
1310 case STUN_ALLOCATE_ERROR_RESPONSE:
1311 return "TURN ALLOCATE error response";
1312 case TURN_REFRESH_REQUEST:
1313 return "TURN REFRESH request";
1314 case TURN_REFRESH_RESPONSE:
1315 return "TURN REFRESH response";
1316 case TURN_REFRESH_ERROR_RESPONSE:
1317 return "TURN REFRESH error response";
1318 case TURN_SEND_INDICATION:
1319 return "TURN SEND INDICATION";
1320 case TURN_DATA_INDICATION:
1321 return "TURN DATA INDICATION";
1322 case TURN_CREATE_PERMISSION_REQUEST:
1323 return "TURN CREATE PERMISSION request";
1324 case TURN_CREATE_PERMISSION_RESPONSE:
1325 return "TURN CREATE PERMISSION response";
1326 case TURN_CREATE_PERMISSION_ERROR_RESPONSE:
1327 return "TURN CREATE PERMISSION error response";
1328 case TURN_CHANNEL_BIND_REQUEST:
1329 return "TURN CHANNEL BIND request";
1330 case TURN_CHANNEL_BIND_RESPONSE:
1331 return "TURN CHANNEL BIND response";
1332 case TURN_CHANNEL_BIND_ERROR_RESPONSE:
1333 return "TURN CHANNEL BIND error response";
1334 default:
1335 return "UNKNOWN<" + std::to_string(msg_type) + ">";
1336 }
1337}
1338
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001339int GetStunSuccessResponseType(int req_type) {
1340 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
1341}
1342
1343int GetStunErrorResponseType(int req_type) {
1344 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
1345}
1346
1347bool IsStunRequestType(int msg_type) {
1348 return ((msg_type & kStunTypeMask) == 0x000);
1349}
1350
1351bool IsStunIndicationType(int msg_type) {
1352 return ((msg_type & kStunTypeMask) == 0x010);
1353}
1354
1355bool IsStunSuccessResponseType(int msg_type) {
1356 return ((msg_type & kStunTypeMask) == 0x100);
1357}
1358
1359bool IsStunErrorResponseType(int msg_type) {
1360 return ((msg_type & kStunTypeMask) == 0x110);
1361}
1362
1363bool ComputeStunCredentialHash(const std::string& username,
1364 const std::string& realm,
1365 const std::string& password,
1366 std::string* hash) {
1367 // http://tools.ietf.org/html/rfc5389#section-15.4
1368 // long-term credentials will be calculated using the key and key is
1369 // key = MD5(username ":" realm ":" SASLprep(password))
1370 std::string input = username;
1371 input += ':';
1372 input += realm;
1373 input += ':';
1374 input += password;
1375
1376 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001377 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1378 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001379 if (size == 0) {
1380 return false;
1381 }
1382
1383 *hash = std::string(digest, size);
1384 return true;
1385}
1386
Jonas Oreland202994c2017-12-18 12:10:43 +01001387std::unique_ptr<StunAttribute> CopyStunAttribute(
1388 const StunAttribute& attribute,
1389 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1390 ByteBufferWriter tmpBuffer;
1391 if (tmp_buffer_ptr == nullptr) {
1392 tmp_buffer_ptr = &tmpBuffer;
1393 }
1394
Yves Gerey665174f2018-06-19 15:03:05 +02001395 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1396 attribute.value_type(), attribute.type(),
1397 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001398
1399 if (!copy) {
1400 return nullptr;
1401 }
1402 tmp_buffer_ptr->Clear();
1403 if (!attribute.Write(tmp_buffer_ptr)) {
1404 return nullptr;
1405 }
1406 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1407 if (!copy->Read(&reader)) {
1408 return nullptr;
1409 }
1410
1411 return copy;
1412}
1413
Steve Antonca7d54e2017-10-25 14:42:51 -07001414StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1415 switch (type) {
1416 case STUN_ATTR_LIFETIME:
1417 return STUN_VALUE_UINT32;
1418 case STUN_ATTR_MAGIC_COOKIE:
1419 return STUN_VALUE_BYTE_STRING;
1420 case STUN_ATTR_BANDWIDTH:
1421 return STUN_VALUE_UINT32;
1422 case STUN_ATTR_DESTINATION_ADDRESS:
1423 return STUN_VALUE_ADDRESS;
1424 case STUN_ATTR_SOURCE_ADDRESS2:
1425 return STUN_VALUE_ADDRESS;
1426 case STUN_ATTR_DATA:
1427 return STUN_VALUE_BYTE_STRING;
1428 case STUN_ATTR_OPTIONS:
1429 return STUN_VALUE_UINT32;
1430 default:
1431 return StunMessage::GetAttributeValueType(type);
1432 }
1433}
1434
1435StunMessage* RelayMessage::CreateNew() const {
1436 return new RelayMessage();
1437}
1438
1439StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1440 switch (type) {
1441 case STUN_ATTR_CHANNEL_NUMBER:
1442 return STUN_VALUE_UINT32;
1443 case STUN_ATTR_TURN_LIFETIME:
1444 return STUN_VALUE_UINT32;
1445 case STUN_ATTR_XOR_PEER_ADDRESS:
1446 return STUN_VALUE_XOR_ADDRESS;
1447 case STUN_ATTR_DATA:
1448 return STUN_VALUE_BYTE_STRING;
1449 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1450 return STUN_VALUE_XOR_ADDRESS;
1451 case STUN_ATTR_EVEN_PORT:
1452 return STUN_VALUE_BYTE_STRING;
1453 case STUN_ATTR_REQUESTED_TRANSPORT:
1454 return STUN_VALUE_UINT32;
1455 case STUN_ATTR_DONT_FRAGMENT:
1456 return STUN_VALUE_BYTE_STRING;
1457 case STUN_ATTR_RESERVATION_TOKEN:
1458 return STUN_VALUE_BYTE_STRING;
1459 default:
1460 return StunMessage::GetAttributeValueType(type);
1461 }
1462}
1463
1464StunMessage* TurnMessage::CreateNew() const {
1465 return new TurnMessage();
1466}
1467
1468StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1469 switch (type) {
1470 case STUN_ATTR_PRIORITY:
Jonas Orelandfa543642020-09-16 10:44:54 +02001471 case STUN_ATTR_GOOG_NETWORK_INFO:
Steve Antonca7d54e2017-10-25 14:42:51 -07001472 case STUN_ATTR_NOMINATION:
1473 return STUN_VALUE_UINT32;
1474 case STUN_ATTR_USE_CANDIDATE:
1475 return STUN_VALUE_BYTE_STRING;
1476 case STUN_ATTR_ICE_CONTROLLED:
1477 return STUN_VALUE_UINT64;
1478 case STUN_ATTR_ICE_CONTROLLING:
1479 return STUN_VALUE_UINT64;
1480 default:
1481 return StunMessage::GetAttributeValueType(type);
1482 }
1483}
1484
1485StunMessage* IceMessage::CreateNew() const {
1486 return new IceMessage();
1487}
1488
Jonas Oreland253d50f2019-11-28 17:08:07 +01001489std::unique_ptr<StunMessage> StunMessage::Clone() const {
1490 std::unique_ptr<StunMessage> copy(CreateNew());
1491 if (!copy) {
1492 return nullptr;
1493 }
1494 rtc::ByteBufferWriter buf;
1495 if (!Write(&buf)) {
1496 return nullptr;
1497 }
1498 rtc::ByteBufferReader reader(buf);
1499 if (!copy->Read(&reader)) {
1500 return nullptr;
1501 }
1502 return copy;
1503}
1504
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001505} // namespace cricket