blob: 4ae834c0c4c2b73b6c8a8c8899623fc728dca76f [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>
14
Yves Gerey665174f2018-06-19 15:03:05 +020015#include <algorithm>
kwiberg3ec46792016-04-27 07:22:53 -070016#include <memory>
Steve Anton6c38cc72017-11-29 10:25:58 -080017#include <utility>
kwiberg3ec46792016-04-27 07:22:53 -070018
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/checks.h"
21#include "rtc_base/crc32.h"
22#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "rtc_base/message_digest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024
jbauchf1f87202016-03-30 06:43:37 -070025using rtc::ByteBufferReader;
26using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000027
Zach Stein92c42892018-11-28 11:38:52 -080028namespace {
29
30uint32_t ReduceTransactionId(const std::string& transaction_id) {
31 RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
32 transaction_id.length() ==
33 cricket::kStunLegacyTransactionIdLength);
Danil Chapovalov7b46e172019-11-14 17:40:23 +010034 ByteBufferReader reader(transaction_id.c_str(), transaction_id.length());
Zach Stein92c42892018-11-28 11:38:52 -080035 uint32_t result = 0;
Zach Steinff71a492018-12-07 11:25:12 -080036 uint32_t next;
37 while (reader.ReadUInt32(&next)) {
38 result ^= next;
Zach Stein92c42892018-11-28 11:38:52 -080039 }
40 return result;
41}
42
43} // namespace
44
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000045namespace cricket {
46
47const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
48const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
49const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
50const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
51const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
52const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
53const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
54const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
55const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
56const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
57const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
58
Yves Gerey665174f2018-06-19 15:03:05 +020059const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000060const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020061const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
Eldar Relloda13ea22019-06-01 12:23:43 +030062const int SERVER_NOT_REACHABLE_ERROR = 701;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000063
64// StunMessage
65
66StunMessage::StunMessage()
67 : type_(0),
68 length_(0),
Jonas Oreland7ca63112018-02-27 08:45:13 +010069 transaction_id_(EMPTY_TRANSACTION_ID),
70 stun_magic_cookie_(kStunMagicCookie) {
nisseede5da42017-01-12 05:15:36 -080071 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000072}
73
Steve Antonca7d54e2017-10-25 14:42:51 -070074StunMessage::~StunMessage() = default;
75
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000076bool StunMessage::IsLegacy() const {
77 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
78 return true;
nisseede5da42017-01-12 05:15:36 -080079 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000080 return false;
81}
82
83bool StunMessage::SetTransactionID(const std::string& str) {
84 if (!IsValidTransactionId(str)) {
85 return false;
86 }
87 transaction_id_ = str;
Zach Stein92c42892018-11-28 11:38:52 -080088 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000089 return true;
90}
91
Jonas Oreland16ccef72018-03-27 09:02:43 +020092static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +020093 return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
94 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +020095}
96
zsteinf42cc9d2017-03-27 16:17:19 -070097void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020098 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +020099 // but allow any type for the range that in the RFC is reserved for
100 // the "designated experts".
101 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200102 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
103 }
nissecc99bc22017-02-02 01:31:30 -0800104
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000105 attr->SetOwner(this);
106 size_t attr_length = attr->length();
107 if (attr_length % 4 != 0) {
108 attr_length += (4 - (attr_length % 4));
109 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200110 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -0700111
112 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000113}
114
Jonas Oreland202994c2017-12-18 12:10:43 +0100115std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
116 std::unique_ptr<StunAttribute> attribute;
117 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
Yves Gerey665174f2018-06-19 15:03:05 +0200118 if ((*it)->type() == type) {
119 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100120 attrs_.erase(std::next(it).base());
121 break;
122 }
123 }
124 if (attribute) {
125 attribute->SetOwner(nullptr);
126 size_t attr_length = attribute->length();
127 if (attr_length % 4 != 0) {
128 attr_length += (4 - (attr_length % 4));
129 }
130 length_ -= static_cast<uint16_t>(attr_length + 4);
131 }
132 return attribute;
133}
134
Jonas Oreland63737a92019-11-21 15:12:14 +0100135void StunMessage::ClearAttributes() {
136 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
137 (*it)->SetOwner(nullptr);
138 }
139 attrs_.clear();
140 length_ = 0;
141}
142
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143const StunAddressAttribute* StunMessage::GetAddress(int type) const {
144 switch (type) {
145 case STUN_ATTR_MAPPED_ADDRESS: {
146 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
147 // missing.
148 const StunAttribute* mapped_address =
149 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
150 if (!mapped_address)
151 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
152 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
153 }
154
155 default:
156 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
157 }
158}
159
160const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
161 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
162}
163
164const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
165 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
166}
167
168const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
169 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
170}
171
Jonas Oreland1721de12019-11-20 12:10:39 +0100172const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
173 return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
174}
175
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000176const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
177 return static_cast<const StunErrorCodeAttribute*>(
178 GetAttribute(STUN_ATTR_ERROR_CODE));
179}
180
deadbeef996fc6b2017-04-26 09:21:22 -0700181int StunMessage::GetErrorCodeValue() const {
182 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
183 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
184}
185
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000186const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
187 return static_cast<const StunUInt16ListAttribute*>(
188 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
189}
190
Yves Gerey665174f2018-06-19 15:03:05 +0200191bool StunMessage::ValidateMessageIntegrity(const char* data,
192 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000193 const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100194 return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
195 kStunMessageIntegritySize, data, size,
196 password);
197}
198
199bool StunMessage::ValidateMessageIntegrity32(const char* data,
200 size_t size,
201 const std::string& password) {
202 return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
203 kStunMessageIntegrity32Size, data, size,
204 password);
205}
206
207// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
208// procedure outlined in RFC 5389, section 15.4.
209bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
210 size_t mi_attr_size,
211 const char* data,
212 size_t size,
213 const std::string& password) {
214 RTC_DCHECK(mi_attr_size <= kStunMessageIntegritySize);
215
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000216 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700217 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000218 return false;
219 }
220
221 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200222 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000223 if (size != (msg_length + kStunHeaderSize)) {
224 return false;
225 }
226
227 // Finding Message Integrity attribute in stun message.
228 size_t current_pos = kStunHeaderSize;
229 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700230 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200231 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000232 // Getting attribute type and length.
233 attr_type = rtc::GetBE16(&data[current_pos]);
234 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
235
236 // If M-I, sanity check it, and break out.
Jonas Oreland63737a92019-11-21 15:12:14 +0100237 if (attr_type == mi_attr_type) {
238 if (attr_length != mi_attr_size ||
katrielc1a206102016-06-20 05:13:16 -0700239 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
240 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000241 return false;
242 }
243 has_message_integrity_attr = true;
244 break;
245 }
246
247 // Otherwise, skip to the next attribute.
248 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
249 if ((attr_length % 4) != 0) {
250 current_pos += (4 - (attr_length % 4));
251 }
252 }
253
254 if (!has_message_integrity_attr) {
255 return false;
256 }
257
258 // Getting length of the message to calculate Message Integrity.
259 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700260 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000261 memcpy(temp_data.get(), data, current_pos);
Jonas Oreland63737a92019-11-21 15:12:14 +0100262 if (size > mi_pos + kStunAttributeHeaderSize + mi_attr_size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000263 // Stun message has other attributes after message integrity.
264 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200265 size_t extra_offset =
Jonas Oreland63737a92019-11-21 15:12:14 +0100266 size - (mi_pos + kStunAttributeHeaderSize + mi_attr_size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000267 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
268
269 // Writing new length of the STUN message @ Message Length in temp buffer.
270 // 0 1 2 3
271 // 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
272 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
273 // |0 0| STUN Message Type | Message Length |
274 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200275 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000276 }
277
278 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200279 size_t ret =
280 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
281 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800282 RTC_DCHECK(ret == sizeof(hmac));
Jonas Oreland63737a92019-11-21 15:12:14 +0100283 if (ret != sizeof(hmac)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000284 return false;
Jonas Oreland63737a92019-11-21 15:12:14 +0100285 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000286
287 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200288 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
Jonas Oreland63737a92019-11-21 15:12:14 +0100289 mi_attr_size) == 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000290}
291
292bool StunMessage::AddMessageIntegrity(const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100293 return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
294 kStunMessageIntegritySize, password.c_str(),
295 password.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000296}
297
Yves Gerey665174f2018-06-19 15:03:05 +0200298bool StunMessage::AddMessageIntegrity(const char* key, size_t keylen) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100299 return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
300 kStunMessageIntegritySize, key, keylen);
301}
302
303bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
304 return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
305 kStunMessageIntegrity32Size, password.data(),
306 password.length());
307}
308
309bool StunMessage::AddMessageIntegrityOfType(int attr_type,
310 size_t attr_size,
311 const char* key,
312 size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000313 // Add the attribute with a dummy value. Since this is a known attribute, it
314 // can't fail.
Jonas Oreland63737a92019-11-21 15:12:14 +0100315 RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200316 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
Jonas Oreland63737a92019-11-21 15:12:14 +0100317 attr_type, std::string(attr_size, '0'));
zsteinf42cc9d2017-03-27 16:17:19 -0700318 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
319 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320
321 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700322 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000323 if (!Write(&buf))
324 return false;
325
326 int msg_len_for_hmac = static_cast<int>(
327 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
328 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200329 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
330 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800331 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000332 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100333 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200334 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000335 return false;
336 }
337
338 // Insert correct HMAC into the attribute.
Jonas Oreland63737a92019-11-21 15:12:14 +0100339 msg_integrity_attr->CopyBytes(hmac, attr_size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000340 return true;
341}
342
343// Verifies a message is in fact a STUN message, by performing the checks
344// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
345// in section 15.5.
346bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
347 // Check the message length.
348 size_t fingerprint_attr_size =
349 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
350 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
351 return false;
352
353 // Skip the rest if the magic cookie isn't present.
354 const char* magic_cookie =
355 data + kStunTransactionIdOffset - kStunMagicCookieLength;
356 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
357 return false;
358
359 // Check the fingerprint type and length.
360 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
361 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200362 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000363 StunUInt32Attribute::SIZE)
364 return false;
365
366 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200367 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000368 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
369 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200370 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371}
372
Jonas Oreland253d50f2019-11-28 17:08:07 +0100373bool StunMessage::IsStunMethod(rtc::ArrayView<int> methods,
374 const char* data,
375 size_t size) {
376 // Check the message length.
377 if (size % 4 != 0 || size < kStunHeaderSize)
378 return false;
379
380 // Skip the rest if the magic cookie isn't present.
381 const char* magic_cookie =
382 data + kStunTransactionIdOffset - kStunMagicCookieLength;
383 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
384 return false;
385
386 int method = rtc::GetBE16(data);
387 for (int m : methods) {
388 if (m == method) {
389 return true;
390 }
391 }
392 return false;
393}
394
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000395bool StunMessage::AddFingerprint() {
396 // Add the attribute with a dummy value. Since this is a known attribute,
397 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700398 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200399 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700400 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700401 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000402
403 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700404 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000405 if (!Write(&buf))
406 return false;
407
408 int msg_len_for_crc32 = static_cast<int>(
409 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200410 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000411
412 // Insert the correct CRC-32, XORed with a constant, into the attribute.
413 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
414 return true;
415}
416
jbauchf1f87202016-03-30 06:43:37 -0700417bool StunMessage::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +0100418 if (!buf->ReadUInt16(&type_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000419 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100420 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000421
422 if (type_ & 0x8000) {
423 // RTP and RTCP set the MSB of first byte, since first two bits are version,
424 // and version is always 2 (10). If set, this is not a STUN packet.
425 return false;
426 }
427
Jonas Oreland1721de12019-11-20 12:10:39 +0100428 if (!buf->ReadUInt16(&length_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000429 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100430 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000431
432 std::string magic_cookie;
Jonas Oreland1721de12019-11-20 12:10:39 +0100433 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000434 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100435 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000436
437 std::string transaction_id;
Jonas Oreland1721de12019-11-20 12:10:39 +0100438 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000439 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100440 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000441
Andrew Royes154d8392019-03-14 10:38:31 -0700442 uint32_t magic_cookie_int;
443 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
444 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
445 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000446 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
447 // If magic cookie is invalid it means that the peer implements
448 // RFC3489 instead of RFC5389.
449 transaction_id.insert(0, magic_cookie);
450 }
nisseede5da42017-01-12 05:15:36 -0800451 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000452 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800453 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000454
Jonas Oreland1721de12019-11-20 12:10:39 +0100455 if (length_ != buf->Length()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000456 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100457 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000458
zsteinad94c4c2017-03-06 13:36:05 -0800459 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000460
461 size_t rest = buf->Length() - length_;
462 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200463 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000464 if (!buf->ReadUInt16(&attr_type))
465 return false;
466 if (!buf->ReadUInt16(&attr_length))
467 return false;
468
Honghai Zhang3e024302016-09-22 09:52:16 -0700469 std::unique_ptr<StunAttribute> attr(
470 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000471 if (!attr) {
472 // Skip any unknown or malformed attributes.
473 if ((attr_length % 4) != 0) {
474 attr_length += (4 - (attr_length % 4));
475 }
Jonas Oreland1721de12019-11-20 12:10:39 +0100476 if (!buf->Consume(attr_length)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000477 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100478 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000479 } else {
Jonas Oreland1721de12019-11-20 12:10:39 +0100480 if (!attr->Read(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000481 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100482 }
zsteinad94c4c2017-03-06 13:36:05 -0800483 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000484 }
485 }
486
nisseede5da42017-01-12 05:15:36 -0800487 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000488 return true;
489}
490
jbauchf1f87202016-03-30 06:43:37 -0700491bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000492 buf->WriteUInt16(type_);
493 buf->WriteUInt16(length_);
494 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100495 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000496 buf->WriteString(transaction_id_);
497
zsteinad94c4c2017-03-06 13:36:05 -0800498 for (const auto& attr : attrs_) {
499 buf->WriteUInt16(attr->type());
500 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
501 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000502 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800503 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000504 }
505
506 return true;
507}
508
Steve Antonca7d54e2017-10-25 14:42:51 -0700509StunMessage* StunMessage::CreateNew() const {
510 return new StunMessage();
511}
512
Jonas Oreland7ca63112018-02-27 08:45:13 +0100513void StunMessage::SetStunMagicCookie(uint32_t val) {
514 stun_magic_cookie_ = val;
515}
516
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000517StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
518 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200519 case STUN_ATTR_MAPPED_ADDRESS:
520 return STUN_VALUE_ADDRESS;
521 case STUN_ATTR_USERNAME:
522 return STUN_VALUE_BYTE_STRING;
523 case STUN_ATTR_MESSAGE_INTEGRITY:
524 return STUN_VALUE_BYTE_STRING;
525 case STUN_ATTR_ERROR_CODE:
526 return STUN_VALUE_ERROR_CODE;
527 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
528 return STUN_VALUE_UINT16_LIST;
529 case STUN_ATTR_REALM:
530 return STUN_VALUE_BYTE_STRING;
531 case STUN_ATTR_NONCE:
532 return STUN_VALUE_BYTE_STRING;
533 case STUN_ATTR_XOR_MAPPED_ADDRESS:
534 return STUN_VALUE_XOR_ADDRESS;
535 case STUN_ATTR_SOFTWARE:
536 return STUN_VALUE_BYTE_STRING;
537 case STUN_ATTR_ALTERNATE_SERVER:
538 return STUN_VALUE_ADDRESS;
539 case STUN_ATTR_FINGERPRINT:
540 return STUN_VALUE_UINT32;
541 case STUN_ATTR_ORIGIN:
542 return STUN_VALUE_BYTE_STRING;
543 case STUN_ATTR_RETRANSMIT_COUNT:
544 return STUN_VALUE_UINT32;
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700545 case STUN_ATTR_LAST_ICE_CHECK_RECEIVED:
546 return STUN_VALUE_BYTE_STRING;
Jonas Oreland1721de12019-11-20 12:10:39 +0100547 case STUN_ATTR_GOOG_MISC_INFO:
548 return STUN_VALUE_UINT16_LIST;
Yves Gerey665174f2018-06-19 15:03:05 +0200549 default:
550 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000551 }
552}
553
554StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
555 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200556 if (value_type != STUN_VALUE_UNKNOWN) {
557 return StunAttribute::Create(value_type, type,
558 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200559 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200560 // Read unknown attributes as STUN_VALUE_BYTE_STRING
561 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
562 static_cast<uint16_t>(length), this);
563 } else {
564 return NULL;
565 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000566}
567
568const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800569 for (const auto& attr : attrs_) {
570 if (attr->type() == type) {
571 return attr.get();
572 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000573 }
574 return NULL;
575}
576
577bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
578 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200579 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000580}
581
Jonas Oreland253d50f2019-11-28 17:08:07 +0100582bool StunMessage::EqualAttributes(
583 const StunMessage* other,
584 std::function<bool(int type)> attribute_type_mask) const {
585 RTC_DCHECK(other != nullptr);
586 rtc::ByteBufferWriter tmp_buffer_ptr1;
587 rtc::ByteBufferWriter tmp_buffer_ptr2;
588 for (const auto& attr : attrs_) {
589 if (attribute_type_mask(attr->type())) {
590 const StunAttribute* other_attr = other->GetAttribute(attr->type());
591 if (other_attr == nullptr) {
592 return false;
593 }
594 tmp_buffer_ptr1.Clear();
595 tmp_buffer_ptr2.Clear();
596 attr->Write(&tmp_buffer_ptr1);
597 other_attr->Write(&tmp_buffer_ptr2);
598 if (tmp_buffer_ptr1.Length() != tmp_buffer_ptr2.Length()) {
599 return false;
600 }
601 if (memcmp(tmp_buffer_ptr1.Data(), tmp_buffer_ptr2.Data(),
602 tmp_buffer_ptr1.Length()) != 0) {
603 return false;
604 }
605 }
606 }
607
608 for (const auto& attr : other->attrs_) {
609 if (attribute_type_mask(attr->type())) {
610 const StunAttribute* own_attr = GetAttribute(attr->type());
611 if (own_attr == nullptr) {
612 return false;
613 }
614 // we have already compared all values...
615 }
616 }
617 return true;
618}
619
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000620// StunAttribute
621
Peter Boström0c4e06b2015-10-07 12:23:21 +0200622StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200623 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000624
jbauchf1f87202016-03-30 06:43:37 -0700625void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000626 int remainder = length_ % 4;
627 if (remainder > 0) {
628 buf->Consume(4 - remainder);
629 }
630}
631
jbauchf1f87202016-03-30 06:43:37 -0700632void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000633 int remainder = length_ % 4;
634 if (remainder > 0) {
635 char zeroes[4] = {0};
636 buf->WriteBytes(zeroes, 4 - remainder);
637 }
638}
639
640StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200641 uint16_t type,
642 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000643 StunMessage* owner) {
644 switch (value_type) {
645 case STUN_VALUE_ADDRESS:
646 return new StunAddressAttribute(type, length);
647 case STUN_VALUE_XOR_ADDRESS:
648 return new StunXorAddressAttribute(type, length, owner);
649 case STUN_VALUE_UINT32:
650 return new StunUInt32Attribute(type);
651 case STUN_VALUE_UINT64:
652 return new StunUInt64Attribute(type);
653 case STUN_VALUE_BYTE_STRING:
654 return new StunByteStringAttribute(type, length);
655 case STUN_VALUE_ERROR_CODE:
656 return new StunErrorCodeAttribute(type, length);
657 case STUN_VALUE_UINT16_LIST:
658 return new StunUInt16ListAttribute(type, length);
659 default:
660 return NULL;
661 }
662}
663
zsteinf42cc9d2017-03-27 16:17:19 -0700664std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
665 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200666 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000667}
668
zsteinf42cc9d2017-03-27 16:17:19 -0700669std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
670 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200671 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000672}
673
zsteinf42cc9d2017-03-27 16:17:19 -0700674std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
675 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200676 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000677}
678
zsteinf42cc9d2017-03-27 16:17:19 -0700679std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
680 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200681 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000682}
683
zsteinf42cc9d2017-03-27 16:17:19 -0700684std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
685 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200686 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000687}
688
zsteinf42cc9d2017-03-27 16:17:19 -0700689std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200690 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
692}
693
zsteinf42cc9d2017-03-27 16:17:19 -0700694std::unique_ptr<StunUInt16ListAttribute>
Jonas Oreland1721de12019-11-20 12:10:39 +0100695StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
696 return std::make_unique<StunUInt16ListAttribute>(type, 0);
697}
698
699std::unique_ptr<StunUInt16ListAttribute>
zsteinf42cc9d2017-03-27 16:17:19 -0700700StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200701 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
702 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000703}
704
Peter Boström0c4e06b2015-10-07 12:23:21 +0200705StunAddressAttribute::StunAddressAttribute(uint16_t type,
706 const rtc::SocketAddress& addr)
707 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000708 SetAddress(addr);
709}
710
Peter Boström0c4e06b2015-10-07 12:23:21 +0200711StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200712 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000713
Steve Antonca7d54e2017-10-25 14:42:51 -0700714StunAttributeValueType StunAddressAttribute::value_type() const {
715 return STUN_VALUE_ADDRESS;
716}
717
jbauchf1f87202016-03-30 06:43:37 -0700718bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200719 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000720 if (!buf->ReadUInt8(&dummy))
721 return false;
722
Peter Boström0c4e06b2015-10-07 12:23:21 +0200723 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000724 if (!buf->ReadUInt8(&stun_family)) {
725 return false;
726 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200727 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000728 if (!buf->ReadUInt16(&port))
729 return false;
730 if (stun_family == STUN_ADDRESS_IPV4) {
731 in_addr v4addr;
732 if (length() != SIZE_IP4) {
733 return false;
734 }
735 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
736 return false;
737 }
738 rtc::IPAddress ipaddr(v4addr);
739 SetAddress(rtc::SocketAddress(ipaddr, port));
740 } else if (stun_family == STUN_ADDRESS_IPV6) {
741 in6_addr v6addr;
742 if (length() != SIZE_IP6) {
743 return false;
744 }
745 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
746 return false;
747 }
748 rtc::IPAddress ipaddr(v6addr);
749 SetAddress(rtc::SocketAddress(ipaddr, port));
750 } else {
751 return false;
752 }
753 return true;
754}
755
jbauchf1f87202016-03-30 06:43:37 -0700756bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000757 StunAddressFamily address_family = family();
758 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100759 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000760 return false;
761 }
762 buf->WriteUInt8(0);
763 buf->WriteUInt8(address_family);
764 buf->WriteUInt16(address_.port());
765 switch (address_.family()) {
766 case AF_INET: {
767 in_addr v4addr = address_.ipaddr().ipv4_address();
768 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
769 break;
770 }
771 case AF_INET6: {
772 in6_addr v6addr = address_.ipaddr().ipv6_address();
773 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
774 break;
775 }
776 }
777 return true;
778}
779
Peter Boström0c4e06b2015-10-07 12:23:21 +0200780StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
781 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200782 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000783
Peter Boström0c4e06b2015-10-07 12:23:21 +0200784StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
785 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000786 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200787 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000788
Steve Antonca7d54e2017-10-25 14:42:51 -0700789StunAttributeValueType StunXorAddressAttribute::value_type() const {
790 return STUN_VALUE_XOR_ADDRESS;
791}
792
793void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
794 owner_ = owner;
795}
796
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000797rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
798 if (owner_) {
799 rtc::IPAddress ip = ipaddr();
800 switch (ip.family()) {
801 case AF_INET: {
802 in_addr v4addr = ip.ipv4_address();
803 v4addr.s_addr =
804 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
805 return rtc::IPAddress(v4addr);
806 }
807 case AF_INET6: {
808 in6_addr v6addr = ip.ipv6_address();
809 const std::string& transaction_id = owner_->transaction_id();
810 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200811 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000812 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
813 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200814 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000815 // Transaction ID is in network byte order, but magic cookie
816 // is stored in host byte order.
817 ip_as_ints[0] =
818 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
819 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
820 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
821 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
822 return rtc::IPAddress(v6addr);
823 }
824 break;
825 }
826 }
827 }
828 // Invalid ip family or transaction ID, or missing owner.
829 // Return an AF_UNSPEC address.
830 return rtc::IPAddress();
831}
832
jbauchf1f87202016-03-30 06:43:37 -0700833bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000834 if (!StunAddressAttribute::Read(buf))
835 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200836 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000837 rtc::IPAddress xored_ip = GetXoredIP();
838 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
839 return true;
840}
841
jbauchf1f87202016-03-30 06:43:37 -0700842bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000843 StunAddressFamily address_family = family();
844 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100845 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000846 return false;
847 }
848 rtc::IPAddress xored_ip = GetXoredIP();
849 if (xored_ip.family() == AF_UNSPEC) {
850 return false;
851 }
852 buf->WriteUInt8(0);
853 buf->WriteUInt8(family());
854 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
855 switch (xored_ip.family()) {
856 case AF_INET: {
857 in_addr v4addr = xored_ip.ipv4_address();
858 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
859 break;
860 }
861 case AF_INET6: {
862 in6_addr v6addr = xored_ip.ipv6_address();
863 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
864 break;
865 }
866 }
867 return true;
868}
869
Peter Boström0c4e06b2015-10-07 12:23:21 +0200870StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200871 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000872
Peter Boström0c4e06b2015-10-07 12:23:21 +0200873StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200874 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000875
Steve Antonca7d54e2017-10-25 14:42:51 -0700876StunAttributeValueType StunUInt32Attribute::value_type() const {
877 return STUN_VALUE_UINT32;
878}
879
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000880bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800881 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000882 return static_cast<bool>((bits_ >> index) & 0x1);
883}
884
885void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800886 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000887 bits_ &= ~(1 << index);
888 bits_ |= value ? (1 << index) : 0;
889}
890
jbauchf1f87202016-03-30 06:43:37 -0700891bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000892 if (length() != SIZE || !buf->ReadUInt32(&bits_))
893 return false;
894 return true;
895}
896
jbauchf1f87202016-03-30 06:43:37 -0700897bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000898 buf->WriteUInt32(bits_);
899 return true;
900}
901
Peter Boström0c4e06b2015-10-07 12:23:21 +0200902StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200903 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000904
Peter Boström0c4e06b2015-10-07 12:23:21 +0200905StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200906 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000907
Steve Antonca7d54e2017-10-25 14:42:51 -0700908StunAttributeValueType StunUInt64Attribute::value_type() const {
909 return STUN_VALUE_UINT64;
910}
911
jbauchf1f87202016-03-30 06:43:37 -0700912bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000913 if (length() != SIZE || !buf->ReadUInt64(&bits_))
914 return false;
915 return true;
916}
917
jbauchf1f87202016-03-30 06:43:37 -0700918bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000919 buf->WriteUInt64(bits_);
920 return true;
921}
922
Peter Boström0c4e06b2015-10-07 12:23:21 +0200923StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200924 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000925
Peter Boström0c4e06b2015-10-07 12:23:21 +0200926StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000927 const std::string& str)
928 : StunAttribute(type, 0), bytes_(NULL) {
929 CopyBytes(str.c_str(), str.size());
930}
931
Peter Boström0c4e06b2015-10-07 12:23:21 +0200932StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000933 const void* bytes,
934 size_t length)
935 : StunAttribute(type, 0), bytes_(NULL) {
936 CopyBytes(bytes, length);
937}
938
Peter Boström0c4e06b2015-10-07 12:23:21 +0200939StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200940 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000941
942StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +0200943 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000944}
945
Steve Antonca7d54e2017-10-25 14:42:51 -0700946StunAttributeValueType StunByteStringAttribute::value_type() const {
947 return STUN_VALUE_BYTE_STRING;
948}
949
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000950void StunByteStringAttribute::CopyBytes(const char* bytes) {
951 CopyBytes(bytes, strlen(bytes));
952}
953
954void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
955 char* new_bytes = new char[length];
956 memcpy(new_bytes, bytes, length);
957 SetBytes(new_bytes, length);
958}
959
Peter Boström0c4e06b2015-10-07 12:23:21 +0200960uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800961 RTC_DCHECK(bytes_ != NULL);
962 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200963 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000964}
965
Peter Boström0c4e06b2015-10-07 12:23:21 +0200966void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800967 RTC_DCHECK(bytes_ != NULL);
968 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000969 bytes_[index] = value;
970}
971
jbauchf1f87202016-03-30 06:43:37 -0700972bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000973 bytes_ = new char[length()];
974 if (!buf->ReadBytes(bytes_, length())) {
975 return false;
976 }
977
978 ConsumePadding(buf);
979 return true;
980}
981
jbauchf1f87202016-03-30 06:43:37 -0700982bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000983 buf->WriteBytes(bytes_, length());
984 WritePadding(buf);
985 return true;
986}
987
988void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +0200989 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000990 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200991 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000992}
993
zsteinf42cc9d2017-03-27 16:17:19 -0700994const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
995
Peter Boström0c4e06b2015-10-07 12:23:21 +0200996StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
997 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000998 const std::string& reason)
999 : StunAttribute(type, 0) {
1000 SetCode(code);
1001 SetReason(reason);
1002}
1003
Peter Boström0c4e06b2015-10-07 12:23:21 +02001004StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +02001005 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001006
Yves Gerey665174f2018-06-19 15:03:05 +02001007StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001008
Steve Antonca7d54e2017-10-25 14:42:51 -07001009StunAttributeValueType StunErrorCodeAttribute::value_type() const {
1010 return STUN_VALUE_ERROR_CODE;
1011}
1012
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001013int StunErrorCodeAttribute::code() const {
1014 return class_ * 100 + number_;
1015}
1016
1017void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001018 class_ = static_cast<uint8_t>(code / 100);
1019 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001020}
1021
1022void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001023 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001024 reason_ = reason;
1025}
1026
jbauchf1f87202016-03-30 06:43:37 -07001027bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001028 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001029 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
1030 return false;
1031
1032 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +01001033 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001034
1035 class_ = ((val >> 8) & 0x7);
1036 number_ = (val & 0xff);
1037
1038 if (!buf->ReadString(&reason_, length() - 4))
1039 return false;
1040
1041 ConsumePadding(buf);
1042 return true;
1043}
1044
jbauchf1f87202016-03-30 06:43:37 -07001045bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001046 buf->WriteUInt32(class_ << 8 | number_);
1047 buf->WriteString(reason_);
1048 WritePadding(buf);
1049 return true;
1050}
1051
Peter Boström0c4e06b2015-10-07 12:23:21 +02001052StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001053 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001054 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001055}
1056
1057StunUInt16ListAttribute::~StunUInt16ListAttribute() {
1058 delete attr_types_;
1059}
1060
Steve Antonca7d54e2017-10-25 14:42:51 -07001061StunAttributeValueType StunUInt16ListAttribute::value_type() const {
1062 return STUN_VALUE_UINT16_LIST;
1063}
1064
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001065size_t StunUInt16ListAttribute::Size() const {
1066 return attr_types_->size();
1067}
1068
Peter Boström0c4e06b2015-10-07 12:23:21 +02001069uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001070 return (*attr_types_)[index];
1071}
1072
Peter Boström0c4e06b2015-10-07 12:23:21 +02001073void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001074 (*attr_types_)[index] = value;
1075}
1076
Peter Boström0c4e06b2015-10-07 12:23:21 +02001077void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001078 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001079 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001080}
1081
Jonas Oreland63737a92019-11-21 15:12:14 +01001082void StunUInt16ListAttribute::AddTypeAtIndex(uint16_t index, uint16_t value) {
1083 if (attr_types_->size() < static_cast<size_t>(index + 1)) {
1084 attr_types_->resize(index + 1);
1085 }
1086 (*attr_types_)[index] = value;
1087 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
1088}
1089
jbauchf1f87202016-03-30 06:43:37 -07001090bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +01001091 if (length() % 2) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001092 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +01001093 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001094
1095 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001096 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001097 if (!buf->ReadUInt16(&attr))
1098 return false;
1099 attr_types_->push_back(attr);
1100 }
1101 // Padding of these attributes is done in RFC 5389 style. This is
1102 // slightly different from RFC3489, but it shouldn't be important.
1103 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
1104 // entries in the list (not necessarily the last one - it's unspecified).
1105 // RFC5389 pads on the end, and the bytes are always ignored.
1106 ConsumePadding(buf);
1107 return true;
1108}
1109
jbauchf1f87202016-03-30 06:43:37 -07001110bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001111 for (size_t i = 0; i < attr_types_->size(); ++i) {
1112 buf->WriteUInt16((*attr_types_)[i]);
1113 }
1114 WritePadding(buf);
1115 return true;
1116}
1117
1118int GetStunSuccessResponseType(int req_type) {
1119 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
1120}
1121
1122int GetStunErrorResponseType(int req_type) {
1123 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
1124}
1125
1126bool IsStunRequestType(int msg_type) {
1127 return ((msg_type & kStunTypeMask) == 0x000);
1128}
1129
1130bool IsStunIndicationType(int msg_type) {
1131 return ((msg_type & kStunTypeMask) == 0x010);
1132}
1133
1134bool IsStunSuccessResponseType(int msg_type) {
1135 return ((msg_type & kStunTypeMask) == 0x100);
1136}
1137
1138bool IsStunErrorResponseType(int msg_type) {
1139 return ((msg_type & kStunTypeMask) == 0x110);
1140}
1141
1142bool ComputeStunCredentialHash(const std::string& username,
1143 const std::string& realm,
1144 const std::string& password,
1145 std::string* hash) {
1146 // http://tools.ietf.org/html/rfc5389#section-15.4
1147 // long-term credentials will be calculated using the key and key is
1148 // key = MD5(username ":" realm ":" SASLprep(password))
1149 std::string input = username;
1150 input += ':';
1151 input += realm;
1152 input += ':';
1153 input += password;
1154
1155 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001156 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1157 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001158 if (size == 0) {
1159 return false;
1160 }
1161
1162 *hash = std::string(digest, size);
1163 return true;
1164}
1165
Jonas Oreland202994c2017-12-18 12:10:43 +01001166std::unique_ptr<StunAttribute> CopyStunAttribute(
1167 const StunAttribute& attribute,
1168 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1169 ByteBufferWriter tmpBuffer;
1170 if (tmp_buffer_ptr == nullptr) {
1171 tmp_buffer_ptr = &tmpBuffer;
1172 }
1173
Yves Gerey665174f2018-06-19 15:03:05 +02001174 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1175 attribute.value_type(), attribute.type(),
1176 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001177
1178 if (!copy) {
1179 return nullptr;
1180 }
1181 tmp_buffer_ptr->Clear();
1182 if (!attribute.Write(tmp_buffer_ptr)) {
1183 return nullptr;
1184 }
1185 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1186 if (!copy->Read(&reader)) {
1187 return nullptr;
1188 }
1189
1190 return copy;
1191}
1192
Steve Antonca7d54e2017-10-25 14:42:51 -07001193StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1194 switch (type) {
1195 case STUN_ATTR_LIFETIME:
1196 return STUN_VALUE_UINT32;
1197 case STUN_ATTR_MAGIC_COOKIE:
1198 return STUN_VALUE_BYTE_STRING;
1199 case STUN_ATTR_BANDWIDTH:
1200 return STUN_VALUE_UINT32;
1201 case STUN_ATTR_DESTINATION_ADDRESS:
1202 return STUN_VALUE_ADDRESS;
1203 case STUN_ATTR_SOURCE_ADDRESS2:
1204 return STUN_VALUE_ADDRESS;
1205 case STUN_ATTR_DATA:
1206 return STUN_VALUE_BYTE_STRING;
1207 case STUN_ATTR_OPTIONS:
1208 return STUN_VALUE_UINT32;
1209 default:
1210 return StunMessage::GetAttributeValueType(type);
1211 }
1212}
1213
1214StunMessage* RelayMessage::CreateNew() const {
1215 return new RelayMessage();
1216}
1217
1218StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1219 switch (type) {
1220 case STUN_ATTR_CHANNEL_NUMBER:
1221 return STUN_VALUE_UINT32;
1222 case STUN_ATTR_TURN_LIFETIME:
1223 return STUN_VALUE_UINT32;
1224 case STUN_ATTR_XOR_PEER_ADDRESS:
1225 return STUN_VALUE_XOR_ADDRESS;
1226 case STUN_ATTR_DATA:
1227 return STUN_VALUE_BYTE_STRING;
1228 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1229 return STUN_VALUE_XOR_ADDRESS;
1230 case STUN_ATTR_EVEN_PORT:
1231 return STUN_VALUE_BYTE_STRING;
1232 case STUN_ATTR_REQUESTED_TRANSPORT:
1233 return STUN_VALUE_UINT32;
1234 case STUN_ATTR_DONT_FRAGMENT:
1235 return STUN_VALUE_BYTE_STRING;
1236 case STUN_ATTR_RESERVATION_TOKEN:
1237 return STUN_VALUE_BYTE_STRING;
1238 default:
1239 return StunMessage::GetAttributeValueType(type);
1240 }
1241}
1242
1243StunMessage* TurnMessage::CreateNew() const {
1244 return new TurnMessage();
1245}
1246
1247StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1248 switch (type) {
1249 case STUN_ATTR_PRIORITY:
1250 case STUN_ATTR_NETWORK_INFO:
1251 case STUN_ATTR_NOMINATION:
1252 return STUN_VALUE_UINT32;
1253 case STUN_ATTR_USE_CANDIDATE:
1254 return STUN_VALUE_BYTE_STRING;
1255 case STUN_ATTR_ICE_CONTROLLED:
1256 return STUN_VALUE_UINT64;
1257 case STUN_ATTR_ICE_CONTROLLING:
1258 return STUN_VALUE_UINT64;
1259 default:
1260 return StunMessage::GetAttributeValueType(type);
1261 }
1262}
1263
1264StunMessage* IceMessage::CreateNew() const {
1265 return new IceMessage();
1266}
1267
Jonas Oreland253d50f2019-11-28 17:08:07 +01001268std::unique_ptr<StunMessage> StunMessage::Clone() const {
1269 std::unique_ptr<StunMessage> copy(CreateNew());
1270 if (!copy) {
1271 return nullptr;
1272 }
1273 rtc::ByteBufferWriter buf;
1274 if (!Write(&buf)) {
1275 return nullptr;
1276 }
1277 rtc::ByteBufferReader reader(buf);
1278 if (!copy->Read(&reader)) {
1279 return nullptr;
1280 }
1281 return copy;
1282}
1283
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001284} // namespace cricket