blob: e7cb5ed0f70f622e653bb57aef2e35d33f63f053 [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"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000027
jbauchf1f87202016-03-30 06:43:37 -070028using rtc::ByteBufferReader;
29using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000030
Harald Alvestrandbee64082020-11-12 11:17:41 +000031namespace cricket {
32
Zach Stein92c42892018-11-28 11:38:52 -080033namespace {
34
Harald Alvestrandbee64082020-11-12 11:17:41 +000035const int k127Utf8CharactersLengthInBytes = 508;
Harald Alvestrandbee64082020-11-12 11:17:41 +000036const int kMessageIntegrityAttributeLength = 20;
Harald Alvestrand837f13c2020-12-04 07:52:22 +000037const int kTheoreticalMaximumAttributeLength = 65535;
Harald Alvestrandbee64082020-11-12 11:17:41 +000038
Tommi408143d2022-06-01 15:29:31 +020039uint32_t ReduceTransactionId(absl::string_view transaction_id) {
Zach Stein92c42892018-11-28 11:38:52 -080040 RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
Tommi408143d2022-06-01 15:29:31 +020041 transaction_id.length() == cricket::kStunLegacyTransactionIdLength)
42 << transaction_id.length();
43 ByteBufferReader reader(transaction_id.data(), transaction_id.size());
Zach Stein92c42892018-11-28 11:38:52 -080044 uint32_t result = 0;
Zach Steinff71a492018-12-07 11:25:12 -080045 uint32_t next;
46 while (reader.ReadUInt32(&next)) {
47 result ^= next;
Zach Stein92c42892018-11-28 11:38:52 -080048 }
49 return result;
50}
51
Harald Alvestrandbee64082020-11-12 11:17:41 +000052// Check the maximum length of a BYTE_STRING attribute against specifications.
53bool LengthValid(int type, int length) {
54 // "Less than 509 bytes" is intended to indicate a maximum of 127
55 // UTF-8 characters, which may take up to 4 bytes per character.
56 switch (type) {
57 case STUN_ATTR_USERNAME:
58 return length <=
59 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.3
60 case STUN_ATTR_MESSAGE_INTEGRITY:
61 return length ==
62 kMessageIntegrityAttributeLength; // RFC 8489 section 14.5
63 case STUN_ATTR_REALM:
64 return length <=
65 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.9
66 case STUN_ATTR_NONCE:
67 return length <=
68 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.10
69 case STUN_ATTR_SOFTWARE:
70 return length <=
71 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.14
Harald Alvestrandbee64082020-11-12 11:17:41 +000072 case STUN_ATTR_DATA:
73 // No length restriction in RFC; it's the content of an UDP datagram,
74 // which in theory can be up to 65.535 bytes.
75 // TODO(bugs.webrtc.org/12179): Write a test to find the real limit.
Harald Alvestrand837f13c2020-12-04 07:52:22 +000076 return length <= kTheoreticalMaximumAttributeLength;
Harald Alvestrandbee64082020-11-12 11:17:41 +000077 default:
78 // Return an arbitrary restriction for all other types.
Harald Alvestrand837f13c2020-12-04 07:52:22 +000079 return length <= kTheoreticalMaximumAttributeLength;
Harald Alvestrandbee64082020-11-12 11:17:41 +000080 }
Artem Titovd3251962021-11-15 16:57:07 +010081 RTC_DCHECK_NOTREACHED();
Harald Alvestrandbee64082020-11-12 11:17:41 +000082 return true;
83}
Zach Stein92c42892018-11-28 11:38:52 -080084
Harald Alvestrandbee64082020-11-12 11:17:41 +000085} // namespace
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000086
87const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
88const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
89const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -070090const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[] = "Unknown Attribute";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000091const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000092const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
93const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
94const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
95const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
96const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
97const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
98
Yves Gerey665174f2018-06-19 15:03:05 +020099const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000100const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200101const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
Eldar Relloda13ea22019-06-01 12:23:43 +0300102const int SERVER_NOT_REACHABLE_ERROR = 701;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000103
104// StunMessage
105
106StunMessage::StunMessage()
Tommi408143d2022-06-01 15:29:31 +0200107 : StunMessage(STUN_INVALID_MESSAGE_TYPE, EMPTY_TRANSACTION_ID) {}
108
109StunMessage::StunMessage(uint16_t type)
110 : StunMessage(type, GenerateTransactionId()) {}
111
112StunMessage::StunMessage(uint16_t type, absl::string_view transaction_id)
113 : type_(type),
114 transaction_id_(transaction_id),
115 reduced_transaction_id_(ReduceTransactionId(transaction_id_)) {
nisseede5da42017-01-12 05:15:36 -0800116 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000117}
118
Steve Antonca7d54e2017-10-25 14:42:51 -0700119StunMessage::~StunMessage() = default;
120
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000121bool StunMessage::IsLegacy() const {
122 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
123 return true;
nisseede5da42017-01-12 05:15:36 -0800124 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000125 return false;
126}
127
Jonas Oreland16ccef72018-03-27 09:02:43 +0200128static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200129 return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
130 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200131}
132
zsteinf42cc9d2017-03-27 16:17:19 -0700133void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200134 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +0200135 // but allow any type for the range that in the RFC is reserved for
136 // the "designated experts".
137 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200138 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
139 }
nissecc99bc22017-02-02 01:31:30 -0800140
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000141 attr->SetOwner(this);
142 size_t attr_length = attr->length();
143 if (attr_length % 4 != 0) {
144 attr_length += (4 - (attr_length % 4));
145 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200146 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -0700147
148 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000149}
150
Jonas Oreland202994c2017-12-18 12:10:43 +0100151std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
152 std::unique_ptr<StunAttribute> attribute;
153 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
Yves Gerey665174f2018-06-19 15:03:05 +0200154 if ((*it)->type() == type) {
155 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100156 attrs_.erase(std::next(it).base());
157 break;
158 }
159 }
160 if (attribute) {
161 attribute->SetOwner(nullptr);
162 size_t attr_length = attribute->length();
163 if (attr_length % 4 != 0) {
164 attr_length += (4 - (attr_length % 4));
165 }
166 length_ -= static_cast<uint16_t>(attr_length + 4);
167 }
168 return attribute;
169}
170
Jonas Oreland63737a92019-11-21 15:12:14 +0100171void StunMessage::ClearAttributes() {
172 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
173 (*it)->SetOwner(nullptr);
174 }
175 attrs_.clear();
176 length_ = 0;
177}
178
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700179std::vector<uint16_t> StunMessage::GetNonComprehendedAttributes() const {
180 std::vector<uint16_t> unknown_attributes;
181 for (auto& attr : attrs_) {
182 // "comprehension-required" range is 0x0000-0x7FFF.
183 if (attr->type() >= 0x0000 && attr->type() <= 0x7FFF &&
184 GetAttributeValueType(attr->type()) == STUN_VALUE_UNKNOWN) {
185 unknown_attributes.push_back(attr->type());
186 }
187 }
188 return unknown_attributes;
189}
190
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000191const StunAddressAttribute* StunMessage::GetAddress(int type) const {
192 switch (type) {
193 case STUN_ATTR_MAPPED_ADDRESS: {
194 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
195 // missing.
196 const StunAttribute* mapped_address =
197 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
198 if (!mapped_address)
199 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
200 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
201 }
202
203 default:
204 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
205 }
206}
207
208const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
209 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
210}
211
212const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
213 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
214}
215
216const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
217 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
218}
219
Jonas Oreland1721de12019-11-20 12:10:39 +0100220const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
221 return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
222}
223
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000224const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
225 return static_cast<const StunErrorCodeAttribute*>(
226 GetAttribute(STUN_ATTR_ERROR_CODE));
227}
228
deadbeef996fc6b2017-04-26 09:21:22 -0700229int StunMessage::GetErrorCodeValue() const {
230 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
231 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
232}
233
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000234const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
235 return static_cast<const StunUInt16ListAttribute*>(
236 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
237}
238
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000239StunMessage::IntegrityStatus StunMessage::ValidateMessageIntegrity(
240 const std::string& password) {
241 password_ = password;
242 if (GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
243 if (ValidateMessageIntegrityOfType(
244 STUN_ATTR_MESSAGE_INTEGRITY, kStunMessageIntegritySize,
245 buffer_.c_str(), buffer_.size(), password)) {
246 integrity_ = IntegrityStatus::kIntegrityOk;
247 } else {
248 integrity_ = IntegrityStatus::kIntegrityBad;
249 }
250 } else if (GetByteString(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32)) {
251 if (ValidateMessageIntegrityOfType(
252 STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32, kStunMessageIntegrity32Size,
253 buffer_.c_str(), buffer_.size(), password)) {
254 integrity_ = IntegrityStatus::kIntegrityOk;
255 } else {
256 integrity_ = IntegrityStatus::kIntegrityBad;
257 }
258 } else {
259 integrity_ = IntegrityStatus::kNoIntegrity;
260 }
261 return integrity_;
262}
263
Yves Gerey665174f2018-06-19 15:03:05 +0200264bool StunMessage::ValidateMessageIntegrity(const char* data,
265 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000266 const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100267 return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
268 kStunMessageIntegritySize, data, size,
269 password);
270}
271
272bool StunMessage::ValidateMessageIntegrity32(const char* data,
273 size_t size,
274 const std::string& password) {
275 return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
276 kStunMessageIntegrity32Size, data, size,
277 password);
278}
279
280// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
281// procedure outlined in RFC 5389, section 15.4.
282bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
283 size_t mi_attr_size,
284 const char* data,
285 size_t size,
286 const std::string& password) {
287 RTC_DCHECK(mi_attr_size <= kStunMessageIntegritySize);
288
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000289 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700290 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000291 return false;
292 }
293
294 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200295 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000296 if (size != (msg_length + kStunHeaderSize)) {
297 return false;
298 }
299
300 // Finding Message Integrity attribute in stun message.
301 size_t current_pos = kStunHeaderSize;
302 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700303 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200304 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000305 // Getting attribute type and length.
306 attr_type = rtc::GetBE16(&data[current_pos]);
307 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
308
309 // If M-I, sanity check it, and break out.
Jonas Oreland63737a92019-11-21 15:12:14 +0100310 if (attr_type == mi_attr_type) {
311 if (attr_length != mi_attr_size ||
katrielc1a206102016-06-20 05:13:16 -0700312 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
313 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000314 return false;
315 }
316 has_message_integrity_attr = true;
317 break;
318 }
319
320 // Otherwise, skip to the next attribute.
321 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
322 if ((attr_length % 4) != 0) {
323 current_pos += (4 - (attr_length % 4));
324 }
325 }
326
327 if (!has_message_integrity_attr) {
328 return false;
329 }
330
331 // Getting length of the message to calculate Message Integrity.
332 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700333 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000334 memcpy(temp_data.get(), data, current_pos);
Jonas Oreland63737a92019-11-21 15:12:14 +0100335 if (size > mi_pos + kStunAttributeHeaderSize + mi_attr_size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000336 // Stun message has other attributes after message integrity.
337 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200338 size_t extra_offset =
Jonas Oreland63737a92019-11-21 15:12:14 +0100339 size - (mi_pos + kStunAttributeHeaderSize + mi_attr_size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000340 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
341
342 // Writing new length of the STUN message @ Message Length in temp buffer.
343 // 0 1 2 3
344 // 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
345 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
346 // |0 0| STUN Message Type | Message Length |
347 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200348 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000349 }
350
351 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200352 size_t ret =
353 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
354 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800355 RTC_DCHECK(ret == sizeof(hmac));
Jonas Oreland63737a92019-11-21 15:12:14 +0100356 if (ret != sizeof(hmac)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000357 return false;
Jonas Oreland63737a92019-11-21 15:12:14 +0100358 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000359
360 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200361 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
Jonas Oreland63737a92019-11-21 15:12:14 +0100362 mi_attr_size) == 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000363}
364
Tommie83500e2022-06-03 14:28:59 +0200365bool StunMessage::AddMessageIntegrity(absl::string_view password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100366 return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
Tommie83500e2022-06-03 14:28:59 +0200367 kStunMessageIntegritySize, password);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000368}
369
Jonas Oreland63737a92019-11-21 15:12:14 +0100370bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
371 return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
Tommie83500e2022-06-03 14:28:59 +0200372 kStunMessageIntegrity32Size, password);
Jonas Oreland63737a92019-11-21 15:12:14 +0100373}
374
375bool StunMessage::AddMessageIntegrityOfType(int attr_type,
376 size_t attr_size,
Tommie83500e2022-06-03 14:28:59 +0200377 absl::string_view key) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000378 // Add the attribute with a dummy value. Since this is a known attribute, it
379 // can't fail.
Jonas Oreland63737a92019-11-21 15:12:14 +0100380 RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200381 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
Jonas Oreland63737a92019-11-21 15:12:14 +0100382 attr_type, std::string(attr_size, '0'));
zsteinf42cc9d2017-03-27 16:17:19 -0700383 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
384 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000385
386 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700387 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000388 if (!Write(&buf))
389 return false;
390
391 int msg_len_for_hmac = static_cast<int>(
392 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
393 char hmac[kStunMessageIntegritySize];
Tommie83500e2022-06-03 14:28:59 +0200394 size_t ret =
395 rtc::ComputeHmac(rtc::DIGEST_SHA_1, key.data(), key.size(), buf.Data(),
396 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800397 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000398 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100399 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200400 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000401 return false;
402 }
403
404 // Insert correct HMAC into the attribute.
Jonas Oreland63737a92019-11-21 15:12:14 +0100405 msg_integrity_attr->CopyBytes(hmac, attr_size);
Tommie83500e2022-06-03 14:28:59 +0200406 password_ = std::string(key);
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000407 integrity_ = IntegrityStatus::kIntegrityOk;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000408 return true;
409}
410
411// Verifies a message is in fact a STUN message, by performing the checks
412// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
413// in section 15.5.
414bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
415 // Check the message length.
416 size_t fingerprint_attr_size =
417 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
418 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
419 return false;
420
421 // Skip the rest if the magic cookie isn't present.
422 const char* magic_cookie =
423 data + kStunTransactionIdOffset - kStunMagicCookieLength;
424 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
425 return false;
426
427 // Check the fingerprint type and length.
428 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
429 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200430 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000431 StunUInt32Attribute::SIZE)
432 return false;
433
434 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200435 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000436 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
437 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200438 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000439}
440
Tommi408143d2022-06-01 15:29:31 +0200441// static
442std::string StunMessage::GenerateTransactionId() {
443 return rtc::CreateRandomString(kStunTransactionIdLength);
444}
445
Jonas Oreland253d50f2019-11-28 17:08:07 +0100446bool StunMessage::IsStunMethod(rtc::ArrayView<int> methods,
447 const char* data,
448 size_t size) {
449 // Check the message length.
450 if (size % 4 != 0 || size < kStunHeaderSize)
451 return false;
452
453 // Skip the rest if the magic cookie isn't present.
454 const char* magic_cookie =
455 data + kStunTransactionIdOffset - kStunMagicCookieLength;
456 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
457 return false;
458
459 int method = rtc::GetBE16(data);
460 for (int m : methods) {
461 if (m == method) {
462 return true;
463 }
464 }
465 return false;
466}
467
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000468bool StunMessage::AddFingerprint() {
469 // Add the attribute with a dummy value. Since this is a known attribute,
470 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700471 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200472 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700473 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700474 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000475
476 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700477 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000478 if (!Write(&buf))
479 return false;
480
481 int msg_len_for_crc32 = static_cast<int>(
482 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200483 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000484
485 // Insert the correct CRC-32, XORed with a constant, into the attribute.
486 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
487 return true;
488}
489
jbauchf1f87202016-03-30 06:43:37 -0700490bool StunMessage::Read(ByteBufferReader* buf) {
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000491 // Keep a copy of the buffer data around for later verification.
492 buffer_.assign(buf->Data(), buf->Length());
493
Jonas Oreland1721de12019-11-20 12:10:39 +0100494 if (!buf->ReadUInt16(&type_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000495 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100496 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000497
498 if (type_ & 0x8000) {
499 // RTP and RTCP set the MSB of first byte, since first two bits are version,
500 // and version is always 2 (10). If set, this is not a STUN packet.
501 return false;
502 }
503
Jonas Oreland1721de12019-11-20 12:10:39 +0100504 if (!buf->ReadUInt16(&length_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000505 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100506 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000507
508 std::string magic_cookie;
Jonas Oreland1721de12019-11-20 12:10:39 +0100509 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000510 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100511 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000512
513 std::string transaction_id;
Jonas Oreland1721de12019-11-20 12:10:39 +0100514 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000515 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100516 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000517
Andrew Royes154d8392019-03-14 10:38:31 -0700518 uint32_t magic_cookie_int;
519 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
520 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
521 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000522 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
523 // If magic cookie is invalid it means that the peer implements
524 // RFC3489 instead of RFC5389.
525 transaction_id.insert(0, magic_cookie);
526 }
nisseede5da42017-01-12 05:15:36 -0800527 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000528 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800529 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000530
Jonas Oreland1721de12019-11-20 12:10:39 +0100531 if (length_ != buf->Length()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000532 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100533 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000534
zsteinad94c4c2017-03-06 13:36:05 -0800535 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000536
537 size_t rest = buf->Length() - length_;
538 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200539 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000540 if (!buf->ReadUInt16(&attr_type))
541 return false;
542 if (!buf->ReadUInt16(&attr_length))
543 return false;
544
Honghai Zhang3e024302016-09-22 09:52:16 -0700545 std::unique_ptr<StunAttribute> attr(
546 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000547 if (!attr) {
548 // Skip any unknown or malformed attributes.
549 if ((attr_length % 4) != 0) {
550 attr_length += (4 - (attr_length % 4));
551 }
Jonas Oreland1721de12019-11-20 12:10:39 +0100552 if (!buf->Consume(attr_length)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000553 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100554 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000555 } else {
Jonas Oreland1721de12019-11-20 12:10:39 +0100556 if (!attr->Read(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000557 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100558 }
zsteinad94c4c2017-03-06 13:36:05 -0800559 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000560 }
561 }
562
nisseede5da42017-01-12 05:15:36 -0800563 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564 return true;
565}
566
jbauchf1f87202016-03-30 06:43:37 -0700567bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000568 buf->WriteUInt16(type_);
569 buf->WriteUInt16(length_);
570 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100571 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000572 buf->WriteString(transaction_id_);
573
zsteinad94c4c2017-03-06 13:36:05 -0800574 for (const auto& attr : attrs_) {
575 buf->WriteUInt16(attr->type());
576 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
577 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000578 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800579 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000580 }
581
582 return true;
583}
584
Steve Antonca7d54e2017-10-25 14:42:51 -0700585StunMessage* StunMessage::CreateNew() const {
586 return new StunMessage();
587}
588
Jonas Oreland7ca63112018-02-27 08:45:13 +0100589void StunMessage::SetStunMagicCookie(uint32_t val) {
590 stun_magic_cookie_ = val;
591}
592
Tommi408143d2022-06-01 15:29:31 +0200593void StunMessage::SetTransactionIdForTesting(absl::string_view transaction_id) {
594 RTC_DCHECK(IsValidTransactionId(transaction_id));
595 transaction_id_ = std::string(transaction_id);
596 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
597}
598
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000599StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
600 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200601 case STUN_ATTR_MAPPED_ADDRESS:
602 return STUN_VALUE_ADDRESS;
603 case STUN_ATTR_USERNAME:
604 return STUN_VALUE_BYTE_STRING;
605 case STUN_ATTR_MESSAGE_INTEGRITY:
606 return STUN_VALUE_BYTE_STRING;
607 case STUN_ATTR_ERROR_CODE:
608 return STUN_VALUE_ERROR_CODE;
609 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
610 return STUN_VALUE_UINT16_LIST;
611 case STUN_ATTR_REALM:
612 return STUN_VALUE_BYTE_STRING;
613 case STUN_ATTR_NONCE:
614 return STUN_VALUE_BYTE_STRING;
615 case STUN_ATTR_XOR_MAPPED_ADDRESS:
616 return STUN_VALUE_XOR_ADDRESS;
617 case STUN_ATTR_SOFTWARE:
618 return STUN_VALUE_BYTE_STRING;
619 case STUN_ATTR_ALTERNATE_SERVER:
620 return STUN_VALUE_ADDRESS;
621 case STUN_ATTR_FINGERPRINT:
622 return STUN_VALUE_UINT32;
Yves Gerey665174f2018-06-19 15:03:05 +0200623 case STUN_ATTR_RETRANSMIT_COUNT:
624 return STUN_VALUE_UINT32;
Jonas Orelandfa543642020-09-16 10:44:54 +0200625 case STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED:
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700626 return STUN_VALUE_BYTE_STRING;
Jonas Oreland1721de12019-11-20 12:10:39 +0100627 case STUN_ATTR_GOOG_MISC_INFO:
628 return STUN_VALUE_UINT16_LIST;
Yves Gerey665174f2018-06-19 15:03:05 +0200629 default:
630 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000631 }
632}
633
634StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
635 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200636 if (value_type != STUN_VALUE_UNKNOWN) {
637 return StunAttribute::Create(value_type, type,
638 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200639 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200640 // Read unknown attributes as STUN_VALUE_BYTE_STRING
641 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
642 static_cast<uint16_t>(length), this);
643 } else {
644 return NULL;
645 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000646}
647
648const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800649 for (const auto& attr : attrs_) {
650 if (attr->type() == type) {
651 return attr.get();
652 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000653 }
654 return NULL;
655}
656
Tommi408143d2022-06-01 15:29:31 +0200657bool StunMessage::IsValidTransactionId(absl::string_view transaction_id) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000658 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200659 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000660}
661
Jonas Oreland253d50f2019-11-28 17:08:07 +0100662bool StunMessage::EqualAttributes(
663 const StunMessage* other,
664 std::function<bool(int type)> attribute_type_mask) const {
665 RTC_DCHECK(other != nullptr);
666 rtc::ByteBufferWriter tmp_buffer_ptr1;
667 rtc::ByteBufferWriter tmp_buffer_ptr2;
668 for (const auto& attr : attrs_) {
669 if (attribute_type_mask(attr->type())) {
670 const StunAttribute* other_attr = other->GetAttribute(attr->type());
671 if (other_attr == nullptr) {
672 return false;
673 }
674 tmp_buffer_ptr1.Clear();
675 tmp_buffer_ptr2.Clear();
676 attr->Write(&tmp_buffer_ptr1);
677 other_attr->Write(&tmp_buffer_ptr2);
678 if (tmp_buffer_ptr1.Length() != tmp_buffer_ptr2.Length()) {
679 return false;
680 }
681 if (memcmp(tmp_buffer_ptr1.Data(), tmp_buffer_ptr2.Data(),
682 tmp_buffer_ptr1.Length()) != 0) {
683 return false;
684 }
685 }
686 }
687
688 for (const auto& attr : other->attrs_) {
689 if (attribute_type_mask(attr->type())) {
690 const StunAttribute* own_attr = GetAttribute(attr->type());
691 if (own_attr == nullptr) {
692 return false;
693 }
694 // we have already compared all values...
695 }
696 }
697 return true;
698}
699
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000700// StunAttribute
701
Peter Boström0c4e06b2015-10-07 12:23:21 +0200702StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200703 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000704
jbauchf1f87202016-03-30 06:43:37 -0700705void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000706 int remainder = length_ % 4;
707 if (remainder > 0) {
708 buf->Consume(4 - remainder);
709 }
710}
711
jbauchf1f87202016-03-30 06:43:37 -0700712void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000713 int remainder = length_ % 4;
714 if (remainder > 0) {
715 char zeroes[4] = {0};
716 buf->WriteBytes(zeroes, 4 - remainder);
717 }
718}
719
720StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200721 uint16_t type,
722 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000723 StunMessage* owner) {
724 switch (value_type) {
725 case STUN_VALUE_ADDRESS:
726 return new StunAddressAttribute(type, length);
727 case STUN_VALUE_XOR_ADDRESS:
728 return new StunXorAddressAttribute(type, length, owner);
729 case STUN_VALUE_UINT32:
730 return new StunUInt32Attribute(type);
731 case STUN_VALUE_UINT64:
732 return new StunUInt64Attribute(type);
733 case STUN_VALUE_BYTE_STRING:
734 return new StunByteStringAttribute(type, length);
735 case STUN_VALUE_ERROR_CODE:
736 return new StunErrorCodeAttribute(type, length);
737 case STUN_VALUE_UINT16_LIST:
738 return new StunUInt16ListAttribute(type, length);
739 default:
740 return NULL;
741 }
742}
743
zsteinf42cc9d2017-03-27 16:17:19 -0700744std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
745 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200746 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000747}
748
zsteinf42cc9d2017-03-27 16:17:19 -0700749std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
750 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200751 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000752}
753
zsteinf42cc9d2017-03-27 16:17:19 -0700754std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
755 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200756 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000757}
758
zsteinf42cc9d2017-03-27 16:17:19 -0700759std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
760 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200761 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000762}
763
zsteinf42cc9d2017-03-27 16:17:19 -0700764std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
765 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200766 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000767}
768
zsteinf42cc9d2017-03-27 16:17:19 -0700769std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200770 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000771 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
772}
773
zsteinf42cc9d2017-03-27 16:17:19 -0700774std::unique_ptr<StunUInt16ListAttribute>
Jonas Oreland1721de12019-11-20 12:10:39 +0100775StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
776 return std::make_unique<StunUInt16ListAttribute>(type, 0);
777}
778
779std::unique_ptr<StunUInt16ListAttribute>
zsteinf42cc9d2017-03-27 16:17:19 -0700780StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200781 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
782 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000783}
784
Peter Boström0c4e06b2015-10-07 12:23:21 +0200785StunAddressAttribute::StunAddressAttribute(uint16_t type,
786 const rtc::SocketAddress& addr)
787 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000788 SetAddress(addr);
789}
790
Peter Boström0c4e06b2015-10-07 12:23:21 +0200791StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200792 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000793
Steve Antonca7d54e2017-10-25 14:42:51 -0700794StunAttributeValueType StunAddressAttribute::value_type() const {
795 return STUN_VALUE_ADDRESS;
796}
797
jbauchf1f87202016-03-30 06:43:37 -0700798bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200799 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000800 if (!buf->ReadUInt8(&dummy))
801 return false;
802
Peter Boström0c4e06b2015-10-07 12:23:21 +0200803 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000804 if (!buf->ReadUInt8(&stun_family)) {
805 return false;
806 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200807 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000808 if (!buf->ReadUInt16(&port))
809 return false;
810 if (stun_family == STUN_ADDRESS_IPV4) {
811 in_addr v4addr;
812 if (length() != SIZE_IP4) {
813 return false;
814 }
815 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
816 return false;
817 }
818 rtc::IPAddress ipaddr(v4addr);
819 SetAddress(rtc::SocketAddress(ipaddr, port));
820 } else if (stun_family == STUN_ADDRESS_IPV6) {
821 in6_addr v6addr;
822 if (length() != SIZE_IP6) {
823 return false;
824 }
825 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
826 return false;
827 }
828 rtc::IPAddress ipaddr(v6addr);
829 SetAddress(rtc::SocketAddress(ipaddr, port));
830 } else {
831 return false;
832 }
833 return true;
834}
835
jbauchf1f87202016-03-30 06:43:37 -0700836bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000837 StunAddressFamily address_family = family();
838 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100839 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000840 return false;
841 }
842 buf->WriteUInt8(0);
843 buf->WriteUInt8(address_family);
844 buf->WriteUInt16(address_.port());
845 switch (address_.family()) {
846 case AF_INET: {
847 in_addr v4addr = address_.ipaddr().ipv4_address();
848 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
849 break;
850 }
851 case AF_INET6: {
852 in6_addr v6addr = address_.ipaddr().ipv6_address();
853 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
854 break;
855 }
856 }
857 return true;
858}
859
Peter Boström0c4e06b2015-10-07 12:23:21 +0200860StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
861 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200862 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000863
Peter Boström0c4e06b2015-10-07 12:23:21 +0200864StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
865 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000866 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200867 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000868
Steve Antonca7d54e2017-10-25 14:42:51 -0700869StunAttributeValueType StunXorAddressAttribute::value_type() const {
870 return STUN_VALUE_XOR_ADDRESS;
871}
872
873void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
874 owner_ = owner;
875}
876
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000877rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
878 if (owner_) {
879 rtc::IPAddress ip = ipaddr();
880 switch (ip.family()) {
881 case AF_INET: {
882 in_addr v4addr = ip.ipv4_address();
883 v4addr.s_addr =
884 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
885 return rtc::IPAddress(v4addr);
886 }
887 case AF_INET6: {
888 in6_addr v6addr = ip.ipv6_address();
889 const std::string& transaction_id = owner_->transaction_id();
890 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200891 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000892 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
893 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200894 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000895 // Transaction ID is in network byte order, but magic cookie
896 // is stored in host byte order.
897 ip_as_ints[0] =
898 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
899 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
900 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
901 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
902 return rtc::IPAddress(v6addr);
903 }
904 break;
905 }
906 }
907 }
908 // Invalid ip family or transaction ID, or missing owner.
909 // Return an AF_UNSPEC address.
910 return rtc::IPAddress();
911}
912
jbauchf1f87202016-03-30 06:43:37 -0700913bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000914 if (!StunAddressAttribute::Read(buf))
915 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200916 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000917 rtc::IPAddress xored_ip = GetXoredIP();
918 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
919 return true;
920}
921
jbauchf1f87202016-03-30 06:43:37 -0700922bool StunXorAddressAttribute::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 xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000926 return false;
927 }
928 rtc::IPAddress xored_ip = GetXoredIP();
929 if (xored_ip.family() == AF_UNSPEC) {
930 return false;
931 }
932 buf->WriteUInt8(0);
933 buf->WriteUInt8(family());
934 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
935 switch (xored_ip.family()) {
936 case AF_INET: {
937 in_addr v4addr = xored_ip.ipv4_address();
938 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
939 break;
940 }
941 case AF_INET6: {
942 in6_addr v6addr = xored_ip.ipv6_address();
943 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
944 break;
945 }
946 }
947 return true;
948}
949
Peter Boström0c4e06b2015-10-07 12:23:21 +0200950StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200951 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000952
Peter Boström0c4e06b2015-10-07 12:23:21 +0200953StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200954 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000955
Steve Antonca7d54e2017-10-25 14:42:51 -0700956StunAttributeValueType StunUInt32Attribute::value_type() const {
957 return STUN_VALUE_UINT32;
958}
959
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000960bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800961 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000962 return static_cast<bool>((bits_ >> index) & 0x1);
963}
964
965void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800966 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000967 bits_ &= ~(1 << index);
968 bits_ |= value ? (1 << index) : 0;
969}
970
jbauchf1f87202016-03-30 06:43:37 -0700971bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000972 if (length() != SIZE || !buf->ReadUInt32(&bits_))
973 return false;
974 return true;
975}
976
jbauchf1f87202016-03-30 06:43:37 -0700977bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000978 buf->WriteUInt32(bits_);
979 return true;
980}
981
Peter Boström0c4e06b2015-10-07 12:23:21 +0200982StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200983 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000984
Peter Boström0c4e06b2015-10-07 12:23:21 +0200985StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200986 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000987
Steve Antonca7d54e2017-10-25 14:42:51 -0700988StunAttributeValueType StunUInt64Attribute::value_type() const {
989 return STUN_VALUE_UINT64;
990}
991
jbauchf1f87202016-03-30 06:43:37 -0700992bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000993 if (length() != SIZE || !buf->ReadUInt64(&bits_))
994 return false;
995 return true;
996}
997
jbauchf1f87202016-03-30 06:43:37 -0700998bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000999 buf->WriteUInt64(bits_);
1000 return true;
1001}
1002
Peter Boström0c4e06b2015-10-07 12:23:21 +02001003StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +02001004 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001005
Peter Boström0c4e06b2015-10-07 12:23:21 +02001006StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
Tommie83500e2022-06-03 14:28:59 +02001007 absl::string_view str)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001008 : StunAttribute(type, 0), bytes_(NULL) {
Tommie83500e2022-06-03 14:28:59 +02001009 CopyBytes(str);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001010}
1011
Peter Boström0c4e06b2015-10-07 12:23:21 +02001012StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001013 const void* bytes,
1014 size_t length)
1015 : StunAttribute(type, 0), bytes_(NULL) {
1016 CopyBytes(bytes, length);
1017}
1018
Peter Boström0c4e06b2015-10-07 12:23:21 +02001019StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001020 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001021
1022StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +02001023 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001024}
1025
Steve Antonca7d54e2017-10-25 14:42:51 -07001026StunAttributeValueType StunByteStringAttribute::value_type() const {
1027 return STUN_VALUE_BYTE_STRING;
1028}
1029
Tommie83500e2022-06-03 14:28:59 +02001030void StunByteStringAttribute::CopyBytes(absl::string_view bytes) {
1031 char* new_bytes = new char[bytes.size()];
1032 memcpy(new_bytes, bytes.data(), bytes.size());
1033 SetBytes(new_bytes, bytes.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001034}
1035
1036void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
1037 char* new_bytes = new char[length];
1038 memcpy(new_bytes, bytes, length);
1039 SetBytes(new_bytes, length);
1040}
1041
Peter Boström0c4e06b2015-10-07 12:23:21 +02001042uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -08001043 RTC_DCHECK(bytes_ != NULL);
1044 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +02001045 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001046}
1047
Peter Boström0c4e06b2015-10-07 12:23:21 +02001048void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -08001049 RTC_DCHECK(bytes_ != NULL);
1050 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001051 bytes_[index] = value;
1052}
1053
jbauchf1f87202016-03-30 06:43:37 -07001054bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001055 bytes_ = new char[length()];
1056 if (!buf->ReadBytes(bytes_, length())) {
1057 return false;
1058 }
1059
1060 ConsumePadding(buf);
1061 return true;
1062}
1063
jbauchf1f87202016-03-30 06:43:37 -07001064bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
Harald Alvestrandbee64082020-11-12 11:17:41 +00001065 // Check that length is legal according to specs
1066 if (!LengthValid(type(), length())) {
1067 return false;
1068 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001069 buf->WriteBytes(bytes_, length());
1070 WritePadding(buf);
1071 return true;
1072}
1073
1074void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +02001075 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001076 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +02001077 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001078}
1079
zsteinf42cc9d2017-03-27 16:17:19 -07001080const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
1081
Peter Boström0c4e06b2015-10-07 12:23:21 +02001082StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
1083 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001084 const std::string& reason)
1085 : StunAttribute(type, 0) {
1086 SetCode(code);
1087 SetReason(reason);
1088}
1089
Peter Boström0c4e06b2015-10-07 12:23:21 +02001090StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001091 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001092
Yves Gerey665174f2018-06-19 15:03:05 +02001093StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001094
Steve Antonca7d54e2017-10-25 14:42:51 -07001095StunAttributeValueType StunErrorCodeAttribute::value_type() const {
1096 return STUN_VALUE_ERROR_CODE;
1097}
1098
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001099int StunErrorCodeAttribute::code() const {
1100 return class_ * 100 + number_;
1101}
1102
1103void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001104 class_ = static_cast<uint8_t>(code / 100);
1105 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001106}
1107
1108void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001109 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001110 reason_ = reason;
1111}
1112
jbauchf1f87202016-03-30 06:43:37 -07001113bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001114 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001115 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
1116 return false;
1117
1118 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +01001119 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001120
1121 class_ = ((val >> 8) & 0x7);
1122 number_ = (val & 0xff);
1123
1124 if (!buf->ReadString(&reason_, length() - 4))
1125 return false;
1126
1127 ConsumePadding(buf);
1128 return true;
1129}
1130
jbauchf1f87202016-03-30 06:43:37 -07001131bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001132 buf->WriteUInt32(class_ << 8 | number_);
1133 buf->WriteString(reason_);
1134 WritePadding(buf);
1135 return true;
1136}
1137
Peter Boström0c4e06b2015-10-07 12:23:21 +02001138StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001139 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001140 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001141}
1142
1143StunUInt16ListAttribute::~StunUInt16ListAttribute() {
1144 delete attr_types_;
1145}
1146
Steve Antonca7d54e2017-10-25 14:42:51 -07001147StunAttributeValueType StunUInt16ListAttribute::value_type() const {
1148 return STUN_VALUE_UINT16_LIST;
1149}
1150
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001151size_t StunUInt16ListAttribute::Size() const {
1152 return attr_types_->size();
1153}
1154
Peter Boström0c4e06b2015-10-07 12:23:21 +02001155uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001156 return (*attr_types_)[index];
1157}
1158
Peter Boström0c4e06b2015-10-07 12:23:21 +02001159void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001160 (*attr_types_)[index] = value;
1161}
1162
Peter Boström0c4e06b2015-10-07 12:23:21 +02001163void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001164 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001165 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001166}
1167
Jonas Oreland63737a92019-11-21 15:12:14 +01001168void StunUInt16ListAttribute::AddTypeAtIndex(uint16_t index, uint16_t value) {
1169 if (attr_types_->size() < static_cast<size_t>(index + 1)) {
1170 attr_types_->resize(index + 1);
1171 }
1172 (*attr_types_)[index] = value;
1173 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
1174}
1175
jbauchf1f87202016-03-30 06:43:37 -07001176bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +01001177 if (length() % 2) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001178 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +01001179 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001180
1181 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001182 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001183 if (!buf->ReadUInt16(&attr))
1184 return false;
1185 attr_types_->push_back(attr);
1186 }
1187 // Padding of these attributes is done in RFC 5389 style. This is
1188 // slightly different from RFC3489, but it shouldn't be important.
1189 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
1190 // entries in the list (not necessarily the last one - it's unspecified).
1191 // RFC5389 pads on the end, and the bytes are always ignored.
1192 ConsumePadding(buf);
1193 return true;
1194}
1195
jbauchf1f87202016-03-30 06:43:37 -07001196bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001197 for (size_t i = 0; i < attr_types_->size(); ++i) {
1198 buf->WriteUInt16((*attr_types_)[i]);
1199 }
1200 WritePadding(buf);
1201 return true;
1202}
1203
Jonas Oreland9a52bd72019-12-11 11:35:48 +01001204std::string StunMethodToString(int msg_type) {
1205 switch (msg_type) {
1206 case STUN_BINDING_REQUEST:
1207 return "STUN BINDING request";
1208 case STUN_BINDING_INDICATION:
1209 return "STUN BINDING indication";
1210 case STUN_BINDING_RESPONSE:
1211 return "STUN BINDING response";
1212 case STUN_BINDING_ERROR_RESPONSE:
1213 return "STUN BINDING error response";
1214 case GOOG_PING_REQUEST:
1215 return "GOOG PING request";
1216 case GOOG_PING_RESPONSE:
1217 return "GOOG PING response";
1218 case GOOG_PING_ERROR_RESPONSE:
1219 return "GOOG PING error response";
1220 case STUN_ALLOCATE_REQUEST:
1221 return "TURN ALLOCATE request";
1222 case STUN_ALLOCATE_RESPONSE:
1223 return "TURN ALLOCATE response";
1224 case STUN_ALLOCATE_ERROR_RESPONSE:
1225 return "TURN ALLOCATE error response";
1226 case TURN_REFRESH_REQUEST:
1227 return "TURN REFRESH request";
1228 case TURN_REFRESH_RESPONSE:
1229 return "TURN REFRESH response";
1230 case TURN_REFRESH_ERROR_RESPONSE:
1231 return "TURN REFRESH error response";
1232 case TURN_SEND_INDICATION:
1233 return "TURN SEND INDICATION";
1234 case TURN_DATA_INDICATION:
1235 return "TURN DATA INDICATION";
1236 case TURN_CREATE_PERMISSION_REQUEST:
1237 return "TURN CREATE PERMISSION request";
1238 case TURN_CREATE_PERMISSION_RESPONSE:
1239 return "TURN CREATE PERMISSION response";
1240 case TURN_CREATE_PERMISSION_ERROR_RESPONSE:
1241 return "TURN CREATE PERMISSION error response";
1242 case TURN_CHANNEL_BIND_REQUEST:
1243 return "TURN CHANNEL BIND request";
1244 case TURN_CHANNEL_BIND_RESPONSE:
1245 return "TURN CHANNEL BIND response";
1246 case TURN_CHANNEL_BIND_ERROR_RESPONSE:
1247 return "TURN CHANNEL BIND error response";
1248 default:
1249 return "UNKNOWN<" + std::to_string(msg_type) + ">";
1250 }
1251}
1252
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001253int GetStunSuccessResponseType(int req_type) {
1254 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
1255}
1256
1257int GetStunErrorResponseType(int req_type) {
1258 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
1259}
1260
1261bool IsStunRequestType(int msg_type) {
1262 return ((msg_type & kStunTypeMask) == 0x000);
1263}
1264
1265bool IsStunIndicationType(int msg_type) {
1266 return ((msg_type & kStunTypeMask) == 0x010);
1267}
1268
1269bool IsStunSuccessResponseType(int msg_type) {
1270 return ((msg_type & kStunTypeMask) == 0x100);
1271}
1272
1273bool IsStunErrorResponseType(int msg_type) {
1274 return ((msg_type & kStunTypeMask) == 0x110);
1275}
1276
1277bool ComputeStunCredentialHash(const std::string& username,
1278 const std::string& realm,
1279 const std::string& password,
1280 std::string* hash) {
1281 // http://tools.ietf.org/html/rfc5389#section-15.4
1282 // long-term credentials will be calculated using the key and key is
1283 // key = MD5(username ":" realm ":" SASLprep(password))
1284 std::string input = username;
1285 input += ':';
1286 input += realm;
1287 input += ':';
1288 input += password;
1289
1290 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001291 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1292 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001293 if (size == 0) {
1294 return false;
1295 }
1296
1297 *hash = std::string(digest, size);
1298 return true;
1299}
1300
Jonas Oreland202994c2017-12-18 12:10:43 +01001301std::unique_ptr<StunAttribute> CopyStunAttribute(
1302 const StunAttribute& attribute,
1303 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1304 ByteBufferWriter tmpBuffer;
1305 if (tmp_buffer_ptr == nullptr) {
1306 tmp_buffer_ptr = &tmpBuffer;
1307 }
1308
Yves Gerey665174f2018-06-19 15:03:05 +02001309 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1310 attribute.value_type(), attribute.type(),
1311 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001312
1313 if (!copy) {
1314 return nullptr;
1315 }
1316 tmp_buffer_ptr->Clear();
1317 if (!attribute.Write(tmp_buffer_ptr)) {
1318 return nullptr;
1319 }
1320 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1321 if (!copy->Read(&reader)) {
1322 return nullptr;
1323 }
1324
1325 return copy;
1326}
1327
Steve Antonca7d54e2017-10-25 14:42:51 -07001328StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1329 switch (type) {
1330 case STUN_ATTR_LIFETIME:
1331 return STUN_VALUE_UINT32;
1332 case STUN_ATTR_MAGIC_COOKIE:
1333 return STUN_VALUE_BYTE_STRING;
1334 case STUN_ATTR_BANDWIDTH:
1335 return STUN_VALUE_UINT32;
1336 case STUN_ATTR_DESTINATION_ADDRESS:
1337 return STUN_VALUE_ADDRESS;
1338 case STUN_ATTR_SOURCE_ADDRESS2:
1339 return STUN_VALUE_ADDRESS;
1340 case STUN_ATTR_DATA:
1341 return STUN_VALUE_BYTE_STRING;
1342 case STUN_ATTR_OPTIONS:
1343 return STUN_VALUE_UINT32;
1344 default:
1345 return StunMessage::GetAttributeValueType(type);
1346 }
1347}
1348
1349StunMessage* RelayMessage::CreateNew() const {
1350 return new RelayMessage();
1351}
1352
1353StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1354 switch (type) {
1355 case STUN_ATTR_CHANNEL_NUMBER:
1356 return STUN_VALUE_UINT32;
1357 case STUN_ATTR_TURN_LIFETIME:
1358 return STUN_VALUE_UINT32;
1359 case STUN_ATTR_XOR_PEER_ADDRESS:
1360 return STUN_VALUE_XOR_ADDRESS;
1361 case STUN_ATTR_DATA:
1362 return STUN_VALUE_BYTE_STRING;
1363 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1364 return STUN_VALUE_XOR_ADDRESS;
1365 case STUN_ATTR_EVEN_PORT:
1366 return STUN_VALUE_BYTE_STRING;
1367 case STUN_ATTR_REQUESTED_TRANSPORT:
1368 return STUN_VALUE_UINT32;
1369 case STUN_ATTR_DONT_FRAGMENT:
1370 return STUN_VALUE_BYTE_STRING;
1371 case STUN_ATTR_RESERVATION_TOKEN:
1372 return STUN_VALUE_BYTE_STRING;
1373 default:
1374 return StunMessage::GetAttributeValueType(type);
1375 }
1376}
1377
1378StunMessage* TurnMessage::CreateNew() const {
1379 return new TurnMessage();
1380}
1381
1382StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1383 switch (type) {
1384 case STUN_ATTR_PRIORITY:
Jonas Orelandfa543642020-09-16 10:44:54 +02001385 case STUN_ATTR_GOOG_NETWORK_INFO:
Steve Antonca7d54e2017-10-25 14:42:51 -07001386 case STUN_ATTR_NOMINATION:
1387 return STUN_VALUE_UINT32;
1388 case STUN_ATTR_USE_CANDIDATE:
1389 return STUN_VALUE_BYTE_STRING;
1390 case STUN_ATTR_ICE_CONTROLLED:
1391 return STUN_VALUE_UINT64;
1392 case STUN_ATTR_ICE_CONTROLLING:
1393 return STUN_VALUE_UINT64;
1394 default:
1395 return StunMessage::GetAttributeValueType(type);
1396 }
1397}
1398
1399StunMessage* IceMessage::CreateNew() const {
1400 return new IceMessage();
1401}
1402
Jonas Oreland253d50f2019-11-28 17:08:07 +01001403std::unique_ptr<StunMessage> StunMessage::Clone() const {
1404 std::unique_ptr<StunMessage> copy(CreateNew());
1405 if (!copy) {
1406 return nullptr;
1407 }
1408 rtc::ByteBufferWriter buf;
1409 if (!Write(&buf)) {
1410 return nullptr;
1411 }
1412 rtc::ByteBufferReader reader(buf);
1413 if (!copy->Read(&reader)) {
1414 return nullptr;
1415 }
1416 return copy;
1417}
1418
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001419} // namespace cricket