blob: 1b5bf0c409d93aeaef35fea59dd79c909b9b5ea1 [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;
34const int kDefaultMaxAttributeLength = 508;
35const int kMessageIntegrityAttributeLength = 20;
Harald Alvestrand837f13c2020-12-04 07:52:22 +000036const int kTheoreticalMaximumAttributeLength = 65535;
Harald Alvestrandbee64082020-11-12 11:17:41 +000037
Zach Stein92c42892018-11-28 11:38:52 -080038uint32_t ReduceTransactionId(const std::string& transaction_id) {
39 RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
40 transaction_id.length() ==
41 cricket::kStunLegacyTransactionIdLength);
Danil Chapovalov7b46e172019-11-14 17:40:23 +010042 ByteBufferReader reader(transaction_id.c_str(), transaction_id.length());
Zach Stein92c42892018-11-28 11:38:52 -080043 uint32_t result = 0;
Zach Steinff71a492018-12-07 11:25:12 -080044 uint32_t next;
45 while (reader.ReadUInt32(&next)) {
46 result ^= next;
Zach Stein92c42892018-11-28 11:38:52 -080047 }
48 return result;
49}
50
Harald Alvestrandbee64082020-11-12 11:17:41 +000051// Check the maximum length of a BYTE_STRING attribute against specifications.
52bool LengthValid(int type, int length) {
53 // "Less than 509 bytes" is intended to indicate a maximum of 127
54 // UTF-8 characters, which may take up to 4 bytes per character.
55 switch (type) {
56 case STUN_ATTR_USERNAME:
57 return length <=
58 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.3
59 case STUN_ATTR_MESSAGE_INTEGRITY:
60 return length ==
61 kMessageIntegrityAttributeLength; // RFC 8489 section 14.5
62 case STUN_ATTR_REALM:
63 return length <=
64 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.9
65 case STUN_ATTR_NONCE:
66 return length <=
67 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.10
68 case STUN_ATTR_SOFTWARE:
69 return length <=
70 k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.14
71 case STUN_ATTR_ORIGIN:
72 // 0x802F is unassigned by IANA.
73 // RESPONSE-ORIGIN is defined in RFC 5780 section 7.3, but does not
74 // specify a maximum length. It's an URL, so return an arbitrary
75 // restriction.
76 return length <= kDefaultMaxAttributeLength;
77 case STUN_ATTR_DATA:
78 // No length restriction in RFC; it's the content of an UDP datagram,
79 // which in theory can be up to 65.535 bytes.
80 // TODO(bugs.webrtc.org/12179): Write a test to find the real limit.
Harald Alvestrand837f13c2020-12-04 07:52:22 +000081 return length <= kTheoreticalMaximumAttributeLength;
Harald Alvestrandbee64082020-11-12 11:17:41 +000082 default:
83 // Return an arbitrary restriction for all other types.
Harald Alvestrand837f13c2020-12-04 07:52:22 +000084 return length <= kTheoreticalMaximumAttributeLength;
Harald Alvestrandbee64082020-11-12 11:17:41 +000085 }
86 RTC_NOTREACHED();
87 return true;
88}
Zach Stein92c42892018-11-28 11:38:52 -080089
Harald Alvestrandbee64082020-11-12 11:17:41 +000090} // namespace
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000091
92const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
93const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
94const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -070095const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[] = "Unknown Attribute";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000096const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
97const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
98const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
99const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
100const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
101const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
102const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
103const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
104
Yves Gerey665174f2018-06-19 15:03:05 +0200105const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000106const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200107const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
Eldar Relloda13ea22019-06-01 12:23:43 +0300108const int SERVER_NOT_REACHABLE_ERROR = 701;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000109
110// StunMessage
111
112StunMessage::StunMessage()
113 : type_(0),
114 length_(0),
Jonas Oreland7ca63112018-02-27 08:45:13 +0100115 transaction_id_(EMPTY_TRANSACTION_ID),
116 stun_magic_cookie_(kStunMagicCookie) {
nisseede5da42017-01-12 05:15:36 -0800117 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000118}
119
Steve Antonca7d54e2017-10-25 14:42:51 -0700120StunMessage::~StunMessage() = default;
121
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000122bool StunMessage::IsLegacy() const {
123 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
124 return true;
nisseede5da42017-01-12 05:15:36 -0800125 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000126 return false;
127}
128
129bool StunMessage::SetTransactionID(const std::string& str) {
130 if (!IsValidTransactionId(str)) {
131 return false;
132 }
133 transaction_id_ = str;
Zach Stein92c42892018-11-28 11:38:52 -0800134 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000135 return true;
136}
137
Jonas Oreland16ccef72018-03-27 09:02:43 +0200138static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200139 return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
140 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200141}
142
zsteinf42cc9d2017-03-27 16:17:19 -0700143void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200144 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +0200145 // but allow any type for the range that in the RFC is reserved for
146 // the "designated experts".
147 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200148 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
149 }
nissecc99bc22017-02-02 01:31:30 -0800150
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000151 attr->SetOwner(this);
152 size_t attr_length = attr->length();
153 if (attr_length % 4 != 0) {
154 attr_length += (4 - (attr_length % 4));
155 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200156 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -0700157
158 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000159}
160
Jonas Oreland202994c2017-12-18 12:10:43 +0100161std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
162 std::unique_ptr<StunAttribute> attribute;
163 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
Yves Gerey665174f2018-06-19 15:03:05 +0200164 if ((*it)->type() == type) {
165 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100166 attrs_.erase(std::next(it).base());
167 break;
168 }
169 }
170 if (attribute) {
171 attribute->SetOwner(nullptr);
172 size_t attr_length = attribute->length();
173 if (attr_length % 4 != 0) {
174 attr_length += (4 - (attr_length % 4));
175 }
176 length_ -= static_cast<uint16_t>(attr_length + 4);
177 }
178 return attribute;
179}
180
Jonas Oreland63737a92019-11-21 15:12:14 +0100181void StunMessage::ClearAttributes() {
182 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
183 (*it)->SetOwner(nullptr);
184 }
185 attrs_.clear();
186 length_ = 0;
187}
188
Taylor Brandstetterfb4351b2020-03-23 16:00:31 -0700189std::vector<uint16_t> StunMessage::GetNonComprehendedAttributes() const {
190 std::vector<uint16_t> unknown_attributes;
191 for (auto& attr : attrs_) {
192 // "comprehension-required" range is 0x0000-0x7FFF.
193 if (attr->type() >= 0x0000 && attr->type() <= 0x7FFF &&
194 GetAttributeValueType(attr->type()) == STUN_VALUE_UNKNOWN) {
195 unknown_attributes.push_back(attr->type());
196 }
197 }
198 return unknown_attributes;
199}
200
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000201const StunAddressAttribute* StunMessage::GetAddress(int type) const {
202 switch (type) {
203 case STUN_ATTR_MAPPED_ADDRESS: {
204 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
205 // missing.
206 const StunAttribute* mapped_address =
207 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
208 if (!mapped_address)
209 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
210 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
211 }
212
213 default:
214 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
215 }
216}
217
218const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
219 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
220}
221
222const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
223 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
224}
225
226const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
227 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
228}
229
Jonas Oreland1721de12019-11-20 12:10:39 +0100230const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
231 return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
232}
233
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000234const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
235 return static_cast<const StunErrorCodeAttribute*>(
236 GetAttribute(STUN_ATTR_ERROR_CODE));
237}
238
deadbeef996fc6b2017-04-26 09:21:22 -0700239int StunMessage::GetErrorCodeValue() const {
240 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
241 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
242}
243
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000244const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
245 return static_cast<const StunUInt16ListAttribute*>(
246 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
247}
248
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000249StunMessage::IntegrityStatus StunMessage::ValidateMessageIntegrity(
250 const std::string& password) {
251 password_ = password;
252 if (GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
253 if (ValidateMessageIntegrityOfType(
254 STUN_ATTR_MESSAGE_INTEGRITY, kStunMessageIntegritySize,
255 buffer_.c_str(), buffer_.size(), password)) {
256 integrity_ = IntegrityStatus::kIntegrityOk;
257 } else {
258 integrity_ = IntegrityStatus::kIntegrityBad;
259 }
260 } else if (GetByteString(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32)) {
261 if (ValidateMessageIntegrityOfType(
262 STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32, kStunMessageIntegrity32Size,
263 buffer_.c_str(), buffer_.size(), password)) {
264 integrity_ = IntegrityStatus::kIntegrityOk;
265 } else {
266 integrity_ = IntegrityStatus::kIntegrityBad;
267 }
268 } else {
269 integrity_ = IntegrityStatus::kNoIntegrity;
270 }
271 return integrity_;
272}
273
Yves Gerey665174f2018-06-19 15:03:05 +0200274bool StunMessage::ValidateMessageIntegrity(const char* data,
275 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000276 const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100277 return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
278 kStunMessageIntegritySize, data, size,
279 password);
280}
281
282bool StunMessage::ValidateMessageIntegrity32(const char* data,
283 size_t size,
284 const std::string& password) {
285 return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
286 kStunMessageIntegrity32Size, data, size,
287 password);
288}
289
290// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
291// procedure outlined in RFC 5389, section 15.4.
292bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
293 size_t mi_attr_size,
294 const char* data,
295 size_t size,
296 const std::string& password) {
297 RTC_DCHECK(mi_attr_size <= kStunMessageIntegritySize);
298
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000299 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700300 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000301 return false;
302 }
303
304 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200305 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000306 if (size != (msg_length + kStunHeaderSize)) {
307 return false;
308 }
309
310 // Finding Message Integrity attribute in stun message.
311 size_t current_pos = kStunHeaderSize;
312 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700313 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200314 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000315 // Getting attribute type and length.
316 attr_type = rtc::GetBE16(&data[current_pos]);
317 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
318
319 // If M-I, sanity check it, and break out.
Jonas Oreland63737a92019-11-21 15:12:14 +0100320 if (attr_type == mi_attr_type) {
321 if (attr_length != mi_attr_size ||
katrielc1a206102016-06-20 05:13:16 -0700322 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
323 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000324 return false;
325 }
326 has_message_integrity_attr = true;
327 break;
328 }
329
330 // Otherwise, skip to the next attribute.
331 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
332 if ((attr_length % 4) != 0) {
333 current_pos += (4 - (attr_length % 4));
334 }
335 }
336
337 if (!has_message_integrity_attr) {
338 return false;
339 }
340
341 // Getting length of the message to calculate Message Integrity.
342 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700343 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000344 memcpy(temp_data.get(), data, current_pos);
Jonas Oreland63737a92019-11-21 15:12:14 +0100345 if (size > mi_pos + kStunAttributeHeaderSize + mi_attr_size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000346 // Stun message has other attributes after message integrity.
347 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200348 size_t extra_offset =
Jonas Oreland63737a92019-11-21 15:12:14 +0100349 size - (mi_pos + kStunAttributeHeaderSize + mi_attr_size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000350 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
351
352 // Writing new length of the STUN message @ Message Length in temp buffer.
353 // 0 1 2 3
354 // 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
355 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
356 // |0 0| STUN Message Type | Message Length |
357 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200358 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000359 }
360
361 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200362 size_t ret =
363 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
364 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800365 RTC_DCHECK(ret == sizeof(hmac));
Jonas Oreland63737a92019-11-21 15:12:14 +0100366 if (ret != sizeof(hmac)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000367 return false;
Jonas Oreland63737a92019-11-21 15:12:14 +0100368 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000369
370 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200371 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
Jonas Oreland63737a92019-11-21 15:12:14 +0100372 mi_attr_size) == 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000373}
374
375bool StunMessage::AddMessageIntegrity(const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100376 return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
377 kStunMessageIntegritySize, password.c_str(),
378 password.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000379}
380
Jonas Oreland63737a92019-11-21 15:12:14 +0100381bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
382 return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
383 kStunMessageIntegrity32Size, password.data(),
384 password.length());
385}
386
387bool StunMessage::AddMessageIntegrityOfType(int attr_type,
388 size_t attr_size,
389 const char* key,
390 size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000391 // Add the attribute with a dummy value. Since this is a known attribute, it
392 // can't fail.
Jonas Oreland63737a92019-11-21 15:12:14 +0100393 RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200394 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
Jonas Oreland63737a92019-11-21 15:12:14 +0100395 attr_type, std::string(attr_size, '0'));
zsteinf42cc9d2017-03-27 16:17:19 -0700396 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
397 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000398
399 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700400 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000401 if (!Write(&buf))
402 return false;
403
404 int msg_len_for_hmac = static_cast<int>(
405 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
406 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200407 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
408 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800409 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000410 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100411 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200412 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413 return false;
414 }
415
416 // Insert correct HMAC into the attribute.
Jonas Oreland63737a92019-11-21 15:12:14 +0100417 msg_integrity_attr->CopyBytes(hmac, attr_size);
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000418 password_.assign(key, keylen);
419 integrity_ = IntegrityStatus::kIntegrityOk;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000420 return true;
421}
422
423// Verifies a message is in fact a STUN message, by performing the checks
424// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
425// in section 15.5.
426bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
427 // Check the message length.
428 size_t fingerprint_attr_size =
429 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
430 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
431 return false;
432
433 // Skip the rest if the magic cookie isn't present.
434 const char* magic_cookie =
435 data + kStunTransactionIdOffset - kStunMagicCookieLength;
436 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
437 return false;
438
439 // Check the fingerprint type and length.
440 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
441 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200442 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000443 StunUInt32Attribute::SIZE)
444 return false;
445
446 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200447 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000448 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
449 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200450 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000451}
452
Jonas Oreland253d50f2019-11-28 17:08:07 +0100453bool StunMessage::IsStunMethod(rtc::ArrayView<int> methods,
454 const char* data,
455 size_t size) {
456 // Check the message length.
457 if (size % 4 != 0 || size < kStunHeaderSize)
458 return false;
459
460 // Skip the rest if the magic cookie isn't present.
461 const char* magic_cookie =
462 data + kStunTransactionIdOffset - kStunMagicCookieLength;
463 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
464 return false;
465
466 int method = rtc::GetBE16(data);
467 for (int m : methods) {
468 if (m == method) {
469 return true;
470 }
471 }
472 return false;
473}
474
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000475bool StunMessage::AddFingerprint() {
476 // Add the attribute with a dummy value. Since this is a known attribute,
477 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700478 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200479 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700480 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700481 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000482
483 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700484 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000485 if (!Write(&buf))
486 return false;
487
488 int msg_len_for_crc32 = static_cast<int>(
489 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200490 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000491
492 // Insert the correct CRC-32, XORed with a constant, into the attribute.
493 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
494 return true;
495}
496
jbauchf1f87202016-03-30 06:43:37 -0700497bool StunMessage::Read(ByteBufferReader* buf) {
Harald Alvestrand07d83c82021-03-02 08:09:53 +0000498 // Keep a copy of the buffer data around for later verification.
499 buffer_.assign(buf->Data(), buf->Length());
500
Jonas Oreland1721de12019-11-20 12:10:39 +0100501 if (!buf->ReadUInt16(&type_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000502 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100503 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000504
505 if (type_ & 0x8000) {
506 // RTP and RTCP set the MSB of first byte, since first two bits are version,
507 // and version is always 2 (10). If set, this is not a STUN packet.
508 return false;
509 }
510
Jonas Oreland1721de12019-11-20 12:10:39 +0100511 if (!buf->ReadUInt16(&length_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000512 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100513 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000514
515 std::string magic_cookie;
Jonas Oreland1721de12019-11-20 12:10:39 +0100516 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000517 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100518 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000519
520 std::string transaction_id;
Jonas Oreland1721de12019-11-20 12:10:39 +0100521 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000522 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100523 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000524
Andrew Royes154d8392019-03-14 10:38:31 -0700525 uint32_t magic_cookie_int;
526 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
527 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
528 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000529 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
530 // If magic cookie is invalid it means that the peer implements
531 // RFC3489 instead of RFC5389.
532 transaction_id.insert(0, magic_cookie);
533 }
nisseede5da42017-01-12 05:15:36 -0800534 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000535 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800536 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000537
Jonas Oreland1721de12019-11-20 12:10:39 +0100538 if (length_ != buf->Length()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000539 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100540 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000541
zsteinad94c4c2017-03-06 13:36:05 -0800542 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000543
544 size_t rest = buf->Length() - length_;
545 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200546 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000547 if (!buf->ReadUInt16(&attr_type))
548 return false;
549 if (!buf->ReadUInt16(&attr_length))
550 return false;
551
Honghai Zhang3e024302016-09-22 09:52:16 -0700552 std::unique_ptr<StunAttribute> attr(
553 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000554 if (!attr) {
555 // Skip any unknown or malformed attributes.
556 if ((attr_length % 4) != 0) {
557 attr_length += (4 - (attr_length % 4));
558 }
Jonas Oreland1721de12019-11-20 12:10:39 +0100559 if (!buf->Consume(attr_length)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000560 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100561 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000562 } else {
Jonas Oreland1721de12019-11-20 12:10:39 +0100563 if (!attr->Read(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100565 }
zsteinad94c4c2017-03-06 13:36:05 -0800566 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000567 }
568 }
569
nisseede5da42017-01-12 05:15:36 -0800570 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000571 return true;
572}
573
jbauchf1f87202016-03-30 06:43:37 -0700574bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000575 buf->WriteUInt16(type_);
576 buf->WriteUInt16(length_);
577 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100578 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000579 buf->WriteString(transaction_id_);
580
zsteinad94c4c2017-03-06 13:36:05 -0800581 for (const auto& attr : attrs_) {
582 buf->WriteUInt16(attr->type());
583 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
584 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000585 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800586 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000587 }
588
589 return true;
590}
591
Steve Antonca7d54e2017-10-25 14:42:51 -0700592StunMessage* StunMessage::CreateNew() const {
593 return new StunMessage();
594}
595
Jonas Oreland7ca63112018-02-27 08:45:13 +0100596void StunMessage::SetStunMagicCookie(uint32_t val) {
597 stun_magic_cookie_ = val;
598}
599
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000600StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
601 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200602 case STUN_ATTR_MAPPED_ADDRESS:
603 return STUN_VALUE_ADDRESS;
604 case STUN_ATTR_USERNAME:
605 return STUN_VALUE_BYTE_STRING;
606 case STUN_ATTR_MESSAGE_INTEGRITY:
607 return STUN_VALUE_BYTE_STRING;
608 case STUN_ATTR_ERROR_CODE:
609 return STUN_VALUE_ERROR_CODE;
610 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
611 return STUN_VALUE_UINT16_LIST;
612 case STUN_ATTR_REALM:
613 return STUN_VALUE_BYTE_STRING;
614 case STUN_ATTR_NONCE:
615 return STUN_VALUE_BYTE_STRING;
616 case STUN_ATTR_XOR_MAPPED_ADDRESS:
617 return STUN_VALUE_XOR_ADDRESS;
618 case STUN_ATTR_SOFTWARE:
619 return STUN_VALUE_BYTE_STRING;
620 case STUN_ATTR_ALTERNATE_SERVER:
621 return STUN_VALUE_ADDRESS;
622 case STUN_ATTR_FINGERPRINT:
623 return STUN_VALUE_UINT32;
624 case STUN_ATTR_ORIGIN:
625 return STUN_VALUE_BYTE_STRING;
626 case STUN_ATTR_RETRANSMIT_COUNT:
627 return STUN_VALUE_UINT32;
Jonas Orelandfa543642020-09-16 10:44:54 +0200628 case STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED:
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700629 return STUN_VALUE_BYTE_STRING;
Jonas Oreland1721de12019-11-20 12:10:39 +0100630 case STUN_ATTR_GOOG_MISC_INFO:
631 return STUN_VALUE_UINT16_LIST;
Yves Gerey665174f2018-06-19 15:03:05 +0200632 default:
633 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000634 }
635}
636
637StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
638 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200639 if (value_type != STUN_VALUE_UNKNOWN) {
640 return StunAttribute::Create(value_type, type,
641 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200642 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200643 // Read unknown attributes as STUN_VALUE_BYTE_STRING
644 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
645 static_cast<uint16_t>(length), this);
646 } else {
647 return NULL;
648 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000649}
650
651const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800652 for (const auto& attr : attrs_) {
653 if (attr->type() == type) {
654 return attr.get();
655 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000656 }
657 return NULL;
658}
659
660bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
661 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200662 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000663}
664
Jonas Oreland253d50f2019-11-28 17:08:07 +0100665bool StunMessage::EqualAttributes(
666 const StunMessage* other,
667 std::function<bool(int type)> attribute_type_mask) const {
668 RTC_DCHECK(other != nullptr);
669 rtc::ByteBufferWriter tmp_buffer_ptr1;
670 rtc::ByteBufferWriter tmp_buffer_ptr2;
671 for (const auto& attr : attrs_) {
672 if (attribute_type_mask(attr->type())) {
673 const StunAttribute* other_attr = other->GetAttribute(attr->type());
674 if (other_attr == nullptr) {
675 return false;
676 }
677 tmp_buffer_ptr1.Clear();
678 tmp_buffer_ptr2.Clear();
679 attr->Write(&tmp_buffer_ptr1);
680 other_attr->Write(&tmp_buffer_ptr2);
681 if (tmp_buffer_ptr1.Length() != tmp_buffer_ptr2.Length()) {
682 return false;
683 }
684 if (memcmp(tmp_buffer_ptr1.Data(), tmp_buffer_ptr2.Data(),
685 tmp_buffer_ptr1.Length()) != 0) {
686 return false;
687 }
688 }
689 }
690
691 for (const auto& attr : other->attrs_) {
692 if (attribute_type_mask(attr->type())) {
693 const StunAttribute* own_attr = GetAttribute(attr->type());
694 if (own_attr == nullptr) {
695 return false;
696 }
697 // we have already compared all values...
698 }
699 }
700 return true;
701}
702
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000703// StunAttribute
704
Peter Boström0c4e06b2015-10-07 12:23:21 +0200705StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200706 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000707
jbauchf1f87202016-03-30 06:43:37 -0700708void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000709 int remainder = length_ % 4;
710 if (remainder > 0) {
711 buf->Consume(4 - remainder);
712 }
713}
714
jbauchf1f87202016-03-30 06:43:37 -0700715void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000716 int remainder = length_ % 4;
717 if (remainder > 0) {
718 char zeroes[4] = {0};
719 buf->WriteBytes(zeroes, 4 - remainder);
720 }
721}
722
723StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200724 uint16_t type,
725 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000726 StunMessage* owner) {
727 switch (value_type) {
728 case STUN_VALUE_ADDRESS:
729 return new StunAddressAttribute(type, length);
730 case STUN_VALUE_XOR_ADDRESS:
731 return new StunXorAddressAttribute(type, length, owner);
732 case STUN_VALUE_UINT32:
733 return new StunUInt32Attribute(type);
734 case STUN_VALUE_UINT64:
735 return new StunUInt64Attribute(type);
736 case STUN_VALUE_BYTE_STRING:
737 return new StunByteStringAttribute(type, length);
738 case STUN_VALUE_ERROR_CODE:
739 return new StunErrorCodeAttribute(type, length);
740 case STUN_VALUE_UINT16_LIST:
741 return new StunUInt16ListAttribute(type, length);
742 default:
743 return NULL;
744 }
745}
746
zsteinf42cc9d2017-03-27 16:17:19 -0700747std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
748 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200749 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000750}
751
zsteinf42cc9d2017-03-27 16:17:19 -0700752std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
753 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200754 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000755}
756
zsteinf42cc9d2017-03-27 16:17:19 -0700757std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
758 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200759 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000760}
761
zsteinf42cc9d2017-03-27 16:17:19 -0700762std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
763 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200764 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000765}
766
zsteinf42cc9d2017-03-27 16:17:19 -0700767std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
768 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200769 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000770}
771
zsteinf42cc9d2017-03-27 16:17:19 -0700772std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200773 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000774 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
775}
776
zsteinf42cc9d2017-03-27 16:17:19 -0700777std::unique_ptr<StunUInt16ListAttribute>
Jonas Oreland1721de12019-11-20 12:10:39 +0100778StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
779 return std::make_unique<StunUInt16ListAttribute>(type, 0);
780}
781
782std::unique_ptr<StunUInt16ListAttribute>
zsteinf42cc9d2017-03-27 16:17:19 -0700783StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200784 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
785 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000786}
787
Peter Boström0c4e06b2015-10-07 12:23:21 +0200788StunAddressAttribute::StunAddressAttribute(uint16_t type,
789 const rtc::SocketAddress& addr)
790 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000791 SetAddress(addr);
792}
793
Peter Boström0c4e06b2015-10-07 12:23:21 +0200794StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200795 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000796
Steve Antonca7d54e2017-10-25 14:42:51 -0700797StunAttributeValueType StunAddressAttribute::value_type() const {
798 return STUN_VALUE_ADDRESS;
799}
800
jbauchf1f87202016-03-30 06:43:37 -0700801bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200802 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000803 if (!buf->ReadUInt8(&dummy))
804 return false;
805
Peter Boström0c4e06b2015-10-07 12:23:21 +0200806 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000807 if (!buf->ReadUInt8(&stun_family)) {
808 return false;
809 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200810 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000811 if (!buf->ReadUInt16(&port))
812 return false;
813 if (stun_family == STUN_ADDRESS_IPV4) {
814 in_addr v4addr;
815 if (length() != SIZE_IP4) {
816 return false;
817 }
818 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
819 return false;
820 }
821 rtc::IPAddress ipaddr(v4addr);
822 SetAddress(rtc::SocketAddress(ipaddr, port));
823 } else if (stun_family == STUN_ADDRESS_IPV6) {
824 in6_addr v6addr;
825 if (length() != SIZE_IP6) {
826 return false;
827 }
828 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
829 return false;
830 }
831 rtc::IPAddress ipaddr(v6addr);
832 SetAddress(rtc::SocketAddress(ipaddr, port));
833 } else {
834 return false;
835 }
836 return true;
837}
838
jbauchf1f87202016-03-30 06:43:37 -0700839bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000840 StunAddressFamily address_family = family();
841 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100842 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000843 return false;
844 }
845 buf->WriteUInt8(0);
846 buf->WriteUInt8(address_family);
847 buf->WriteUInt16(address_.port());
848 switch (address_.family()) {
849 case AF_INET: {
850 in_addr v4addr = address_.ipaddr().ipv4_address();
851 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
852 break;
853 }
854 case AF_INET6: {
855 in6_addr v6addr = address_.ipaddr().ipv6_address();
856 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
857 break;
858 }
859 }
860 return true;
861}
862
Peter Boström0c4e06b2015-10-07 12:23:21 +0200863StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
864 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200865 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000866
Peter Boström0c4e06b2015-10-07 12:23:21 +0200867StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
868 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000869 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200870 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000871
Steve Antonca7d54e2017-10-25 14:42:51 -0700872StunAttributeValueType StunXorAddressAttribute::value_type() const {
873 return STUN_VALUE_XOR_ADDRESS;
874}
875
876void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
877 owner_ = owner;
878}
879
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000880rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
881 if (owner_) {
882 rtc::IPAddress ip = ipaddr();
883 switch (ip.family()) {
884 case AF_INET: {
885 in_addr v4addr = ip.ipv4_address();
886 v4addr.s_addr =
887 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
888 return rtc::IPAddress(v4addr);
889 }
890 case AF_INET6: {
891 in6_addr v6addr = ip.ipv6_address();
892 const std::string& transaction_id = owner_->transaction_id();
893 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200894 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000895 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
896 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200897 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000898 // Transaction ID is in network byte order, but magic cookie
899 // is stored in host byte order.
900 ip_as_ints[0] =
901 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
902 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
903 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
904 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
905 return rtc::IPAddress(v6addr);
906 }
907 break;
908 }
909 }
910 }
911 // Invalid ip family or transaction ID, or missing owner.
912 // Return an AF_UNSPEC address.
913 return rtc::IPAddress();
914}
915
jbauchf1f87202016-03-30 06:43:37 -0700916bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000917 if (!StunAddressAttribute::Read(buf))
918 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200919 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000920 rtc::IPAddress xored_ip = GetXoredIP();
921 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
922 return true;
923}
924
jbauchf1f87202016-03-30 06:43:37 -0700925bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000926 StunAddressFamily address_family = family();
927 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100928 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000929 return false;
930 }
931 rtc::IPAddress xored_ip = GetXoredIP();
932 if (xored_ip.family() == AF_UNSPEC) {
933 return false;
934 }
935 buf->WriteUInt8(0);
936 buf->WriteUInt8(family());
937 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
938 switch (xored_ip.family()) {
939 case AF_INET: {
940 in_addr v4addr = xored_ip.ipv4_address();
941 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
942 break;
943 }
944 case AF_INET6: {
945 in6_addr v6addr = xored_ip.ipv6_address();
946 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
947 break;
948 }
949 }
950 return true;
951}
952
Peter Boström0c4e06b2015-10-07 12:23:21 +0200953StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200954 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000955
Peter Boström0c4e06b2015-10-07 12:23:21 +0200956StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200957 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000958
Steve Antonca7d54e2017-10-25 14:42:51 -0700959StunAttributeValueType StunUInt32Attribute::value_type() const {
960 return STUN_VALUE_UINT32;
961}
962
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000963bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800964 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000965 return static_cast<bool>((bits_ >> index) & 0x1);
966}
967
968void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800969 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000970 bits_ &= ~(1 << index);
971 bits_ |= value ? (1 << index) : 0;
972}
973
jbauchf1f87202016-03-30 06:43:37 -0700974bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000975 if (length() != SIZE || !buf->ReadUInt32(&bits_))
976 return false;
977 return true;
978}
979
jbauchf1f87202016-03-30 06:43:37 -0700980bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000981 buf->WriteUInt32(bits_);
982 return true;
983}
984
Peter Boström0c4e06b2015-10-07 12:23:21 +0200985StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200986 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000987
Peter Boström0c4e06b2015-10-07 12:23:21 +0200988StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200989 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000990
Steve Antonca7d54e2017-10-25 14:42:51 -0700991StunAttributeValueType StunUInt64Attribute::value_type() const {
992 return STUN_VALUE_UINT64;
993}
994
jbauchf1f87202016-03-30 06:43:37 -0700995bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000996 if (length() != SIZE || !buf->ReadUInt64(&bits_))
997 return false;
998 return true;
999}
1000
jbauchf1f87202016-03-30 06:43:37 -07001001bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001002 buf->WriteUInt64(bits_);
1003 return true;
1004}
1005
Peter Boström0c4e06b2015-10-07 12:23:21 +02001006StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +02001007 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001008
Peter Boström0c4e06b2015-10-07 12:23:21 +02001009StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001010 const std::string& str)
1011 : StunAttribute(type, 0), bytes_(NULL) {
1012 CopyBytes(str.c_str(), str.size());
1013}
1014
Peter Boström0c4e06b2015-10-07 12:23:21 +02001015StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001016 const void* bytes,
1017 size_t length)
1018 : StunAttribute(type, 0), bytes_(NULL) {
1019 CopyBytes(bytes, length);
1020}
1021
Peter Boström0c4e06b2015-10-07 12:23:21 +02001022StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001023 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001024
1025StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +02001026 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001027}
1028
Steve Antonca7d54e2017-10-25 14:42:51 -07001029StunAttributeValueType StunByteStringAttribute::value_type() const {
1030 return STUN_VALUE_BYTE_STRING;
1031}
1032
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001033void StunByteStringAttribute::CopyBytes(const char* bytes) {
1034 CopyBytes(bytes, strlen(bytes));
1035}
1036
1037void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
1038 char* new_bytes = new char[length];
1039 memcpy(new_bytes, bytes, length);
1040 SetBytes(new_bytes, length);
1041}
1042
Peter Boström0c4e06b2015-10-07 12:23:21 +02001043uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -08001044 RTC_DCHECK(bytes_ != NULL);
1045 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +02001046 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001047}
1048
Peter Boström0c4e06b2015-10-07 12:23:21 +02001049void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -08001050 RTC_DCHECK(bytes_ != NULL);
1051 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001052 bytes_[index] = value;
1053}
1054
jbauchf1f87202016-03-30 06:43:37 -07001055bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001056 bytes_ = new char[length()];
1057 if (!buf->ReadBytes(bytes_, length())) {
1058 return false;
1059 }
1060
1061 ConsumePadding(buf);
1062 return true;
1063}
1064
jbauchf1f87202016-03-30 06:43:37 -07001065bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
Harald Alvestrandbee64082020-11-12 11:17:41 +00001066 // Check that length is legal according to specs
1067 if (!LengthValid(type(), length())) {
1068 return false;
1069 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001070 buf->WriteBytes(bytes_, length());
1071 WritePadding(buf);
1072 return true;
1073}
1074
1075void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +02001076 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001077 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +02001078 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001079}
1080
zsteinf42cc9d2017-03-27 16:17:19 -07001081const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
1082
Peter Boström0c4e06b2015-10-07 12:23:21 +02001083StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
1084 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001085 const std::string& reason)
1086 : StunAttribute(type, 0) {
1087 SetCode(code);
1088 SetReason(reason);
1089}
1090
Peter Boström0c4e06b2015-10-07 12:23:21 +02001091StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001092 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001093
Yves Gerey665174f2018-06-19 15:03:05 +02001094StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001095
Steve Antonca7d54e2017-10-25 14:42:51 -07001096StunAttributeValueType StunErrorCodeAttribute::value_type() const {
1097 return STUN_VALUE_ERROR_CODE;
1098}
1099
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001100int StunErrorCodeAttribute::code() const {
1101 return class_ * 100 + number_;
1102}
1103
1104void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001105 class_ = static_cast<uint8_t>(code / 100);
1106 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001107}
1108
1109void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001110 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001111 reason_ = reason;
1112}
1113
jbauchf1f87202016-03-30 06:43:37 -07001114bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001115 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001116 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
1117 return false;
1118
1119 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +01001120 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001121
1122 class_ = ((val >> 8) & 0x7);
1123 number_ = (val & 0xff);
1124
1125 if (!buf->ReadString(&reason_, length() - 4))
1126 return false;
1127
1128 ConsumePadding(buf);
1129 return true;
1130}
1131
jbauchf1f87202016-03-30 06:43:37 -07001132bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001133 buf->WriteUInt32(class_ << 8 | number_);
1134 buf->WriteString(reason_);
1135 WritePadding(buf);
1136 return true;
1137}
1138
Peter Boström0c4e06b2015-10-07 12:23:21 +02001139StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001140 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001141 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001142}
1143
1144StunUInt16ListAttribute::~StunUInt16ListAttribute() {
1145 delete attr_types_;
1146}
1147
Steve Antonca7d54e2017-10-25 14:42:51 -07001148StunAttributeValueType StunUInt16ListAttribute::value_type() const {
1149 return STUN_VALUE_UINT16_LIST;
1150}
1151
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001152size_t StunUInt16ListAttribute::Size() const {
1153 return attr_types_->size();
1154}
1155
Peter Boström0c4e06b2015-10-07 12:23:21 +02001156uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001157 return (*attr_types_)[index];
1158}
1159
Peter Boström0c4e06b2015-10-07 12:23:21 +02001160void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001161 (*attr_types_)[index] = value;
1162}
1163
Peter Boström0c4e06b2015-10-07 12:23:21 +02001164void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001165 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001166 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001167}
1168
Jonas Oreland63737a92019-11-21 15:12:14 +01001169void StunUInt16ListAttribute::AddTypeAtIndex(uint16_t index, uint16_t value) {
1170 if (attr_types_->size() < static_cast<size_t>(index + 1)) {
1171 attr_types_->resize(index + 1);
1172 }
1173 (*attr_types_)[index] = value;
1174 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
1175}
1176
jbauchf1f87202016-03-30 06:43:37 -07001177bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +01001178 if (length() % 2) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001179 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +01001180 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001181
1182 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001183 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001184 if (!buf->ReadUInt16(&attr))
1185 return false;
1186 attr_types_->push_back(attr);
1187 }
1188 // Padding of these attributes is done in RFC 5389 style. This is
1189 // slightly different from RFC3489, but it shouldn't be important.
1190 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
1191 // entries in the list (not necessarily the last one - it's unspecified).
1192 // RFC5389 pads on the end, and the bytes are always ignored.
1193 ConsumePadding(buf);
1194 return true;
1195}
1196
jbauchf1f87202016-03-30 06:43:37 -07001197bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001198 for (size_t i = 0; i < attr_types_->size(); ++i) {
1199 buf->WriteUInt16((*attr_types_)[i]);
1200 }
1201 WritePadding(buf);
1202 return true;
1203}
1204
Jonas Oreland9a52bd72019-12-11 11:35:48 +01001205std::string StunMethodToString(int msg_type) {
1206 switch (msg_type) {
1207 case STUN_BINDING_REQUEST:
1208 return "STUN BINDING request";
1209 case STUN_BINDING_INDICATION:
1210 return "STUN BINDING indication";
1211 case STUN_BINDING_RESPONSE:
1212 return "STUN BINDING response";
1213 case STUN_BINDING_ERROR_RESPONSE:
1214 return "STUN BINDING error response";
1215 case GOOG_PING_REQUEST:
1216 return "GOOG PING request";
1217 case GOOG_PING_RESPONSE:
1218 return "GOOG PING response";
1219 case GOOG_PING_ERROR_RESPONSE:
1220 return "GOOG PING error response";
1221 case STUN_ALLOCATE_REQUEST:
1222 return "TURN ALLOCATE request";
1223 case STUN_ALLOCATE_RESPONSE:
1224 return "TURN ALLOCATE response";
1225 case STUN_ALLOCATE_ERROR_RESPONSE:
1226 return "TURN ALLOCATE error response";
1227 case TURN_REFRESH_REQUEST:
1228 return "TURN REFRESH request";
1229 case TURN_REFRESH_RESPONSE:
1230 return "TURN REFRESH response";
1231 case TURN_REFRESH_ERROR_RESPONSE:
1232 return "TURN REFRESH error response";
1233 case TURN_SEND_INDICATION:
1234 return "TURN SEND INDICATION";
1235 case TURN_DATA_INDICATION:
1236 return "TURN DATA INDICATION";
1237 case TURN_CREATE_PERMISSION_REQUEST:
1238 return "TURN CREATE PERMISSION request";
1239 case TURN_CREATE_PERMISSION_RESPONSE:
1240 return "TURN CREATE PERMISSION response";
1241 case TURN_CREATE_PERMISSION_ERROR_RESPONSE:
1242 return "TURN CREATE PERMISSION error response";
1243 case TURN_CHANNEL_BIND_REQUEST:
1244 return "TURN CHANNEL BIND request";
1245 case TURN_CHANNEL_BIND_RESPONSE:
1246 return "TURN CHANNEL BIND response";
1247 case TURN_CHANNEL_BIND_ERROR_RESPONSE:
1248 return "TURN CHANNEL BIND error response";
1249 default:
1250 return "UNKNOWN<" + std::to_string(msg_type) + ">";
1251 }
1252}
1253
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001254int GetStunSuccessResponseType(int req_type) {
1255 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
1256}
1257
1258int GetStunErrorResponseType(int req_type) {
1259 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
1260}
1261
1262bool IsStunRequestType(int msg_type) {
1263 return ((msg_type & kStunTypeMask) == 0x000);
1264}
1265
1266bool IsStunIndicationType(int msg_type) {
1267 return ((msg_type & kStunTypeMask) == 0x010);
1268}
1269
1270bool IsStunSuccessResponseType(int msg_type) {
1271 return ((msg_type & kStunTypeMask) == 0x100);
1272}
1273
1274bool IsStunErrorResponseType(int msg_type) {
1275 return ((msg_type & kStunTypeMask) == 0x110);
1276}
1277
1278bool ComputeStunCredentialHash(const std::string& username,
1279 const std::string& realm,
1280 const std::string& password,
1281 std::string* hash) {
1282 // http://tools.ietf.org/html/rfc5389#section-15.4
1283 // long-term credentials will be calculated using the key and key is
1284 // key = MD5(username ":" realm ":" SASLprep(password))
1285 std::string input = username;
1286 input += ':';
1287 input += realm;
1288 input += ':';
1289 input += password;
1290
1291 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001292 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1293 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001294 if (size == 0) {
1295 return false;
1296 }
1297
1298 *hash = std::string(digest, size);
1299 return true;
1300}
1301
Jonas Oreland202994c2017-12-18 12:10:43 +01001302std::unique_ptr<StunAttribute> CopyStunAttribute(
1303 const StunAttribute& attribute,
1304 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1305 ByteBufferWriter tmpBuffer;
1306 if (tmp_buffer_ptr == nullptr) {
1307 tmp_buffer_ptr = &tmpBuffer;
1308 }
1309
Yves Gerey665174f2018-06-19 15:03:05 +02001310 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1311 attribute.value_type(), attribute.type(),
1312 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001313
1314 if (!copy) {
1315 return nullptr;
1316 }
1317 tmp_buffer_ptr->Clear();
1318 if (!attribute.Write(tmp_buffer_ptr)) {
1319 return nullptr;
1320 }
1321 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1322 if (!copy->Read(&reader)) {
1323 return nullptr;
1324 }
1325
1326 return copy;
1327}
1328
Steve Antonca7d54e2017-10-25 14:42:51 -07001329StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1330 switch (type) {
1331 case STUN_ATTR_LIFETIME:
1332 return STUN_VALUE_UINT32;
1333 case STUN_ATTR_MAGIC_COOKIE:
1334 return STUN_VALUE_BYTE_STRING;
1335 case STUN_ATTR_BANDWIDTH:
1336 return STUN_VALUE_UINT32;
1337 case STUN_ATTR_DESTINATION_ADDRESS:
1338 return STUN_VALUE_ADDRESS;
1339 case STUN_ATTR_SOURCE_ADDRESS2:
1340 return STUN_VALUE_ADDRESS;
1341 case STUN_ATTR_DATA:
1342 return STUN_VALUE_BYTE_STRING;
1343 case STUN_ATTR_OPTIONS:
1344 return STUN_VALUE_UINT32;
1345 default:
1346 return StunMessage::GetAttributeValueType(type);
1347 }
1348}
1349
1350StunMessage* RelayMessage::CreateNew() const {
1351 return new RelayMessage();
1352}
1353
1354StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1355 switch (type) {
1356 case STUN_ATTR_CHANNEL_NUMBER:
1357 return STUN_VALUE_UINT32;
1358 case STUN_ATTR_TURN_LIFETIME:
1359 return STUN_VALUE_UINT32;
1360 case STUN_ATTR_XOR_PEER_ADDRESS:
1361 return STUN_VALUE_XOR_ADDRESS;
1362 case STUN_ATTR_DATA:
1363 return STUN_VALUE_BYTE_STRING;
1364 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1365 return STUN_VALUE_XOR_ADDRESS;
1366 case STUN_ATTR_EVEN_PORT:
1367 return STUN_VALUE_BYTE_STRING;
1368 case STUN_ATTR_REQUESTED_TRANSPORT:
1369 return STUN_VALUE_UINT32;
1370 case STUN_ATTR_DONT_FRAGMENT:
1371 return STUN_VALUE_BYTE_STRING;
1372 case STUN_ATTR_RESERVATION_TOKEN:
1373 return STUN_VALUE_BYTE_STRING;
1374 default:
1375 return StunMessage::GetAttributeValueType(type);
1376 }
1377}
1378
1379StunMessage* TurnMessage::CreateNew() const {
1380 return new TurnMessage();
1381}
1382
1383StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1384 switch (type) {
1385 case STUN_ATTR_PRIORITY:
Jonas Orelandfa543642020-09-16 10:44:54 +02001386 case STUN_ATTR_GOOG_NETWORK_INFO:
Steve Antonca7d54e2017-10-25 14:42:51 -07001387 case STUN_ATTR_NOMINATION:
1388 return STUN_VALUE_UINT32;
1389 case STUN_ATTR_USE_CANDIDATE:
1390 return STUN_VALUE_BYTE_STRING;
1391 case STUN_ATTR_ICE_CONTROLLED:
1392 return STUN_VALUE_UINT64;
1393 case STUN_ATTR_ICE_CONTROLLING:
1394 return STUN_VALUE_UINT64;
1395 default:
1396 return StunMessage::GetAttributeValueType(type);
1397 }
1398}
1399
1400StunMessage* IceMessage::CreateNew() const {
1401 return new IceMessage();
1402}
1403
Jonas Oreland253d50f2019-11-28 17:08:07 +01001404std::unique_ptr<StunMessage> StunMessage::Clone() const {
1405 std::unique_ptr<StunMessage> copy(CreateNew());
1406 if (!copy) {
1407 return nullptr;
1408 }
1409 rtc::ByteBufferWriter buf;
1410 if (!Write(&buf)) {
1411 return nullptr;
1412 }
1413 rtc::ByteBufferReader reader(buf);
1414 if (!copy->Read(&reader)) {
1415 return nullptr;
1416 }
1417 return copy;
1418}
1419
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001420} // namespace cricket