blob: dba0c4d804b8141d83d7b1d1116dcd41dc73f3ef [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "p2p/base/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
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000135const StunAddressAttribute* StunMessage::GetAddress(int type) const {
136 switch (type) {
137 case STUN_ATTR_MAPPED_ADDRESS: {
138 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
139 // missing.
140 const StunAttribute* mapped_address =
141 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
142 if (!mapped_address)
143 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
144 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
145 }
146
147 default:
148 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
149 }
150}
151
152const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
153 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
154}
155
156const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
157 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
158}
159
160const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
161 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
162}
163
164const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
165 return static_cast<const StunErrorCodeAttribute*>(
166 GetAttribute(STUN_ATTR_ERROR_CODE));
167}
168
deadbeef996fc6b2017-04-26 09:21:22 -0700169int StunMessage::GetErrorCodeValue() const {
170 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
171 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
172}
173
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000174const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
175 return static_cast<const StunUInt16ListAttribute*>(
176 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
177}
178
179// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
180// procedure outlined in RFC 5389, section 15.4.
Yves Gerey665174f2018-06-19 15:03:05 +0200181bool StunMessage::ValidateMessageIntegrity(const char* data,
182 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000183 const std::string& password) {
184 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700185 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000186 return false;
187 }
188
189 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200190 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000191 if (size != (msg_length + kStunHeaderSize)) {
192 return false;
193 }
194
195 // Finding Message Integrity attribute in stun message.
196 size_t current_pos = kStunHeaderSize;
197 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700198 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200199 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000200 // Getting attribute type and length.
201 attr_type = rtc::GetBE16(&data[current_pos]);
202 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
203
204 // If M-I, sanity check it, and break out.
205 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
206 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700207 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
208 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000209 return false;
210 }
211 has_message_integrity_attr = true;
212 break;
213 }
214
215 // Otherwise, skip to the next attribute.
216 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
217 if ((attr_length % 4) != 0) {
218 current_pos += (4 - (attr_length % 4));
219 }
220 }
221
222 if (!has_message_integrity_attr) {
223 return false;
224 }
225
226 // Getting length of the message to calculate Message Integrity.
227 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700228 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000229 memcpy(temp_data.get(), data, current_pos);
230 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
231 // Stun message has other attributes after message integrity.
232 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200233 size_t extra_offset =
234 size - (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000235 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
236
237 // Writing new length of the STUN message @ Message Length in temp buffer.
238 // 0 1 2 3
239 // 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
240 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
241 // |0 0| STUN Message Type | Message Length |
242 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200243 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000244 }
245
246 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200247 size_t ret =
248 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
249 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800250 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000251 if (ret != sizeof(hmac))
252 return false;
253
254 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200255 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000256 sizeof(hmac)) == 0;
257}
258
259bool StunMessage::AddMessageIntegrity(const std::string& password) {
260 return AddMessageIntegrity(password.c_str(), password.size());
261}
262
Yves Gerey665174f2018-06-19 15:03:05 +0200263bool StunMessage::AddMessageIntegrity(const char* key, size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000264 // Add the attribute with a dummy value. Since this is a known attribute, it
265 // can't fail.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200266 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
zsteinf42cc9d2017-03-27 16:17:19 -0700267 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
268 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
269 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000270
271 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700272 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000273 if (!Write(&buf))
274 return false;
275
276 int msg_len_for_hmac = static_cast<int>(
277 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
278 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200279 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
280 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800281 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000282 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100283 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200284 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000285 return false;
286 }
287
288 // Insert correct HMAC into the attribute.
289 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
290 return true;
291}
292
293// Verifies a message is in fact a STUN message, by performing the checks
294// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
295// in section 15.5.
296bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
297 // Check the message length.
298 size_t fingerprint_attr_size =
299 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
300 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
301 return false;
302
303 // Skip the rest if the magic cookie isn't present.
304 const char* magic_cookie =
305 data + kStunTransactionIdOffset - kStunMagicCookieLength;
306 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
307 return false;
308
309 // Check the fingerprint type and length.
310 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
311 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200312 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000313 StunUInt32Attribute::SIZE)
314 return false;
315
316 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200317 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000318 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
319 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200320 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000321}
322
323bool StunMessage::AddFingerprint() {
324 // Add the attribute with a dummy value. Since this is a known attribute,
325 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700326 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200327 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700328 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700329 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000330
331 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700332 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000333 if (!Write(&buf))
334 return false;
335
336 int msg_len_for_crc32 = static_cast<int>(
337 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200338 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000339
340 // Insert the correct CRC-32, XORed with a constant, into the attribute.
341 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
342 return true;
343}
344
jbauchf1f87202016-03-30 06:43:37 -0700345bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000346 if (!buf->ReadUInt16(&type_))
347 return false;
348
349 if (type_ & 0x8000) {
350 // RTP and RTCP set the MSB of first byte, since first two bits are version,
351 // and version is always 2 (10). If set, this is not a STUN packet.
352 return false;
353 }
354
355 if (!buf->ReadUInt16(&length_))
356 return false;
357
358 std::string magic_cookie;
359 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
360 return false;
361
362 std::string transaction_id;
363 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
364 return false;
365
Andrew Royes154d8392019-03-14 10:38:31 -0700366 uint32_t magic_cookie_int;
367 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
368 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
369 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000370 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
371 // If magic cookie is invalid it means that the peer implements
372 // RFC3489 instead of RFC5389.
373 transaction_id.insert(0, magic_cookie);
374 }
nisseede5da42017-01-12 05:15:36 -0800375 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000376 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800377 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000378
379 if (length_ != buf->Length())
380 return false;
381
zsteinad94c4c2017-03-06 13:36:05 -0800382 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000383
384 size_t rest = buf->Length() - length_;
385 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200386 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000387 if (!buf->ReadUInt16(&attr_type))
388 return false;
389 if (!buf->ReadUInt16(&attr_length))
390 return false;
391
Honghai Zhang3e024302016-09-22 09:52:16 -0700392 std::unique_ptr<StunAttribute> attr(
393 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000394 if (!attr) {
395 // Skip any unknown or malformed attributes.
396 if ((attr_length % 4) != 0) {
397 attr_length += (4 - (attr_length % 4));
398 }
399 if (!buf->Consume(attr_length))
400 return false;
401 } else {
402 if (!attr->Read(buf))
403 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800404 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000405 }
406 }
407
nisseede5da42017-01-12 05:15:36 -0800408 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000409 return true;
410}
411
jbauchf1f87202016-03-30 06:43:37 -0700412bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413 buf->WriteUInt16(type_);
414 buf->WriteUInt16(length_);
415 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100416 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000417 buf->WriteString(transaction_id_);
418
zsteinad94c4c2017-03-06 13:36:05 -0800419 for (const auto& attr : attrs_) {
420 buf->WriteUInt16(attr->type());
421 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
422 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000423 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800424 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000425 }
426
427 return true;
428}
429
Steve Antonca7d54e2017-10-25 14:42:51 -0700430StunMessage* StunMessage::CreateNew() const {
431 return new StunMessage();
432}
433
Jonas Oreland7ca63112018-02-27 08:45:13 +0100434void StunMessage::SetStunMagicCookie(uint32_t val) {
435 stun_magic_cookie_ = val;
436}
437
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000438StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
439 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200440 case STUN_ATTR_MAPPED_ADDRESS:
441 return STUN_VALUE_ADDRESS;
442 case STUN_ATTR_USERNAME:
443 return STUN_VALUE_BYTE_STRING;
444 case STUN_ATTR_MESSAGE_INTEGRITY:
445 return STUN_VALUE_BYTE_STRING;
446 case STUN_ATTR_ERROR_CODE:
447 return STUN_VALUE_ERROR_CODE;
448 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
449 return STUN_VALUE_UINT16_LIST;
450 case STUN_ATTR_REALM:
451 return STUN_VALUE_BYTE_STRING;
452 case STUN_ATTR_NONCE:
453 return STUN_VALUE_BYTE_STRING;
454 case STUN_ATTR_XOR_MAPPED_ADDRESS:
455 return STUN_VALUE_XOR_ADDRESS;
456 case STUN_ATTR_SOFTWARE:
457 return STUN_VALUE_BYTE_STRING;
458 case STUN_ATTR_ALTERNATE_SERVER:
459 return STUN_VALUE_ADDRESS;
460 case STUN_ATTR_FINGERPRINT:
461 return STUN_VALUE_UINT32;
462 case STUN_ATTR_ORIGIN:
463 return STUN_VALUE_BYTE_STRING;
464 case STUN_ATTR_RETRANSMIT_COUNT:
465 return STUN_VALUE_UINT32;
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700466 case STUN_ATTR_LAST_ICE_CHECK_RECEIVED:
467 return STUN_VALUE_BYTE_STRING;
Yves Gerey665174f2018-06-19 15:03:05 +0200468 default:
469 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000470 }
471}
472
473StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
474 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200475 if (value_type != STUN_VALUE_UNKNOWN) {
476 return StunAttribute::Create(value_type, type,
477 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200478 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200479 // Read unknown attributes as STUN_VALUE_BYTE_STRING
480 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
481 static_cast<uint16_t>(length), this);
482 } else {
483 return NULL;
484 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000485}
486
487const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800488 for (const auto& attr : attrs_) {
489 if (attr->type() == type) {
490 return attr.get();
491 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000492 }
493 return NULL;
494}
495
496bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
497 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200498 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000499}
500
501// StunAttribute
502
Peter Boström0c4e06b2015-10-07 12:23:21 +0200503StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200504 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000505
jbauchf1f87202016-03-30 06:43:37 -0700506void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000507 int remainder = length_ % 4;
508 if (remainder > 0) {
509 buf->Consume(4 - remainder);
510 }
511}
512
jbauchf1f87202016-03-30 06:43:37 -0700513void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000514 int remainder = length_ % 4;
515 if (remainder > 0) {
516 char zeroes[4] = {0};
517 buf->WriteBytes(zeroes, 4 - remainder);
518 }
519}
520
521StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200522 uint16_t type,
523 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000524 StunMessage* owner) {
525 switch (value_type) {
526 case STUN_VALUE_ADDRESS:
527 return new StunAddressAttribute(type, length);
528 case STUN_VALUE_XOR_ADDRESS:
529 return new StunXorAddressAttribute(type, length, owner);
530 case STUN_VALUE_UINT32:
531 return new StunUInt32Attribute(type);
532 case STUN_VALUE_UINT64:
533 return new StunUInt64Attribute(type);
534 case STUN_VALUE_BYTE_STRING:
535 return new StunByteStringAttribute(type, length);
536 case STUN_VALUE_ERROR_CODE:
537 return new StunErrorCodeAttribute(type, length);
538 case STUN_VALUE_UINT16_LIST:
539 return new StunUInt16ListAttribute(type, length);
540 default:
541 return NULL;
542 }
543}
544
zsteinf42cc9d2017-03-27 16:17:19 -0700545std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
546 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200547 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000548}
549
zsteinf42cc9d2017-03-27 16:17:19 -0700550std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
551 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200552 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000553}
554
zsteinf42cc9d2017-03-27 16:17:19 -0700555std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
556 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200557 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000558}
559
zsteinf42cc9d2017-03-27 16:17:19 -0700560std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
561 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200562 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000563}
564
zsteinf42cc9d2017-03-27 16:17:19 -0700565std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
566 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200567 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000568}
569
zsteinf42cc9d2017-03-27 16:17:19 -0700570std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200571 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000572 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
573}
574
zsteinf42cc9d2017-03-27 16:17:19 -0700575std::unique_ptr<StunUInt16ListAttribute>
576StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200577 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
578 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000579}
580
Peter Boström0c4e06b2015-10-07 12:23:21 +0200581StunAddressAttribute::StunAddressAttribute(uint16_t type,
582 const rtc::SocketAddress& addr)
583 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000584 SetAddress(addr);
585}
586
Peter Boström0c4e06b2015-10-07 12:23:21 +0200587StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200588 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000589
Steve Antonca7d54e2017-10-25 14:42:51 -0700590StunAttributeValueType StunAddressAttribute::value_type() const {
591 return STUN_VALUE_ADDRESS;
592}
593
jbauchf1f87202016-03-30 06:43:37 -0700594bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200595 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000596 if (!buf->ReadUInt8(&dummy))
597 return false;
598
Peter Boström0c4e06b2015-10-07 12:23:21 +0200599 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000600 if (!buf->ReadUInt8(&stun_family)) {
601 return false;
602 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200603 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000604 if (!buf->ReadUInt16(&port))
605 return false;
606 if (stun_family == STUN_ADDRESS_IPV4) {
607 in_addr v4addr;
608 if (length() != SIZE_IP4) {
609 return false;
610 }
611 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
612 return false;
613 }
614 rtc::IPAddress ipaddr(v4addr);
615 SetAddress(rtc::SocketAddress(ipaddr, port));
616 } else if (stun_family == STUN_ADDRESS_IPV6) {
617 in6_addr v6addr;
618 if (length() != SIZE_IP6) {
619 return false;
620 }
621 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
622 return false;
623 }
624 rtc::IPAddress ipaddr(v6addr);
625 SetAddress(rtc::SocketAddress(ipaddr, port));
626 } else {
627 return false;
628 }
629 return true;
630}
631
jbauchf1f87202016-03-30 06:43:37 -0700632bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000633 StunAddressFamily address_family = family();
634 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100635 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000636 return false;
637 }
638 buf->WriteUInt8(0);
639 buf->WriteUInt8(address_family);
640 buf->WriteUInt16(address_.port());
641 switch (address_.family()) {
642 case AF_INET: {
643 in_addr v4addr = address_.ipaddr().ipv4_address();
644 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
645 break;
646 }
647 case AF_INET6: {
648 in6_addr v6addr = address_.ipaddr().ipv6_address();
649 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
650 break;
651 }
652 }
653 return true;
654}
655
Peter Boström0c4e06b2015-10-07 12:23:21 +0200656StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
657 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200658 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000659
Peter Boström0c4e06b2015-10-07 12:23:21 +0200660StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
661 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000662 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200663 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000664
Steve Antonca7d54e2017-10-25 14:42:51 -0700665StunAttributeValueType StunXorAddressAttribute::value_type() const {
666 return STUN_VALUE_XOR_ADDRESS;
667}
668
669void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
670 owner_ = owner;
671}
672
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000673rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
674 if (owner_) {
675 rtc::IPAddress ip = ipaddr();
676 switch (ip.family()) {
677 case AF_INET: {
678 in_addr v4addr = ip.ipv4_address();
679 v4addr.s_addr =
680 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
681 return rtc::IPAddress(v4addr);
682 }
683 case AF_INET6: {
684 in6_addr v6addr = ip.ipv6_address();
685 const std::string& transaction_id = owner_->transaction_id();
686 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200687 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000688 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
689 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200690 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691 // Transaction ID is in network byte order, but magic cookie
692 // is stored in host byte order.
693 ip_as_ints[0] =
694 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
695 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
696 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
697 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
698 return rtc::IPAddress(v6addr);
699 }
700 break;
701 }
702 }
703 }
704 // Invalid ip family or transaction ID, or missing owner.
705 // Return an AF_UNSPEC address.
706 return rtc::IPAddress();
707}
708
jbauchf1f87202016-03-30 06:43:37 -0700709bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000710 if (!StunAddressAttribute::Read(buf))
711 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200712 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000713 rtc::IPAddress xored_ip = GetXoredIP();
714 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
715 return true;
716}
717
jbauchf1f87202016-03-30 06:43:37 -0700718bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000719 StunAddressFamily address_family = family();
720 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100721 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000722 return false;
723 }
724 rtc::IPAddress xored_ip = GetXoredIP();
725 if (xored_ip.family() == AF_UNSPEC) {
726 return false;
727 }
728 buf->WriteUInt8(0);
729 buf->WriteUInt8(family());
730 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
731 switch (xored_ip.family()) {
732 case AF_INET: {
733 in_addr v4addr = xored_ip.ipv4_address();
734 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
735 break;
736 }
737 case AF_INET6: {
738 in6_addr v6addr = xored_ip.ipv6_address();
739 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
740 break;
741 }
742 }
743 return true;
744}
745
Peter Boström0c4e06b2015-10-07 12:23:21 +0200746StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200747 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000748
Peter Boström0c4e06b2015-10-07 12:23:21 +0200749StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200750 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000751
Steve Antonca7d54e2017-10-25 14:42:51 -0700752StunAttributeValueType StunUInt32Attribute::value_type() const {
753 return STUN_VALUE_UINT32;
754}
755
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000756bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800757 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000758 return static_cast<bool>((bits_ >> index) & 0x1);
759}
760
761void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800762 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000763 bits_ &= ~(1 << index);
764 bits_ |= value ? (1 << index) : 0;
765}
766
jbauchf1f87202016-03-30 06:43:37 -0700767bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000768 if (length() != SIZE || !buf->ReadUInt32(&bits_))
769 return false;
770 return true;
771}
772
jbauchf1f87202016-03-30 06:43:37 -0700773bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000774 buf->WriteUInt32(bits_);
775 return true;
776}
777
Peter Boström0c4e06b2015-10-07 12:23:21 +0200778StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200779 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000780
Peter Boström0c4e06b2015-10-07 12:23:21 +0200781StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200782 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000783
Steve Antonca7d54e2017-10-25 14:42:51 -0700784StunAttributeValueType StunUInt64Attribute::value_type() const {
785 return STUN_VALUE_UINT64;
786}
787
jbauchf1f87202016-03-30 06:43:37 -0700788bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000789 if (length() != SIZE || !buf->ReadUInt64(&bits_))
790 return false;
791 return true;
792}
793
jbauchf1f87202016-03-30 06:43:37 -0700794bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000795 buf->WriteUInt64(bits_);
796 return true;
797}
798
Peter Boström0c4e06b2015-10-07 12:23:21 +0200799StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200800 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000801
Peter Boström0c4e06b2015-10-07 12:23:21 +0200802StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000803 const std::string& str)
804 : StunAttribute(type, 0), bytes_(NULL) {
805 CopyBytes(str.c_str(), str.size());
806}
807
Peter Boström0c4e06b2015-10-07 12:23:21 +0200808StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000809 const void* bytes,
810 size_t length)
811 : StunAttribute(type, 0), bytes_(NULL) {
812 CopyBytes(bytes, length);
813}
814
Peter Boström0c4e06b2015-10-07 12:23:21 +0200815StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200816 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000817
818StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +0200819 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000820}
821
Steve Antonca7d54e2017-10-25 14:42:51 -0700822StunAttributeValueType StunByteStringAttribute::value_type() const {
823 return STUN_VALUE_BYTE_STRING;
824}
825
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000826void StunByteStringAttribute::CopyBytes(const char* bytes) {
827 CopyBytes(bytes, strlen(bytes));
828}
829
830void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
831 char* new_bytes = new char[length];
832 memcpy(new_bytes, bytes, length);
833 SetBytes(new_bytes, length);
834}
835
Peter Boström0c4e06b2015-10-07 12:23:21 +0200836uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800837 RTC_DCHECK(bytes_ != NULL);
838 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200839 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000840}
841
Peter Boström0c4e06b2015-10-07 12:23:21 +0200842void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800843 RTC_DCHECK(bytes_ != NULL);
844 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000845 bytes_[index] = value;
846}
847
jbauchf1f87202016-03-30 06:43:37 -0700848bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000849 bytes_ = new char[length()];
850 if (!buf->ReadBytes(bytes_, length())) {
851 return false;
852 }
853
854 ConsumePadding(buf);
855 return true;
856}
857
jbauchf1f87202016-03-30 06:43:37 -0700858bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000859 buf->WriteBytes(bytes_, length());
860 WritePadding(buf);
861 return true;
862}
863
864void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +0200865 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000866 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200867 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000868}
869
zsteinf42cc9d2017-03-27 16:17:19 -0700870const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
871
Peter Boström0c4e06b2015-10-07 12:23:21 +0200872StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
873 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000874 const std::string& reason)
875 : StunAttribute(type, 0) {
876 SetCode(code);
877 SetReason(reason);
878}
879
Peter Boström0c4e06b2015-10-07 12:23:21 +0200880StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200881 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000882
Yves Gerey665174f2018-06-19 15:03:05 +0200883StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000884
Steve Antonca7d54e2017-10-25 14:42:51 -0700885StunAttributeValueType StunErrorCodeAttribute::value_type() const {
886 return STUN_VALUE_ERROR_CODE;
887}
888
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000889int StunErrorCodeAttribute::code() const {
890 return class_ * 100 + number_;
891}
892
893void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200894 class_ = static_cast<uint8_t>(code / 100);
895 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000896}
897
898void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200899 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000900 reason_ = reason;
901}
902
jbauchf1f87202016-03-30 06:43:37 -0700903bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200904 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000905 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
906 return false;
907
908 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100909 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000910
911 class_ = ((val >> 8) & 0x7);
912 number_ = (val & 0xff);
913
914 if (!buf->ReadString(&reason_, length() - 4))
915 return false;
916
917 ConsumePadding(buf);
918 return true;
919}
920
jbauchf1f87202016-03-30 06:43:37 -0700921bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000922 buf->WriteUInt32(class_ << 8 | number_);
923 buf->WriteString(reason_);
924 WritePadding(buf);
925 return true;
926}
927
Peter Boström0c4e06b2015-10-07 12:23:21 +0200928StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000929 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200930 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000931}
932
933StunUInt16ListAttribute::~StunUInt16ListAttribute() {
934 delete attr_types_;
935}
936
Steve Antonca7d54e2017-10-25 14:42:51 -0700937StunAttributeValueType StunUInt16ListAttribute::value_type() const {
938 return STUN_VALUE_UINT16_LIST;
939}
940
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000941size_t StunUInt16ListAttribute::Size() const {
942 return attr_types_->size();
943}
944
Peter Boström0c4e06b2015-10-07 12:23:21 +0200945uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000946 return (*attr_types_)[index];
947}
948
Peter Boström0c4e06b2015-10-07 12:23:21 +0200949void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000950 (*attr_types_)[index] = value;
951}
952
Peter Boström0c4e06b2015-10-07 12:23:21 +0200953void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000954 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200955 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000956}
957
jbauchf1f87202016-03-30 06:43:37 -0700958bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000959 if (length() % 2)
960 return false;
961
962 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200963 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000964 if (!buf->ReadUInt16(&attr))
965 return false;
966 attr_types_->push_back(attr);
967 }
968 // Padding of these attributes is done in RFC 5389 style. This is
969 // slightly different from RFC3489, but it shouldn't be important.
970 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
971 // entries in the list (not necessarily the last one - it's unspecified).
972 // RFC5389 pads on the end, and the bytes are always ignored.
973 ConsumePadding(buf);
974 return true;
975}
976
jbauchf1f87202016-03-30 06:43:37 -0700977bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000978 for (size_t i = 0; i < attr_types_->size(); ++i) {
979 buf->WriteUInt16((*attr_types_)[i]);
980 }
981 WritePadding(buf);
982 return true;
983}
984
985int GetStunSuccessResponseType(int req_type) {
986 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
987}
988
989int GetStunErrorResponseType(int req_type) {
990 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
991}
992
993bool IsStunRequestType(int msg_type) {
994 return ((msg_type & kStunTypeMask) == 0x000);
995}
996
997bool IsStunIndicationType(int msg_type) {
998 return ((msg_type & kStunTypeMask) == 0x010);
999}
1000
1001bool IsStunSuccessResponseType(int msg_type) {
1002 return ((msg_type & kStunTypeMask) == 0x100);
1003}
1004
1005bool IsStunErrorResponseType(int msg_type) {
1006 return ((msg_type & kStunTypeMask) == 0x110);
1007}
1008
1009bool ComputeStunCredentialHash(const std::string& username,
1010 const std::string& realm,
1011 const std::string& password,
1012 std::string* hash) {
1013 // http://tools.ietf.org/html/rfc5389#section-15.4
1014 // long-term credentials will be calculated using the key and key is
1015 // key = MD5(username ":" realm ":" SASLprep(password))
1016 std::string input = username;
1017 input += ':';
1018 input += realm;
1019 input += ':';
1020 input += password;
1021
1022 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001023 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1024 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001025 if (size == 0) {
1026 return false;
1027 }
1028
1029 *hash = std::string(digest, size);
1030 return true;
1031}
1032
Jonas Oreland202994c2017-12-18 12:10:43 +01001033std::unique_ptr<StunAttribute> CopyStunAttribute(
1034 const StunAttribute& attribute,
1035 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1036 ByteBufferWriter tmpBuffer;
1037 if (tmp_buffer_ptr == nullptr) {
1038 tmp_buffer_ptr = &tmpBuffer;
1039 }
1040
Yves Gerey665174f2018-06-19 15:03:05 +02001041 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1042 attribute.value_type(), attribute.type(),
1043 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001044
1045 if (!copy) {
1046 return nullptr;
1047 }
1048 tmp_buffer_ptr->Clear();
1049 if (!attribute.Write(tmp_buffer_ptr)) {
1050 return nullptr;
1051 }
1052 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1053 if (!copy->Read(&reader)) {
1054 return nullptr;
1055 }
1056
1057 return copy;
1058}
1059
Steve Antonca7d54e2017-10-25 14:42:51 -07001060StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1061 switch (type) {
1062 case STUN_ATTR_LIFETIME:
1063 return STUN_VALUE_UINT32;
1064 case STUN_ATTR_MAGIC_COOKIE:
1065 return STUN_VALUE_BYTE_STRING;
1066 case STUN_ATTR_BANDWIDTH:
1067 return STUN_VALUE_UINT32;
1068 case STUN_ATTR_DESTINATION_ADDRESS:
1069 return STUN_VALUE_ADDRESS;
1070 case STUN_ATTR_SOURCE_ADDRESS2:
1071 return STUN_VALUE_ADDRESS;
1072 case STUN_ATTR_DATA:
1073 return STUN_VALUE_BYTE_STRING;
1074 case STUN_ATTR_OPTIONS:
1075 return STUN_VALUE_UINT32;
1076 default:
1077 return StunMessage::GetAttributeValueType(type);
1078 }
1079}
1080
1081StunMessage* RelayMessage::CreateNew() const {
1082 return new RelayMessage();
1083}
1084
1085StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1086 switch (type) {
1087 case STUN_ATTR_CHANNEL_NUMBER:
1088 return STUN_VALUE_UINT32;
1089 case STUN_ATTR_TURN_LIFETIME:
1090 return STUN_VALUE_UINT32;
1091 case STUN_ATTR_XOR_PEER_ADDRESS:
1092 return STUN_VALUE_XOR_ADDRESS;
1093 case STUN_ATTR_DATA:
1094 return STUN_VALUE_BYTE_STRING;
1095 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1096 return STUN_VALUE_XOR_ADDRESS;
1097 case STUN_ATTR_EVEN_PORT:
1098 return STUN_VALUE_BYTE_STRING;
1099 case STUN_ATTR_REQUESTED_TRANSPORT:
1100 return STUN_VALUE_UINT32;
1101 case STUN_ATTR_DONT_FRAGMENT:
1102 return STUN_VALUE_BYTE_STRING;
1103 case STUN_ATTR_RESERVATION_TOKEN:
1104 return STUN_VALUE_BYTE_STRING;
1105 default:
1106 return StunMessage::GetAttributeValueType(type);
1107 }
1108}
1109
1110StunMessage* TurnMessage::CreateNew() const {
1111 return new TurnMessage();
1112}
1113
1114StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1115 switch (type) {
1116 case STUN_ATTR_PRIORITY:
1117 case STUN_ATTR_NETWORK_INFO:
1118 case STUN_ATTR_NOMINATION:
1119 return STUN_VALUE_UINT32;
1120 case STUN_ATTR_USE_CANDIDATE:
1121 return STUN_VALUE_BYTE_STRING;
1122 case STUN_ATTR_ICE_CONTROLLED:
1123 return STUN_VALUE_UINT64;
1124 case STUN_ATTR_ICE_CONTROLLING:
1125 return STUN_VALUE_UINT64;
1126 default:
1127 return StunMessage::GetAttributeValueType(type);
1128 }
1129}
1130
1131StunMessage* IceMessage::CreateNew() const {
1132 return new IceMessage();
1133}
1134
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001135} // namespace cricket