blob: 87da0058d30592501a7f3209b2e3b6803848646d [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>
Yves Gerey665174f2018-06-19 15:03:05 +020014#include <algorithm>
Harald Alvestrandbee64082020-11-12 11:17:41 +000015#include <cstdint>
16#include <iterator>
kwiberg3ec46792016-04-27 07:22:53 -070017#include <memory>
Steve Anton6c38cc72017-11-29 10:25:58 -080018#include <utility>
kwiberg3ec46792016-04-27 07:22:53 -070019
Steve Anton10542f22019-01-11 09:11:00 -080020#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/checks.h"
22#include "rtc_base/crc32.h"
23#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "rtc_base/message_digest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000025
jbauchf1f87202016-03-30 06:43:37 -070026using rtc::ByteBufferReader;
27using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000028
Harald Alvestrandbee64082020-11-12 11:17:41 +000029namespace cricket {
30
Zach Stein92c42892018-11-28 11:38:52 -080031namespace {
32
Harald Alvestrandbee64082020-11-12 11:17:41 +000033const int k127Utf8CharactersLengthInBytes = 508;
Harald Alvestrandbee64082020-11-12 11:17:41 +000034const int kMessageIntegrityAttributeLength = 20;
Harald Alvestrand837f13c2020-12-04 07:52:22 +000035const int kTheoreticalMaximumAttributeLength = 65535;
Harald Alvestrandbee64082020-11-12 11:17:41 +000036
Zach Stein92c42892018-11-28 11:38:52 -080037uint32_t ReduceTransactionId(const std::string& transaction_id) {
38 RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
39 transaction_id.length() ==
40 cricket::kStunLegacyTransactionIdLength);
Danil Chapovalov7b46e172019-11-14 17:40:23 +010041 ByteBufferReader reader(transaction_id.c_str(), transaction_id.length());
Zach Stein92c42892018-11-28 11:38:52 -080042 uint32_t result = 0;
Zach Steinff71a492018-12-07 11:25:12 -080043 uint32_t next;
44 while (reader.ReadUInt32(&next)) {
45 result ^= next;
Zach Stein92c42892018-11-28 11:38:52 -080046 }
47 return result;
48}
49
Harald Alvestrandbee64082020-11-12 11:17:41 +000050// Check the maximum length of a BYTE_STRING attribute against specifications.
51bool LengthValid(int type, int length) {
52 // "Less than 509 bytes" is intended to indicate a maximum of 127
53 // UTF-8 characters, which may take up to 4 bytes per character.
54 switch (type) {
55 case STUN_ATTR_USERNAME:
56 return length <=
57 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.3
58 case STUN_ATTR_MESSAGE_INTEGRITY:
59 return length ==
60 kMessageIntegrityAttributeLength; // RFC 8489 section 14.5
61 case STUN_ATTR_REALM:
62 return length <=
63 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.9
64 case STUN_ATTR_NONCE:
65 return length <=
66 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.10
67 case STUN_ATTR_SOFTWARE:
68 return length <=
69 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.14
Harald Alvestrandbee64082020-11-12 11:17:41 +000070 case STUN_ATTR_DATA:
71 // No length restriction in RFC; it's the content of an UDP datagram,
72 // which in theory can be up to 65.535 bytes.
73 // TODO(bugs.webrtc.org/12179): Write a test to find the real limit.
Harald Alvestrand837f13c2020-12-04 07:52:22 +000074 return length <= kTheoreticalMaximumAttributeLength;
Harald Alvestrandbee64082020-11-12 11:17:41 +000075 default:
76 // Return an arbitrary restriction for all other types.
Harald Alvestrand837f13c2020-12-04 07:52:22 +000077 return length <= kTheoreticalMaximumAttributeLength;
Harald Alvestrandbee64082020-11-12 11:17:41 +000078 }
Artem Titovd3251962021-11-15 16:57:07 +010079 RTC_DCHECK_NOTREACHED();
Harald Alvestrandbee64082020-11-12 11:17:41 +000080 return true;
81}
Zach Stein92c42892018-11-28 11:38:52 -080082
Harald Alvestrandbee64082020-11-12 11:17:41 +000083} // namespace
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000084
85const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
86const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
87const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -070088const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[] = "Unknown Attribute";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000089const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000090const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
91const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
92const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
93const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
94const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
95const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
96
Yves Gerey665174f2018-06-19 15:03:05 +020097const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000098const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020099const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
Eldar Relloda13ea22019-06-01 12:23:43 +0300100const int SERVER_NOT_REACHABLE_ERROR = 701;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000101
102// StunMessage
103
104StunMessage::StunMessage()
105 : type_(0),
106 length_(0),
Jonas Oreland7ca63112018-02-27 08:45:13 +0100107 transaction_id_(EMPTY_TRANSACTION_ID),
108 stun_magic_cookie_(kStunMagicCookie) {
nisseede5da42017-01-12 05:15:36 -0800109 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000110}
111
Steve Antonca7d54e2017-10-25 14:42:51 -0700112StunMessage::~StunMessage() = default;
113
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000114bool StunMessage::IsLegacy() const {
115 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
116 return true;
nisseede5da42017-01-12 05:15:36 -0800117 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000118 return false;
119}
120
121bool StunMessage::SetTransactionID(const std::string& str) {
122 if (!IsValidTransactionId(str)) {
123 return false;
124 }
125 transaction_id_ = str;
Zach Stein92c42892018-11-28 11:38:52 -0800126 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000127 return true;
128}
129
Jonas Oreland16ccef72018-03-27 09:02:43 +0200130static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200131 return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
132 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200133}
134
zsteinf42cc9d2017-03-27 16:17:19 -0700135void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200136 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +0200137 // but allow any type for the range that in the RFC is reserved for
138 // the "designated experts".
139 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200140 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
141 }
nissecc99bc22017-02-02 01:31:30 -0800142
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143 attr->SetOwner(this);
144 size_t attr_length = attr->length();
145 if (attr_length % 4 != 0) {
146 attr_length += (4 - (attr_length % 4));
147 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200148 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -0700149
150 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000151}
152
Jonas Oreland202994c2017-12-18 12:10:43 +0100153std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
154 std::unique_ptr<StunAttribute> attribute;
155 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
Yves Gerey665174f2018-06-19 15:03:05 +0200156 if ((*it)->type() == type) {
157 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100158 attrs_.erase(std::next(it).base());
159 break;
160 }
161 }
162 if (attribute) {
163 attribute->SetOwner(nullptr);
164 size_t attr_length = attribute->length();
165 if (attr_length % 4 != 0) {
166 attr_length += (4 - (attr_length % 4));
167 }
168 length_ -= static_cast<uint16_t>(attr_length + 4);
169 }
170 return attribute;
171}
172
Jonas Oreland63737a92019-11-21 15:12:14 +0100173void StunMessage::ClearAttributes() {
174 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
175 (*it)->SetOwner(nullptr);
176 }
177 attrs_.clear();
178 length_ = 0;
179}
180
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700181std::vector<uint16_t> StunMessage::GetNonComprehendedAttributes() const {
182 std::vector<uint16_t> unknown_attributes;
183 for (auto& attr : attrs_) {
184 // "comprehension-required" range is 0x0000-0x7FFF.
185 if (attr->type() >= 0x0000 && attr->type() <= 0x7FFF &&
186 GetAttributeValueType(attr->type()) == STUN_VALUE_UNKNOWN) {
187 unknown_attributes.push_back(attr->type());
188 }
189 }
190 return unknown_attributes;
191}
192
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000193const StunAddressAttribute* StunMessage::GetAddress(int type) const {
194 switch (type) {
195 case STUN_ATTR_MAPPED_ADDRESS: {
196 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
197 // missing.
198 const StunAttribute* mapped_address =
199 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
200 if (!mapped_address)
201 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
202 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
203 }
204
205 default:
206 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
207 }
208}
209
210const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
211 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
212}
213
214const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
215 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
216}
217
218const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
219 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
220}
221
Jonas Oreland1721de12019-11-20 12:10:39 +0100222const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
223 return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
224}
225
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000226const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
227 return static_cast<const StunErrorCodeAttribute*>(
228 GetAttribute(STUN_ATTR_ERROR_CODE));
229}
230
deadbeef996fc6b2017-04-26 09:21:22 -0700231int StunMessage::GetErrorCodeValue() const {
232 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
233 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
234}
235
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000236const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
237 return static_cast<const StunUInt16ListAttribute*>(
238 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
239}
240
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000241StunMessage::IntegrityStatus StunMessage::ValidateMessageIntegrity(
242 const std::string& password) {
243 password_ = password;
244 if (GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
245 if (ValidateMessageIntegrityOfType(
246 STUN_ATTR_MESSAGE_INTEGRITY, kStunMessageIntegritySize,
247 buffer_.c_str(), buffer_.size(), password)) {
248 integrity_ = IntegrityStatus::kIntegrityOk;
249 } else {
250 integrity_ = IntegrityStatus::kIntegrityBad;
251 }
252 } else if (GetByteString(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32)) {
253 if (ValidateMessageIntegrityOfType(
254 STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32, kStunMessageIntegrity32Size,
255 buffer_.c_str(), buffer_.size(), password)) {
256 integrity_ = IntegrityStatus::kIntegrityOk;
257 } else {
258 integrity_ = IntegrityStatus::kIntegrityBad;
259 }
260 } else {
261 integrity_ = IntegrityStatus::kNoIntegrity;
262 }
263 return integrity_;
264}
265
Yves Gerey665174f2018-06-19 15:03:05 +0200266bool StunMessage::ValidateMessageIntegrity(const char* data,
267 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000268 const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100269 return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
270 kStunMessageIntegritySize, data, size,
271 password);
272}
273
274bool StunMessage::ValidateMessageIntegrity32(const char* data,
275 size_t size,
276 const std::string& password) {
277 return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
278 kStunMessageIntegrity32Size, data, size,
279 password);
280}
281
282// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
283// procedure outlined in RFC 5389, section 15.4.
284bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
285 size_t mi_attr_size,
286 const char* data,
287 size_t size,
288 const std::string& password) {
289 RTC_DCHECK(mi_attr_size <= kStunMessageIntegritySize);
290
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000291 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700292 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000293 return false;
294 }
295
296 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200297 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000298 if (size != (msg_length + kStunHeaderSize)) {
299 return false;
300 }
301
302 // Finding Message Integrity attribute in stun message.
303 size_t current_pos = kStunHeaderSize;
304 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700305 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200306 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000307 // Getting attribute type and length.
308 attr_type = rtc::GetBE16(&data[current_pos]);
309 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
310
311 // If M-I, sanity check it, and break out.
Jonas Oreland63737a92019-11-21 15:12:14 +0100312 if (attr_type == mi_attr_type) {
313 if (attr_length != mi_attr_size ||
katrielc1a206102016-06-20 05:13:16 -0700314 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
315 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000316 return false;
317 }
318 has_message_integrity_attr = true;
319 break;
320 }
321
322 // Otherwise, skip to the next attribute.
323 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
324 if ((attr_length % 4) != 0) {
325 current_pos += (4 - (attr_length % 4));
326 }
327 }
328
329 if (!has_message_integrity_attr) {
330 return false;
331 }
332
333 // Getting length of the message to calculate Message Integrity.
334 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700335 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000336 memcpy(temp_data.get(), data, current_pos);
Jonas Oreland63737a92019-11-21 15:12:14 +0100337 if (size > mi_pos + kStunAttributeHeaderSize + mi_attr_size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000338 // Stun message has other attributes after message integrity.
339 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200340 size_t extra_offset =
Jonas Oreland63737a92019-11-21 15:12:14 +0100341 size - (mi_pos + kStunAttributeHeaderSize + mi_attr_size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000342 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
343
344 // Writing new length of the STUN message @ Message Length in temp buffer.
345 // 0 1 2 3
346 // 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
347 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
348 // |0 0| STUN Message Type | Message Length |
349 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200350 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 }
352
353 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200354 size_t ret =
355 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
356 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800357 RTC_DCHECK(ret == sizeof(hmac));
Jonas Oreland63737a92019-11-21 15:12:14 +0100358 if (ret != sizeof(hmac)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000359 return false;
Jonas Oreland63737a92019-11-21 15:12:14 +0100360 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000361
362 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200363 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
Jonas Oreland63737a92019-11-21 15:12:14 +0100364 mi_attr_size) == 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000365}
366
367bool StunMessage::AddMessageIntegrity(const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100368 return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
369 kStunMessageIntegritySize, password.c_str(),
370 password.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371}
372
Jonas Oreland63737a92019-11-21 15:12:14 +0100373bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
374 return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
375 kStunMessageIntegrity32Size, password.data(),
376 password.length());
377}
378
379bool StunMessage::AddMessageIntegrityOfType(int attr_type,
380 size_t attr_size,
381 const char* key,
382 size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000383 // Add the attribute with a dummy value. Since this is a known attribute, it
384 // can't fail.
Jonas Oreland63737a92019-11-21 15:12:14 +0100385 RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200386 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
Jonas Oreland63737a92019-11-21 15:12:14 +0100387 attr_type, std::string(attr_size, '0'));
zsteinf42cc9d2017-03-27 16:17:19 -0700388 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
389 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000390
391 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700392 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000393 if (!Write(&buf))
394 return false;
395
396 int msg_len_for_hmac = static_cast<int>(
397 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
398 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200399 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
400 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800401 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000402 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100403 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200404 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000405 return false;
406 }
407
408 // Insert correct HMAC into the attribute.
Jonas Oreland63737a92019-11-21 15:12:14 +0100409 msg_integrity_attr->CopyBytes(hmac, attr_size);
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000410 password_.assign(key, keylen);
411 integrity_ = IntegrityStatus::kIntegrityOk;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000412 return true;
413}
414
415// Verifies a message is in fact a STUN message, by performing the checks
416// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
417// in section 15.5.
418bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
419 // Check the message length.
420 size_t fingerprint_attr_size =
421 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
422 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
423 return false;
424
425 // Skip the rest if the magic cookie isn't present.
426 const char* magic_cookie =
427 data + kStunTransactionIdOffset - kStunMagicCookieLength;
428 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
429 return false;
430
431 // Check the fingerprint type and length.
432 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
433 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200434 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000435 StunUInt32Attribute::SIZE)
436 return false;
437
438 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200439 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000440 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
441 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200442 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000443}
444
Jonas Oreland253d50f2019-11-28 17:08:07 +0100445bool StunMessage::IsStunMethod(rtc::ArrayView<int> methods,
446 const char* data,
447 size_t size) {
448 // Check the message length.
449 if (size % 4 != 0 || size < kStunHeaderSize)
450 return false;
451
452 // Skip the rest if the magic cookie isn't present.
453 const char* magic_cookie =
454 data + kStunTransactionIdOffset - kStunMagicCookieLength;
455 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
456 return false;
457
458 int method = rtc::GetBE16(data);
459 for (int m : methods) {
460 if (m == method) {
461 return true;
462 }
463 }
464 return false;
465}
466
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000467bool StunMessage::AddFingerprint() {
468 // Add the attribute with a dummy value. Since this is a known attribute,
469 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700470 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200471 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700472 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700473 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000474
475 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700476 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000477 if (!Write(&buf))
478 return false;
479
480 int msg_len_for_crc32 = static_cast<int>(
481 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200482 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000483
484 // Insert the correct CRC-32, XORed with a constant, into the attribute.
485 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
486 return true;
487}
488
jbauchf1f87202016-03-30 06:43:37 -0700489bool StunMessage::Read(ByteBufferReader* buf) {
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000490 // Keep a copy of the buffer data around for later verification.
491 buffer_.assign(buf->Data(), buf->Length());
492
Jonas Oreland1721de12019-11-20 12:10:39 +0100493 if (!buf->ReadUInt16(&type_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000494 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100495 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000496
497 if (type_ & 0x8000) {
498 // RTP and RTCP set the MSB of first byte, since first two bits are version,
499 // and version is always 2 (10). If set, this is not a STUN packet.
500 return false;
501 }
502
Jonas Oreland1721de12019-11-20 12:10:39 +0100503 if (!buf->ReadUInt16(&length_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000504 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100505 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000506
507 std::string magic_cookie;
Jonas Oreland1721de12019-11-20 12:10:39 +0100508 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000509 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100510 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000511
512 std::string transaction_id;
Jonas Oreland1721de12019-11-20 12:10:39 +0100513 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000514 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100515 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000516
Andrew Royes154d8392019-03-14 10:38:31 -0700517 uint32_t magic_cookie_int;
518 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
519 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
520 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000521 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
522 // If magic cookie is invalid it means that the peer implements
523 // RFC3489 instead of RFC5389.
524 transaction_id.insert(0, magic_cookie);
525 }
nisseede5da42017-01-12 05:15:36 -0800526 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000527 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800528 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000529
Jonas Oreland1721de12019-11-20 12:10:39 +0100530 if (length_ != buf->Length()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000531 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100532 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000533
zsteinad94c4c2017-03-06 13:36:05 -0800534 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000535
536 size_t rest = buf->Length() - length_;
537 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200538 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000539 if (!buf->ReadUInt16(&attr_type))
540 return false;
541 if (!buf->ReadUInt16(&attr_length))
542 return false;
543
Honghai Zhang3e024302016-09-22 09:52:16 -0700544 std::unique_ptr<StunAttribute> attr(
545 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000546 if (!attr) {
547 // Skip any unknown or malformed attributes.
548 if ((attr_length % 4) != 0) {
549 attr_length += (4 - (attr_length % 4));
550 }
Jonas Oreland1721de12019-11-20 12:10:39 +0100551 if (!buf->Consume(attr_length)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000552 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100553 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000554 } else {
Jonas Oreland1721de12019-11-20 12:10:39 +0100555 if (!attr->Read(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000556 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100557 }
zsteinad94c4c2017-03-06 13:36:05 -0800558 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000559 }
560 }
561
nisseede5da42017-01-12 05:15:36 -0800562 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000563 return true;
564}
565
jbauchf1f87202016-03-30 06:43:37 -0700566bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000567 buf->WriteUInt16(type_);
568 buf->WriteUInt16(length_);
569 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100570 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000571 buf->WriteString(transaction_id_);
572
zsteinad94c4c2017-03-06 13:36:05 -0800573 for (const auto& attr : attrs_) {
574 buf->WriteUInt16(attr->type());
575 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
576 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000577 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800578 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000579 }
580
581 return true;
582}
583
Steve Antonca7d54e2017-10-25 14:42:51 -0700584StunMessage* StunMessage::CreateNew() const {
585 return new StunMessage();
586}
587
Jonas Oreland7ca63112018-02-27 08:45:13 +0100588void StunMessage::SetStunMagicCookie(uint32_t val) {
589 stun_magic_cookie_ = val;
590}
591
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000592StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
593 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200594 case STUN_ATTR_MAPPED_ADDRESS:
595 return STUN_VALUE_ADDRESS;
596 case STUN_ATTR_USERNAME:
597 return STUN_VALUE_BYTE_STRING;
598 case STUN_ATTR_MESSAGE_INTEGRITY:
599 return STUN_VALUE_BYTE_STRING;
600 case STUN_ATTR_ERROR_CODE:
601 return STUN_VALUE_ERROR_CODE;
602 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
603 return STUN_VALUE_UINT16_LIST;
604 case STUN_ATTR_REALM:
605 return STUN_VALUE_BYTE_STRING;
606 case STUN_ATTR_NONCE:
607 return STUN_VALUE_BYTE_STRING;
608 case STUN_ATTR_XOR_MAPPED_ADDRESS:
609 return STUN_VALUE_XOR_ADDRESS;
610 case STUN_ATTR_SOFTWARE:
611 return STUN_VALUE_BYTE_STRING;
612 case STUN_ATTR_ALTERNATE_SERVER:
613 return STUN_VALUE_ADDRESS;
614 case STUN_ATTR_FINGERPRINT:
615 return STUN_VALUE_UINT32;
Yves Gerey665174f2018-06-19 15:03:05 +0200616 case STUN_ATTR_RETRANSMIT_COUNT:
617 return STUN_VALUE_UINT32;
Jonas Orelandfa543642020-09-16 10:44:54 +0200618 case STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED:
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700619 return STUN_VALUE_BYTE_STRING;
Jonas Oreland1721de12019-11-20 12:10:39 +0100620 case STUN_ATTR_GOOG_MISC_INFO:
621 return STUN_VALUE_UINT16_LIST;
Yves Gerey665174f2018-06-19 15:03:05 +0200622 default:
623 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000624 }
625}
626
627StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
628 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200629 if (value_type != STUN_VALUE_UNKNOWN) {
630 return StunAttribute::Create(value_type, type,
631 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200632 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200633 // Read unknown attributes as STUN_VALUE_BYTE_STRING
634 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
635 static_cast<uint16_t>(length), this);
636 } else {
637 return NULL;
638 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000639}
640
641const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800642 for (const auto& attr : attrs_) {
643 if (attr->type() == type) {
644 return attr.get();
645 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000646 }
647 return NULL;
648}
649
650bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
651 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200652 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000653}
654
Jonas Oreland253d50f2019-11-28 17:08:07 +0100655bool StunMessage::EqualAttributes(
656 const StunMessage* other,
657 std::function<bool(int type)> attribute_type_mask) const {
658 RTC_DCHECK(other != nullptr);
659 rtc::ByteBufferWriter tmp_buffer_ptr1;
660 rtc::ByteBufferWriter tmp_buffer_ptr2;
661 for (const auto& attr : attrs_) {
662 if (attribute_type_mask(attr->type())) {
663 const StunAttribute* other_attr = other->GetAttribute(attr->type());
664 if (other_attr == nullptr) {
665 return false;
666 }
667 tmp_buffer_ptr1.Clear();
668 tmp_buffer_ptr2.Clear();
669 attr->Write(&tmp_buffer_ptr1);
670 other_attr->Write(&tmp_buffer_ptr2);
671 if (tmp_buffer_ptr1.Length() != tmp_buffer_ptr2.Length()) {
672 return false;
673 }
674 if (memcmp(tmp_buffer_ptr1.Data(), tmp_buffer_ptr2.Data(),
675 tmp_buffer_ptr1.Length()) != 0) {
676 return false;
677 }
678 }
679 }
680
681 for (const auto& attr : other->attrs_) {
682 if (attribute_type_mask(attr->type())) {
683 const StunAttribute* own_attr = GetAttribute(attr->type());
684 if (own_attr == nullptr) {
685 return false;
686 }
687 // we have already compared all values...
688 }
689 }
690 return true;
691}
692
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000693// StunAttribute
694
Peter Boström0c4e06b2015-10-07 12:23:21 +0200695StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200696 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000697
jbauchf1f87202016-03-30 06:43:37 -0700698void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000699 int remainder = length_ % 4;
700 if (remainder > 0) {
701 buf->Consume(4 - remainder);
702 }
703}
704
jbauchf1f87202016-03-30 06:43:37 -0700705void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000706 int remainder = length_ % 4;
707 if (remainder > 0) {
708 char zeroes[4] = {0};
709 buf->WriteBytes(zeroes, 4 - remainder);
710 }
711}
712
713StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200714 uint16_t type,
715 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000716 StunMessage* owner) {
717 switch (value_type) {
718 case STUN_VALUE_ADDRESS:
719 return new StunAddressAttribute(type, length);
720 case STUN_VALUE_XOR_ADDRESS:
721 return new StunXorAddressAttribute(type, length, owner);
722 case STUN_VALUE_UINT32:
723 return new StunUInt32Attribute(type);
724 case STUN_VALUE_UINT64:
725 return new StunUInt64Attribute(type);
726 case STUN_VALUE_BYTE_STRING:
727 return new StunByteStringAttribute(type, length);
728 case STUN_VALUE_ERROR_CODE:
729 return new StunErrorCodeAttribute(type, length);
730 case STUN_VALUE_UINT16_LIST:
731 return new StunUInt16ListAttribute(type, length);
732 default:
733 return NULL;
734 }
735}
736
zsteinf42cc9d2017-03-27 16:17:19 -0700737std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
738 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200739 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000740}
741
zsteinf42cc9d2017-03-27 16:17:19 -0700742std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
743 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200744 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000745}
746
zsteinf42cc9d2017-03-27 16:17:19 -0700747std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
748 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200749 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000750}
751
zsteinf42cc9d2017-03-27 16:17:19 -0700752std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
753 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200754 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000755}
756
zsteinf42cc9d2017-03-27 16:17:19 -0700757std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
758 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200759 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000760}
761
zsteinf42cc9d2017-03-27 16:17:19 -0700762std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200763 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000764 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
765}
766
zsteinf42cc9d2017-03-27 16:17:19 -0700767std::unique_ptr<StunUInt16ListAttribute>
Jonas Oreland1721de12019-11-20 12:10:39 +0100768StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
769 return std::make_unique<StunUInt16ListAttribute>(type, 0);
770}
771
772std::unique_ptr<StunUInt16ListAttribute>
zsteinf42cc9d2017-03-27 16:17:19 -0700773StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200774 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
775 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000776}
777
Peter Boström0c4e06b2015-10-07 12:23:21 +0200778StunAddressAttribute::StunAddressAttribute(uint16_t type,
779 const rtc::SocketAddress& addr)
780 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000781 SetAddress(addr);
782}
783
Peter Boström0c4e06b2015-10-07 12:23:21 +0200784StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200785 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000786
Steve Antonca7d54e2017-10-25 14:42:51 -0700787StunAttributeValueType StunAddressAttribute::value_type() const {
788 return STUN_VALUE_ADDRESS;
789}
790
jbauchf1f87202016-03-30 06:43:37 -0700791bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200792 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000793 if (!buf->ReadUInt8(&dummy))
794 return false;
795
Peter Boström0c4e06b2015-10-07 12:23:21 +0200796 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000797 if (!buf->ReadUInt8(&stun_family)) {
798 return false;
799 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200800 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000801 if (!buf->ReadUInt16(&port))
802 return false;
803 if (stun_family == STUN_ADDRESS_IPV4) {
804 in_addr v4addr;
805 if (length() != SIZE_IP4) {
806 return false;
807 }
808 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
809 return false;
810 }
811 rtc::IPAddress ipaddr(v4addr);
812 SetAddress(rtc::SocketAddress(ipaddr, port));
813 } else if (stun_family == STUN_ADDRESS_IPV6) {
814 in6_addr v6addr;
815 if (length() != SIZE_IP6) {
816 return false;
817 }
818 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
819 return false;
820 }
821 rtc::IPAddress ipaddr(v6addr);
822 SetAddress(rtc::SocketAddress(ipaddr, port));
823 } else {
824 return false;
825 }
826 return true;
827}
828
jbauchf1f87202016-03-30 06:43:37 -0700829bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000830 StunAddressFamily address_family = family();
831 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100832 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000833 return false;
834 }
835 buf->WriteUInt8(0);
836 buf->WriteUInt8(address_family);
837 buf->WriteUInt16(address_.port());
838 switch (address_.family()) {
839 case AF_INET: {
840 in_addr v4addr = address_.ipaddr().ipv4_address();
841 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
842 break;
843 }
844 case AF_INET6: {
845 in6_addr v6addr = address_.ipaddr().ipv6_address();
846 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
847 break;
848 }
849 }
850 return true;
851}
852
Peter Boström0c4e06b2015-10-07 12:23:21 +0200853StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
854 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200855 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000856
Peter Boström0c4e06b2015-10-07 12:23:21 +0200857StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
858 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000859 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200860 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000861
Steve Antonca7d54e2017-10-25 14:42:51 -0700862StunAttributeValueType StunXorAddressAttribute::value_type() const {
863 return STUN_VALUE_XOR_ADDRESS;
864}
865
866void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
867 owner_ = owner;
868}
869
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000870rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
871 if (owner_) {
872 rtc::IPAddress ip = ipaddr();
873 switch (ip.family()) {
874 case AF_INET: {
875 in_addr v4addr = ip.ipv4_address();
876 v4addr.s_addr =
877 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
878 return rtc::IPAddress(v4addr);
879 }
880 case AF_INET6: {
881 in6_addr v6addr = ip.ipv6_address();
882 const std::string& transaction_id = owner_->transaction_id();
883 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200884 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000885 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
886 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200887 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000888 // Transaction ID is in network byte order, but magic cookie
889 // is stored in host byte order.
890 ip_as_ints[0] =
891 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
892 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
893 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
894 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
895 return rtc::IPAddress(v6addr);
896 }
897 break;
898 }
899 }
900 }
901 // Invalid ip family or transaction ID, or missing owner.
902 // Return an AF_UNSPEC address.
903 return rtc::IPAddress();
904}
905
jbauchf1f87202016-03-30 06:43:37 -0700906bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000907 if (!StunAddressAttribute::Read(buf))
908 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200909 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000910 rtc::IPAddress xored_ip = GetXoredIP();
911 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
912 return true;
913}
914
jbauchf1f87202016-03-30 06:43:37 -0700915bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000916 StunAddressFamily address_family = family();
917 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100918 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000919 return false;
920 }
921 rtc::IPAddress xored_ip = GetXoredIP();
922 if (xored_ip.family() == AF_UNSPEC) {
923 return false;
924 }
925 buf->WriteUInt8(0);
926 buf->WriteUInt8(family());
927 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
928 switch (xored_ip.family()) {
929 case AF_INET: {
930 in_addr v4addr = xored_ip.ipv4_address();
931 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
932 break;
933 }
934 case AF_INET6: {
935 in6_addr v6addr = xored_ip.ipv6_address();
936 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
937 break;
938 }
939 }
940 return true;
941}
942
Peter Boström0c4e06b2015-10-07 12:23:21 +0200943StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200944 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000945
Peter Boström0c4e06b2015-10-07 12:23:21 +0200946StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200947 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000948
Steve Antonca7d54e2017-10-25 14:42:51 -0700949StunAttributeValueType StunUInt32Attribute::value_type() const {
950 return STUN_VALUE_UINT32;
951}
952
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000953bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800954 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000955 return static_cast<bool>((bits_ >> index) & 0x1);
956}
957
958void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800959 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000960 bits_ &= ~(1 << index);
961 bits_ |= value ? (1 << index) : 0;
962}
963
jbauchf1f87202016-03-30 06:43:37 -0700964bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000965 if (length() != SIZE || !buf->ReadUInt32(&bits_))
966 return false;
967 return true;
968}
969
jbauchf1f87202016-03-30 06:43:37 -0700970bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000971 buf->WriteUInt32(bits_);
972 return true;
973}
974
Peter Boström0c4e06b2015-10-07 12:23:21 +0200975StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200976 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000977
Peter Boström0c4e06b2015-10-07 12:23:21 +0200978StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200979 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000980
Steve Antonca7d54e2017-10-25 14:42:51 -0700981StunAttributeValueType StunUInt64Attribute::value_type() const {
982 return STUN_VALUE_UINT64;
983}
984
jbauchf1f87202016-03-30 06:43:37 -0700985bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000986 if (length() != SIZE || !buf->ReadUInt64(&bits_))
987 return false;
988 return true;
989}
990
jbauchf1f87202016-03-30 06:43:37 -0700991bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000992 buf->WriteUInt64(bits_);
993 return true;
994}
995
Peter Boström0c4e06b2015-10-07 12:23:21 +0200996StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200997 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000998
Peter Boström0c4e06b2015-10-07 12:23:21 +0200999StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001000 const std::string& str)
1001 : StunAttribute(type, 0), bytes_(NULL) {
1002 CopyBytes(str.c_str(), str.size());
1003}
1004
Peter Boström0c4e06b2015-10-07 12:23:21 +02001005StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001006 const void* bytes,
1007 size_t length)
1008 : StunAttribute(type, 0), bytes_(NULL) {
1009 CopyBytes(bytes, length);
1010}
1011
Peter Boström0c4e06b2015-10-07 12:23:21 +02001012StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001013 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001014
1015StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +02001016 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001017}
1018
Steve Antonca7d54e2017-10-25 14:42:51 -07001019StunAttributeValueType StunByteStringAttribute::value_type() const {
1020 return STUN_VALUE_BYTE_STRING;
1021}
1022
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001023void StunByteStringAttribute::CopyBytes(const char* bytes) {
1024 CopyBytes(bytes, strlen(bytes));
1025}
1026
1027void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
1028 char* new_bytes = new char[length];
1029 memcpy(new_bytes, bytes, length);
1030 SetBytes(new_bytes, length);
1031}
1032
Peter Boström0c4e06b2015-10-07 12:23:21 +02001033uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -08001034 RTC_DCHECK(bytes_ != NULL);
1035 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +02001036 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001037}
1038
Peter Boström0c4e06b2015-10-07 12:23:21 +02001039void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -08001040 RTC_DCHECK(bytes_ != NULL);
1041 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001042 bytes_[index] = value;
1043}
1044
jbauchf1f87202016-03-30 06:43:37 -07001045bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001046 bytes_ = new char[length()];
1047 if (!buf->ReadBytes(bytes_, length())) {
1048 return false;
1049 }
1050
1051 ConsumePadding(buf);
1052 return true;
1053}
1054
jbauchf1f87202016-03-30 06:43:37 -07001055bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
Harald Alvestrandbee64082020-11-12 11:17:41 +00001056 // Check that length is legal according to specs
1057 if (!LengthValid(type(), length())) {
1058 return false;
1059 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001060 buf->WriteBytes(bytes_, length());
1061 WritePadding(buf);
1062 return true;
1063}
1064
1065void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +02001066 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001067 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +02001068 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001069}
1070
zsteinf42cc9d2017-03-27 16:17:19 -07001071const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
1072
Peter Boström0c4e06b2015-10-07 12:23:21 +02001073StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
1074 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001075 const std::string& reason)
1076 : StunAttribute(type, 0) {
1077 SetCode(code);
1078 SetReason(reason);
1079}
1080
Peter Boström0c4e06b2015-10-07 12:23:21 +02001081StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001082 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001083
Yves Gerey665174f2018-06-19 15:03:05 +02001084StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001085
Steve Antonca7d54e2017-10-25 14:42:51 -07001086StunAttributeValueType StunErrorCodeAttribute::value_type() const {
1087 return STUN_VALUE_ERROR_CODE;
1088}
1089
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001090int StunErrorCodeAttribute::code() const {
1091 return class_ * 100 + number_;
1092}
1093
1094void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001095 class_ = static_cast<uint8_t>(code / 100);
1096 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001097}
1098
1099void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001100 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001101 reason_ = reason;
1102}
1103
jbauchf1f87202016-03-30 06:43:37 -07001104bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001105 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001106 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
1107 return false;
1108
1109 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +01001110 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001111
1112 class_ = ((val >> 8) & 0x7);
1113 number_ = (val & 0xff);
1114
1115 if (!buf->ReadString(&reason_, length() - 4))
1116 return false;
1117
1118 ConsumePadding(buf);
1119 return true;
1120}
1121
jbauchf1f87202016-03-30 06:43:37 -07001122bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001123 buf->WriteUInt32(class_ << 8 | number_);
1124 buf->WriteString(reason_);
1125 WritePadding(buf);
1126 return true;
1127}
1128
Peter Boström0c4e06b2015-10-07 12:23:21 +02001129StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001130 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001131 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001132}
1133
1134StunUInt16ListAttribute::~StunUInt16ListAttribute() {
1135 delete attr_types_;
1136}
1137
Steve Antonca7d54e2017-10-25 14:42:51 -07001138StunAttributeValueType StunUInt16ListAttribute::value_type() const {
1139 return STUN_VALUE_UINT16_LIST;
1140}
1141
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001142size_t StunUInt16ListAttribute::Size() const {
1143 return attr_types_->size();
1144}
1145
Peter Boström0c4e06b2015-10-07 12:23:21 +02001146uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001147 return (*attr_types_)[index];
1148}
1149
Peter Boström0c4e06b2015-10-07 12:23:21 +02001150void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001151 (*attr_types_)[index] = value;
1152}
1153
Peter Boström0c4e06b2015-10-07 12:23:21 +02001154void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001155 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001156 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001157}
1158
Jonas Oreland63737a92019-11-21 15:12:14 +01001159void StunUInt16ListAttribute::AddTypeAtIndex(uint16_t index, uint16_t value) {
1160 if (attr_types_->size() < static_cast<size_t>(index + 1)) {
1161 attr_types_->resize(index + 1);
1162 }
1163 (*attr_types_)[index] = value;
1164 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
1165}
1166
jbauchf1f87202016-03-30 06:43:37 -07001167bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +01001168 if (length() % 2) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001169 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +01001170 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001171
1172 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001173 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001174 if (!buf->ReadUInt16(&attr))
1175 return false;
1176 attr_types_->push_back(attr);
1177 }
1178 // Padding of these attributes is done in RFC 5389 style. This is
1179 // slightly different from RFC3489, but it shouldn't be important.
1180 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
1181 // entries in the list (not necessarily the last one - it's unspecified).
1182 // RFC5389 pads on the end, and the bytes are always ignored.
1183 ConsumePadding(buf);
1184 return true;
1185}
1186
jbauchf1f87202016-03-30 06:43:37 -07001187bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001188 for (size_t i = 0; i < attr_types_->size(); ++i) {
1189 buf->WriteUInt16((*attr_types_)[i]);
1190 }
1191 WritePadding(buf);
1192 return true;
1193}
1194
Jonas Oreland9a52bd72019-12-11 11:35:48 +01001195std::string StunMethodToString(int msg_type) {
1196 switch (msg_type) {
1197 case STUN_BINDING_REQUEST:
1198 return "STUN BINDING request";
1199 case STUN_BINDING_INDICATION:
1200 return "STUN BINDING indication";
1201 case STUN_BINDING_RESPONSE:
1202 return "STUN BINDING response";
1203 case STUN_BINDING_ERROR_RESPONSE:
1204 return "STUN BINDING error response";
1205 case GOOG_PING_REQUEST:
1206 return "GOOG PING request";
1207 case GOOG_PING_RESPONSE:
1208 return "GOOG PING response";
1209 case GOOG_PING_ERROR_RESPONSE:
1210 return "GOOG PING error response";
1211 case STUN_ALLOCATE_REQUEST:
1212 return "TURN ALLOCATE request";
1213 case STUN_ALLOCATE_RESPONSE:
1214 return "TURN ALLOCATE response";
1215 case STUN_ALLOCATE_ERROR_RESPONSE:
1216 return "TURN ALLOCATE error response";
1217 case TURN_REFRESH_REQUEST:
1218 return "TURN REFRESH request";
1219 case TURN_REFRESH_RESPONSE:
1220 return "TURN REFRESH response";
1221 case TURN_REFRESH_ERROR_RESPONSE:
1222 return "TURN REFRESH error response";
1223 case TURN_SEND_INDICATION:
1224 return "TURN SEND INDICATION";
1225 case TURN_DATA_INDICATION:
1226 return "TURN DATA INDICATION";
1227 case TURN_CREATE_PERMISSION_REQUEST:
1228 return "TURN CREATE PERMISSION request";
1229 case TURN_CREATE_PERMISSION_RESPONSE:
1230 return "TURN CREATE PERMISSION response";
1231 case TURN_CREATE_PERMISSION_ERROR_RESPONSE:
1232 return "TURN CREATE PERMISSION error response";
1233 case TURN_CHANNEL_BIND_REQUEST:
1234 return "TURN CHANNEL BIND request";
1235 case TURN_CHANNEL_BIND_RESPONSE:
1236 return "TURN CHANNEL BIND response";
1237 case TURN_CHANNEL_BIND_ERROR_RESPONSE:
1238 return "TURN CHANNEL BIND error response";
1239 default:
1240 return "UNKNOWN<" + std::to_string(msg_type) + ">";
1241 }
1242}
1243
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001244int GetStunSuccessResponseType(int req_type) {
1245 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
1246}
1247
1248int GetStunErrorResponseType(int req_type) {
1249 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
1250}
1251
1252bool IsStunRequestType(int msg_type) {
1253 return ((msg_type & kStunTypeMask) == 0x000);
1254}
1255
1256bool IsStunIndicationType(int msg_type) {
1257 return ((msg_type & kStunTypeMask) == 0x010);
1258}
1259
1260bool IsStunSuccessResponseType(int msg_type) {
1261 return ((msg_type & kStunTypeMask) == 0x100);
1262}
1263
1264bool IsStunErrorResponseType(int msg_type) {
1265 return ((msg_type & kStunTypeMask) == 0x110);
1266}
1267
1268bool ComputeStunCredentialHash(const std::string& username,
1269 const std::string& realm,
1270 const std::string& password,
1271 std::string* hash) {
1272 // http://tools.ietf.org/html/rfc5389#section-15.4
1273 // long-term credentials will be calculated using the key and key is
1274 // key = MD5(username ":" realm ":" SASLprep(password))
1275 std::string input = username;
1276 input += ':';
1277 input += realm;
1278 input += ':';
1279 input += password;
1280
1281 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001282 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1283 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001284 if (size == 0) {
1285 return false;
1286 }
1287
1288 *hash = std::string(digest, size);
1289 return true;
1290}
1291
Jonas Oreland202994c2017-12-18 12:10:43 +01001292std::unique_ptr<StunAttribute> CopyStunAttribute(
1293 const StunAttribute& attribute,
1294 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1295 ByteBufferWriter tmpBuffer;
1296 if (tmp_buffer_ptr == nullptr) {
1297 tmp_buffer_ptr = &tmpBuffer;
1298 }
1299
Yves Gerey665174f2018-06-19 15:03:05 +02001300 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1301 attribute.value_type(), attribute.type(),
1302 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001303
1304 if (!copy) {
1305 return nullptr;
1306 }
1307 tmp_buffer_ptr->Clear();
1308 if (!attribute.Write(tmp_buffer_ptr)) {
1309 return nullptr;
1310 }
1311 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1312 if (!copy->Read(&reader)) {
1313 return nullptr;
1314 }
1315
1316 return copy;
1317}
1318
Steve Antonca7d54e2017-10-25 14:42:51 -07001319StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1320 switch (type) {
1321 case STUN_ATTR_LIFETIME:
1322 return STUN_VALUE_UINT32;
1323 case STUN_ATTR_MAGIC_COOKIE:
1324 return STUN_VALUE_BYTE_STRING;
1325 case STUN_ATTR_BANDWIDTH:
1326 return STUN_VALUE_UINT32;
1327 case STUN_ATTR_DESTINATION_ADDRESS:
1328 return STUN_VALUE_ADDRESS;
1329 case STUN_ATTR_SOURCE_ADDRESS2:
1330 return STUN_VALUE_ADDRESS;
1331 case STUN_ATTR_DATA:
1332 return STUN_VALUE_BYTE_STRING;
1333 case STUN_ATTR_OPTIONS:
1334 return STUN_VALUE_UINT32;
1335 default:
1336 return StunMessage::GetAttributeValueType(type);
1337 }
1338}
1339
1340StunMessage* RelayMessage::CreateNew() const {
1341 return new RelayMessage();
1342}
1343
1344StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1345 switch (type) {
1346 case STUN_ATTR_CHANNEL_NUMBER:
1347 return STUN_VALUE_UINT32;
1348 case STUN_ATTR_TURN_LIFETIME:
1349 return STUN_VALUE_UINT32;
1350 case STUN_ATTR_XOR_PEER_ADDRESS:
1351 return STUN_VALUE_XOR_ADDRESS;
1352 case STUN_ATTR_DATA:
1353 return STUN_VALUE_BYTE_STRING;
1354 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1355 return STUN_VALUE_XOR_ADDRESS;
1356 case STUN_ATTR_EVEN_PORT:
1357 return STUN_VALUE_BYTE_STRING;
1358 case STUN_ATTR_REQUESTED_TRANSPORT:
1359 return STUN_VALUE_UINT32;
1360 case STUN_ATTR_DONT_FRAGMENT:
1361 return STUN_VALUE_BYTE_STRING;
1362 case STUN_ATTR_RESERVATION_TOKEN:
1363 return STUN_VALUE_BYTE_STRING;
1364 default:
1365 return StunMessage::GetAttributeValueType(type);
1366 }
1367}
1368
1369StunMessage* TurnMessage::CreateNew() const {
1370 return new TurnMessage();
1371}
1372
1373StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1374 switch (type) {
1375 case STUN_ATTR_PRIORITY:
Jonas Orelandfa543642020-09-16 10:44:54 +02001376 case STUN_ATTR_GOOG_NETWORK_INFO:
Steve Antonca7d54e2017-10-25 14:42:51 -07001377 case STUN_ATTR_NOMINATION:
1378 return STUN_VALUE_UINT32;
1379 case STUN_ATTR_USE_CANDIDATE:
1380 return STUN_VALUE_BYTE_STRING;
1381 case STUN_ATTR_ICE_CONTROLLED:
1382 return STUN_VALUE_UINT64;
1383 case STUN_ATTR_ICE_CONTROLLING:
1384 return STUN_VALUE_UINT64;
1385 default:
1386 return StunMessage::GetAttributeValueType(type);
1387 }
1388}
1389
1390StunMessage* IceMessage::CreateNew() const {
1391 return new IceMessage();
1392}
1393
Jonas Oreland253d50f2019-11-28 17:08:07 +01001394std::unique_ptr<StunMessage> StunMessage::Clone() const {
1395 std::unique_ptr<StunMessage> copy(CreateNew());
1396 if (!copy) {
1397 return nullptr;
1398 }
1399 rtc::ByteBufferWriter buf;
1400 if (!Write(&buf)) {
1401 return nullptr;
1402 }
1403 rtc::ByteBufferReader reader(buf);
1404 if (!copy->Read(&reader)) {
1405 return nullptr;
1406 }
1407 return copy;
1408}
1409
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001410} // namespace cricket