blob: 7fa3c90bf123f61a5ef06ab2538c230c822344e4 [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
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
Jonas Oreland1721de12019-11-20 12:10:39 +0100164const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
165 return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
166}
167
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000168const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
169 return static_cast<const StunErrorCodeAttribute*>(
170 GetAttribute(STUN_ATTR_ERROR_CODE));
171}
172
deadbeef996fc6b2017-04-26 09:21:22 -0700173int StunMessage::GetErrorCodeValue() const {
174 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
175 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
176}
177
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000178const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
179 return static_cast<const StunUInt16ListAttribute*>(
180 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
181}
182
183// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
184// procedure outlined in RFC 5389, section 15.4.
Yves Gerey665174f2018-06-19 15:03:05 +0200185bool StunMessage::ValidateMessageIntegrity(const char* data,
186 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000187 const std::string& password) {
188 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700189 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000190 return false;
191 }
192
193 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200194 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000195 if (size != (msg_length + kStunHeaderSize)) {
196 return false;
197 }
198
199 // Finding Message Integrity attribute in stun message.
200 size_t current_pos = kStunHeaderSize;
201 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700202 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200203 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000204 // Getting attribute type and length.
205 attr_type = rtc::GetBE16(&data[current_pos]);
206 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
207
208 // If M-I, sanity check it, and break out.
209 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
210 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700211 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
212 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000213 return false;
214 }
215 has_message_integrity_attr = true;
216 break;
217 }
218
219 // Otherwise, skip to the next attribute.
220 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
221 if ((attr_length % 4) != 0) {
222 current_pos += (4 - (attr_length % 4));
223 }
224 }
225
226 if (!has_message_integrity_attr) {
227 return false;
228 }
229
230 // Getting length of the message to calculate Message Integrity.
231 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700232 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000233 memcpy(temp_data.get(), data, current_pos);
234 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
235 // Stun message has other attributes after message integrity.
236 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200237 size_t extra_offset =
238 size - (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000239 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
240
241 // Writing new length of the STUN message @ Message Length in temp buffer.
242 // 0 1 2 3
243 // 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
244 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
245 // |0 0| STUN Message Type | Message Length |
246 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200247 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000248 }
249
250 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200251 size_t ret =
252 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
253 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800254 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000255 if (ret != sizeof(hmac))
256 return false;
257
258 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200259 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000260 sizeof(hmac)) == 0;
261}
262
263bool StunMessage::AddMessageIntegrity(const std::string& password) {
264 return AddMessageIntegrity(password.c_str(), password.size());
265}
266
Yves Gerey665174f2018-06-19 15:03:05 +0200267bool StunMessage::AddMessageIntegrity(const char* key, size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000268 // Add the attribute with a dummy value. Since this is a known attribute, it
269 // can't fail.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200270 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
zsteinf42cc9d2017-03-27 16:17:19 -0700271 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
272 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
273 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000274
275 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700276 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000277 if (!Write(&buf))
278 return false;
279
280 int msg_len_for_hmac = static_cast<int>(
281 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
282 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200283 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
284 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800285 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000286 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100287 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200288 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000289 return false;
290 }
291
292 // Insert correct HMAC into the attribute.
293 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
294 return true;
295}
296
297// Verifies a message is in fact a STUN message, by performing the checks
298// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
299// in section 15.5.
300bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
301 // Check the message length.
302 size_t fingerprint_attr_size =
303 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
304 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
305 return false;
306
307 // Skip the rest if the magic cookie isn't present.
308 const char* magic_cookie =
309 data + kStunTransactionIdOffset - kStunMagicCookieLength;
310 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
311 return false;
312
313 // Check the fingerprint type and length.
314 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
315 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200316 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000317 StunUInt32Attribute::SIZE)
318 return false;
319
320 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200321 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000322 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
323 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200324 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000325}
326
327bool StunMessage::AddFingerprint() {
328 // Add the attribute with a dummy value. Since this is a known attribute,
329 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700330 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200331 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700332 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700333 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000334
335 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700336 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000337 if (!Write(&buf))
338 return false;
339
340 int msg_len_for_crc32 = static_cast<int>(
341 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200342 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000343
344 // Insert the correct CRC-32, XORed with a constant, into the attribute.
345 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
346 return true;
347}
348
jbauchf1f87202016-03-30 06:43:37 -0700349bool StunMessage::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +0100350 if (!buf->ReadUInt16(&type_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100352 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000353
354 if (type_ & 0x8000) {
355 // RTP and RTCP set the MSB of first byte, since first two bits are version,
356 // and version is always 2 (10). If set, this is not a STUN packet.
357 return false;
358 }
359
Jonas Oreland1721de12019-11-20 12:10:39 +0100360 if (!buf->ReadUInt16(&length_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000361 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100362 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000363
364 std::string magic_cookie;
Jonas Oreland1721de12019-11-20 12:10:39 +0100365 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000366 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100367 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000368
369 std::string transaction_id;
Jonas Oreland1721de12019-11-20 12:10:39 +0100370 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100372 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000373
Andrew Royes154d8392019-03-14 10:38:31 -0700374 uint32_t magic_cookie_int;
375 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
376 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
377 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000378 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
379 // If magic cookie is invalid it means that the peer implements
380 // RFC3489 instead of RFC5389.
381 transaction_id.insert(0, magic_cookie);
382 }
nisseede5da42017-01-12 05:15:36 -0800383 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000384 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800385 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000386
Jonas Oreland1721de12019-11-20 12:10:39 +0100387 if (length_ != buf->Length()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000388 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100389 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000390
zsteinad94c4c2017-03-06 13:36:05 -0800391 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000392
393 size_t rest = buf->Length() - length_;
394 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200395 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000396 if (!buf->ReadUInt16(&attr_type))
397 return false;
398 if (!buf->ReadUInt16(&attr_length))
399 return false;
400
Honghai Zhang3e024302016-09-22 09:52:16 -0700401 std::unique_ptr<StunAttribute> attr(
402 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000403 if (!attr) {
404 // Skip any unknown or malformed attributes.
405 if ((attr_length % 4) != 0) {
406 attr_length += (4 - (attr_length % 4));
407 }
Jonas Oreland1721de12019-11-20 12:10:39 +0100408 if (!buf->Consume(attr_length)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000409 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100410 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000411 } else {
Jonas Oreland1721de12019-11-20 12:10:39 +0100412 if (!attr->Read(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000413 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100414 }
zsteinad94c4c2017-03-06 13:36:05 -0800415 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000416 }
417 }
418
nisseede5da42017-01-12 05:15:36 -0800419 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000420 return true;
421}
422
jbauchf1f87202016-03-30 06:43:37 -0700423bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000424 buf->WriteUInt16(type_);
425 buf->WriteUInt16(length_);
426 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100427 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000428 buf->WriteString(transaction_id_);
429
zsteinad94c4c2017-03-06 13:36:05 -0800430 for (const auto& attr : attrs_) {
431 buf->WriteUInt16(attr->type());
432 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
433 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000434 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800435 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000436 }
437
438 return true;
439}
440
Steve Antonca7d54e2017-10-25 14:42:51 -0700441StunMessage* StunMessage::CreateNew() const {
442 return new StunMessage();
443}
444
Jonas Oreland7ca63112018-02-27 08:45:13 +0100445void StunMessage::SetStunMagicCookie(uint32_t val) {
446 stun_magic_cookie_ = val;
447}
448
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000449StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
450 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200451 case STUN_ATTR_MAPPED_ADDRESS:
452 return STUN_VALUE_ADDRESS;
453 case STUN_ATTR_USERNAME:
454 return STUN_VALUE_BYTE_STRING;
455 case STUN_ATTR_MESSAGE_INTEGRITY:
456 return STUN_VALUE_BYTE_STRING;
457 case STUN_ATTR_ERROR_CODE:
458 return STUN_VALUE_ERROR_CODE;
459 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
460 return STUN_VALUE_UINT16_LIST;
461 case STUN_ATTR_REALM:
462 return STUN_VALUE_BYTE_STRING;
463 case STUN_ATTR_NONCE:
464 return STUN_VALUE_BYTE_STRING;
465 case STUN_ATTR_XOR_MAPPED_ADDRESS:
466 return STUN_VALUE_XOR_ADDRESS;
467 case STUN_ATTR_SOFTWARE:
468 return STUN_VALUE_BYTE_STRING;
469 case STUN_ATTR_ALTERNATE_SERVER:
470 return STUN_VALUE_ADDRESS;
471 case STUN_ATTR_FINGERPRINT:
472 return STUN_VALUE_UINT32;
473 case STUN_ATTR_ORIGIN:
474 return STUN_VALUE_BYTE_STRING;
475 case STUN_ATTR_RETRANSMIT_COUNT:
476 return STUN_VALUE_UINT32;
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700477 case STUN_ATTR_LAST_ICE_CHECK_RECEIVED:
478 return STUN_VALUE_BYTE_STRING;
Jonas Oreland1721de12019-11-20 12:10:39 +0100479 case STUN_ATTR_GOOG_MISC_INFO:
480 return STUN_VALUE_UINT16_LIST;
Yves Gerey665174f2018-06-19 15:03:05 +0200481 default:
482 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000483 }
484}
485
486StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
487 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200488 if (value_type != STUN_VALUE_UNKNOWN) {
489 return StunAttribute::Create(value_type, type,
490 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200491 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200492 // Read unknown attributes as STUN_VALUE_BYTE_STRING
493 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
494 static_cast<uint16_t>(length), this);
495 } else {
496 return NULL;
497 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000498}
499
500const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800501 for (const auto& attr : attrs_) {
502 if (attr->type() == type) {
503 return attr.get();
504 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000505 }
506 return NULL;
507}
508
509bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
510 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200511 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000512}
513
514// StunAttribute
515
Peter Boström0c4e06b2015-10-07 12:23:21 +0200516StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200517 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000518
jbauchf1f87202016-03-30 06:43:37 -0700519void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000520 int remainder = length_ % 4;
521 if (remainder > 0) {
522 buf->Consume(4 - remainder);
523 }
524}
525
jbauchf1f87202016-03-30 06:43:37 -0700526void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000527 int remainder = length_ % 4;
528 if (remainder > 0) {
529 char zeroes[4] = {0};
530 buf->WriteBytes(zeroes, 4 - remainder);
531 }
532}
533
534StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200535 uint16_t type,
536 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000537 StunMessage* owner) {
538 switch (value_type) {
539 case STUN_VALUE_ADDRESS:
540 return new StunAddressAttribute(type, length);
541 case STUN_VALUE_XOR_ADDRESS:
542 return new StunXorAddressAttribute(type, length, owner);
543 case STUN_VALUE_UINT32:
544 return new StunUInt32Attribute(type);
545 case STUN_VALUE_UINT64:
546 return new StunUInt64Attribute(type);
547 case STUN_VALUE_BYTE_STRING:
548 return new StunByteStringAttribute(type, length);
549 case STUN_VALUE_ERROR_CODE:
550 return new StunErrorCodeAttribute(type, length);
551 case STUN_VALUE_UINT16_LIST:
552 return new StunUInt16ListAttribute(type, length);
553 default:
554 return NULL;
555 }
556}
557
zsteinf42cc9d2017-03-27 16:17:19 -0700558std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
559 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200560 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000561}
562
zsteinf42cc9d2017-03-27 16:17:19 -0700563std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
564 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200565 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000566}
567
zsteinf42cc9d2017-03-27 16:17:19 -0700568std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
569 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200570 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000571}
572
zsteinf42cc9d2017-03-27 16:17:19 -0700573std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
574 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200575 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000576}
577
zsteinf42cc9d2017-03-27 16:17:19 -0700578std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
579 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200580 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000581}
582
zsteinf42cc9d2017-03-27 16:17:19 -0700583std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200584 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000585 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
586}
587
zsteinf42cc9d2017-03-27 16:17:19 -0700588std::unique_ptr<StunUInt16ListAttribute>
Jonas Oreland1721de12019-11-20 12:10:39 +0100589StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
590 return std::make_unique<StunUInt16ListAttribute>(type, 0);
591}
592
593std::unique_ptr<StunUInt16ListAttribute>
zsteinf42cc9d2017-03-27 16:17:19 -0700594StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200595 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
596 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000597}
598
Peter Boström0c4e06b2015-10-07 12:23:21 +0200599StunAddressAttribute::StunAddressAttribute(uint16_t type,
600 const rtc::SocketAddress& addr)
601 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000602 SetAddress(addr);
603}
604
Peter Boström0c4e06b2015-10-07 12:23:21 +0200605StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200606 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000607
Steve Antonca7d54e2017-10-25 14:42:51 -0700608StunAttributeValueType StunAddressAttribute::value_type() const {
609 return STUN_VALUE_ADDRESS;
610}
611
jbauchf1f87202016-03-30 06:43:37 -0700612bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200613 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000614 if (!buf->ReadUInt8(&dummy))
615 return false;
616
Peter Boström0c4e06b2015-10-07 12:23:21 +0200617 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000618 if (!buf->ReadUInt8(&stun_family)) {
619 return false;
620 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200621 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000622 if (!buf->ReadUInt16(&port))
623 return false;
624 if (stun_family == STUN_ADDRESS_IPV4) {
625 in_addr v4addr;
626 if (length() != SIZE_IP4) {
627 return false;
628 }
629 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
630 return false;
631 }
632 rtc::IPAddress ipaddr(v4addr);
633 SetAddress(rtc::SocketAddress(ipaddr, port));
634 } else if (stun_family == STUN_ADDRESS_IPV6) {
635 in6_addr v6addr;
636 if (length() != SIZE_IP6) {
637 return false;
638 }
639 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
640 return false;
641 }
642 rtc::IPAddress ipaddr(v6addr);
643 SetAddress(rtc::SocketAddress(ipaddr, port));
644 } else {
645 return false;
646 }
647 return true;
648}
649
jbauchf1f87202016-03-30 06:43:37 -0700650bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000651 StunAddressFamily address_family = family();
652 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100653 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000654 return false;
655 }
656 buf->WriteUInt8(0);
657 buf->WriteUInt8(address_family);
658 buf->WriteUInt16(address_.port());
659 switch (address_.family()) {
660 case AF_INET: {
661 in_addr v4addr = address_.ipaddr().ipv4_address();
662 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
663 break;
664 }
665 case AF_INET6: {
666 in6_addr v6addr = address_.ipaddr().ipv6_address();
667 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
668 break;
669 }
670 }
671 return true;
672}
673
Peter Boström0c4e06b2015-10-07 12:23:21 +0200674StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
675 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200676 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000677
Peter Boström0c4e06b2015-10-07 12:23:21 +0200678StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
679 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000680 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200681 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000682
Steve Antonca7d54e2017-10-25 14:42:51 -0700683StunAttributeValueType StunXorAddressAttribute::value_type() const {
684 return STUN_VALUE_XOR_ADDRESS;
685}
686
687void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
688 owner_ = owner;
689}
690
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
692 if (owner_) {
693 rtc::IPAddress ip = ipaddr();
694 switch (ip.family()) {
695 case AF_INET: {
696 in_addr v4addr = ip.ipv4_address();
697 v4addr.s_addr =
698 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
699 return rtc::IPAddress(v4addr);
700 }
701 case AF_INET6: {
702 in6_addr v6addr = ip.ipv6_address();
703 const std::string& transaction_id = owner_->transaction_id();
704 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200705 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000706 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
707 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200708 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000709 // Transaction ID is in network byte order, but magic cookie
710 // is stored in host byte order.
711 ip_as_ints[0] =
712 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
713 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
714 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
715 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
716 return rtc::IPAddress(v6addr);
717 }
718 break;
719 }
720 }
721 }
722 // Invalid ip family or transaction ID, or missing owner.
723 // Return an AF_UNSPEC address.
724 return rtc::IPAddress();
725}
726
jbauchf1f87202016-03-30 06:43:37 -0700727bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000728 if (!StunAddressAttribute::Read(buf))
729 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200730 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000731 rtc::IPAddress xored_ip = GetXoredIP();
732 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
733 return true;
734}
735
jbauchf1f87202016-03-30 06:43:37 -0700736bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000737 StunAddressFamily address_family = family();
738 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100739 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000740 return false;
741 }
742 rtc::IPAddress xored_ip = GetXoredIP();
743 if (xored_ip.family() == AF_UNSPEC) {
744 return false;
745 }
746 buf->WriteUInt8(0);
747 buf->WriteUInt8(family());
748 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
749 switch (xored_ip.family()) {
750 case AF_INET: {
751 in_addr v4addr = xored_ip.ipv4_address();
752 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
753 break;
754 }
755 case AF_INET6: {
756 in6_addr v6addr = xored_ip.ipv6_address();
757 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
758 break;
759 }
760 }
761 return true;
762}
763
Peter Boström0c4e06b2015-10-07 12:23:21 +0200764StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200765 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000766
Peter Boström0c4e06b2015-10-07 12:23:21 +0200767StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200768 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000769
Steve Antonca7d54e2017-10-25 14:42:51 -0700770StunAttributeValueType StunUInt32Attribute::value_type() const {
771 return STUN_VALUE_UINT32;
772}
773
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000774bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800775 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000776 return static_cast<bool>((bits_ >> index) & 0x1);
777}
778
779void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800780 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000781 bits_ &= ~(1 << index);
782 bits_ |= value ? (1 << index) : 0;
783}
784
jbauchf1f87202016-03-30 06:43:37 -0700785bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000786 if (length() != SIZE || !buf->ReadUInt32(&bits_))
787 return false;
788 return true;
789}
790
jbauchf1f87202016-03-30 06:43:37 -0700791bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000792 buf->WriteUInt32(bits_);
793 return true;
794}
795
Peter Boström0c4e06b2015-10-07 12:23:21 +0200796StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200797 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000798
Peter Boström0c4e06b2015-10-07 12:23:21 +0200799StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200800 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000801
Steve Antonca7d54e2017-10-25 14:42:51 -0700802StunAttributeValueType StunUInt64Attribute::value_type() const {
803 return STUN_VALUE_UINT64;
804}
805
jbauchf1f87202016-03-30 06:43:37 -0700806bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000807 if (length() != SIZE || !buf->ReadUInt64(&bits_))
808 return false;
809 return true;
810}
811
jbauchf1f87202016-03-30 06:43:37 -0700812bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000813 buf->WriteUInt64(bits_);
814 return true;
815}
816
Peter Boström0c4e06b2015-10-07 12:23:21 +0200817StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200818 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000819
Peter Boström0c4e06b2015-10-07 12:23:21 +0200820StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000821 const std::string& str)
822 : StunAttribute(type, 0), bytes_(NULL) {
823 CopyBytes(str.c_str(), str.size());
824}
825
Peter Boström0c4e06b2015-10-07 12:23:21 +0200826StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000827 const void* bytes,
828 size_t length)
829 : StunAttribute(type, 0), bytes_(NULL) {
830 CopyBytes(bytes, length);
831}
832
Peter Boström0c4e06b2015-10-07 12:23:21 +0200833StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200834 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000835
836StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +0200837 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000838}
839
Steve Antonca7d54e2017-10-25 14:42:51 -0700840StunAttributeValueType StunByteStringAttribute::value_type() const {
841 return STUN_VALUE_BYTE_STRING;
842}
843
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000844void StunByteStringAttribute::CopyBytes(const char* bytes) {
845 CopyBytes(bytes, strlen(bytes));
846}
847
848void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
849 char* new_bytes = new char[length];
850 memcpy(new_bytes, bytes, length);
851 SetBytes(new_bytes, length);
852}
853
Peter Boström0c4e06b2015-10-07 12:23:21 +0200854uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800855 RTC_DCHECK(bytes_ != NULL);
856 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200857 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000858}
859
Peter Boström0c4e06b2015-10-07 12:23:21 +0200860void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800861 RTC_DCHECK(bytes_ != NULL);
862 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000863 bytes_[index] = value;
864}
865
jbauchf1f87202016-03-30 06:43:37 -0700866bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000867 bytes_ = new char[length()];
868 if (!buf->ReadBytes(bytes_, length())) {
869 return false;
870 }
871
872 ConsumePadding(buf);
873 return true;
874}
875
jbauchf1f87202016-03-30 06:43:37 -0700876bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000877 buf->WriteBytes(bytes_, length());
878 WritePadding(buf);
879 return true;
880}
881
882void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +0200883 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000884 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200885 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000886}
887
zsteinf42cc9d2017-03-27 16:17:19 -0700888const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
889
Peter Boström0c4e06b2015-10-07 12:23:21 +0200890StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
891 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000892 const std::string& reason)
893 : StunAttribute(type, 0) {
894 SetCode(code);
895 SetReason(reason);
896}
897
Peter Boström0c4e06b2015-10-07 12:23:21 +0200898StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200899 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000900
Yves Gerey665174f2018-06-19 15:03:05 +0200901StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000902
Steve Antonca7d54e2017-10-25 14:42:51 -0700903StunAttributeValueType StunErrorCodeAttribute::value_type() const {
904 return STUN_VALUE_ERROR_CODE;
905}
906
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000907int StunErrorCodeAttribute::code() const {
908 return class_ * 100 + number_;
909}
910
911void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200912 class_ = static_cast<uint8_t>(code / 100);
913 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000914}
915
916void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200917 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000918 reason_ = reason;
919}
920
jbauchf1f87202016-03-30 06:43:37 -0700921bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200922 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000923 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
924 return false;
925
926 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100927 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000928
929 class_ = ((val >> 8) & 0x7);
930 number_ = (val & 0xff);
931
932 if (!buf->ReadString(&reason_, length() - 4))
933 return false;
934
935 ConsumePadding(buf);
936 return true;
937}
938
jbauchf1f87202016-03-30 06:43:37 -0700939bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000940 buf->WriteUInt32(class_ << 8 | number_);
941 buf->WriteString(reason_);
942 WritePadding(buf);
943 return true;
944}
945
Peter Boström0c4e06b2015-10-07 12:23:21 +0200946StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000947 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200948 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000949}
950
951StunUInt16ListAttribute::~StunUInt16ListAttribute() {
952 delete attr_types_;
953}
954
Steve Antonca7d54e2017-10-25 14:42:51 -0700955StunAttributeValueType StunUInt16ListAttribute::value_type() const {
956 return STUN_VALUE_UINT16_LIST;
957}
958
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000959size_t StunUInt16ListAttribute::Size() const {
960 return attr_types_->size();
961}
962
Peter Boström0c4e06b2015-10-07 12:23:21 +0200963uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000964 return (*attr_types_)[index];
965}
966
Peter Boström0c4e06b2015-10-07 12:23:21 +0200967void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000968 (*attr_types_)[index] = value;
969}
970
Peter Boström0c4e06b2015-10-07 12:23:21 +0200971void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000972 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200973 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000974}
975
jbauchf1f87202016-03-30 06:43:37 -0700976bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +0100977 if (length() % 2) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000978 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100979 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000980
981 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200982 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000983 if (!buf->ReadUInt16(&attr))
984 return false;
985 attr_types_->push_back(attr);
986 }
987 // Padding of these attributes is done in RFC 5389 style. This is
988 // slightly different from RFC3489, but it shouldn't be important.
989 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
990 // entries in the list (not necessarily the last one - it's unspecified).
991 // RFC5389 pads on the end, and the bytes are always ignored.
992 ConsumePadding(buf);
993 return true;
994}
995
jbauchf1f87202016-03-30 06:43:37 -0700996bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000997 for (size_t i = 0; i < attr_types_->size(); ++i) {
998 buf->WriteUInt16((*attr_types_)[i]);
999 }
1000 WritePadding(buf);
1001 return true;
1002}
1003
1004int GetStunSuccessResponseType(int req_type) {
1005 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
1006}
1007
1008int GetStunErrorResponseType(int req_type) {
1009 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
1010}
1011
1012bool IsStunRequestType(int msg_type) {
1013 return ((msg_type & kStunTypeMask) == 0x000);
1014}
1015
1016bool IsStunIndicationType(int msg_type) {
1017 return ((msg_type & kStunTypeMask) == 0x010);
1018}
1019
1020bool IsStunSuccessResponseType(int msg_type) {
1021 return ((msg_type & kStunTypeMask) == 0x100);
1022}
1023
1024bool IsStunErrorResponseType(int msg_type) {
1025 return ((msg_type & kStunTypeMask) == 0x110);
1026}
1027
1028bool ComputeStunCredentialHash(const std::string& username,
1029 const std::string& realm,
1030 const std::string& password,
1031 std::string* hash) {
1032 // http://tools.ietf.org/html/rfc5389#section-15.4
1033 // long-term credentials will be calculated using the key and key is
1034 // key = MD5(username ":" realm ":" SASLprep(password))
1035 std::string input = username;
1036 input += ':';
1037 input += realm;
1038 input += ':';
1039 input += password;
1040
1041 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001042 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1043 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001044 if (size == 0) {
1045 return false;
1046 }
1047
1048 *hash = std::string(digest, size);
1049 return true;
1050}
1051
Jonas Oreland202994c2017-12-18 12:10:43 +01001052std::unique_ptr<StunAttribute> CopyStunAttribute(
1053 const StunAttribute& attribute,
1054 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1055 ByteBufferWriter tmpBuffer;
1056 if (tmp_buffer_ptr == nullptr) {
1057 tmp_buffer_ptr = &tmpBuffer;
1058 }
1059
Yves Gerey665174f2018-06-19 15:03:05 +02001060 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1061 attribute.value_type(), attribute.type(),
1062 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001063
1064 if (!copy) {
1065 return nullptr;
1066 }
1067 tmp_buffer_ptr->Clear();
1068 if (!attribute.Write(tmp_buffer_ptr)) {
1069 return nullptr;
1070 }
1071 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1072 if (!copy->Read(&reader)) {
1073 return nullptr;
1074 }
1075
1076 return copy;
1077}
1078
Steve Antonca7d54e2017-10-25 14:42:51 -07001079StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1080 switch (type) {
1081 case STUN_ATTR_LIFETIME:
1082 return STUN_VALUE_UINT32;
1083 case STUN_ATTR_MAGIC_COOKIE:
1084 return STUN_VALUE_BYTE_STRING;
1085 case STUN_ATTR_BANDWIDTH:
1086 return STUN_VALUE_UINT32;
1087 case STUN_ATTR_DESTINATION_ADDRESS:
1088 return STUN_VALUE_ADDRESS;
1089 case STUN_ATTR_SOURCE_ADDRESS2:
1090 return STUN_VALUE_ADDRESS;
1091 case STUN_ATTR_DATA:
1092 return STUN_VALUE_BYTE_STRING;
1093 case STUN_ATTR_OPTIONS:
1094 return STUN_VALUE_UINT32;
1095 default:
1096 return StunMessage::GetAttributeValueType(type);
1097 }
1098}
1099
1100StunMessage* RelayMessage::CreateNew() const {
1101 return new RelayMessage();
1102}
1103
1104StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1105 switch (type) {
1106 case STUN_ATTR_CHANNEL_NUMBER:
1107 return STUN_VALUE_UINT32;
1108 case STUN_ATTR_TURN_LIFETIME:
1109 return STUN_VALUE_UINT32;
1110 case STUN_ATTR_XOR_PEER_ADDRESS:
1111 return STUN_VALUE_XOR_ADDRESS;
1112 case STUN_ATTR_DATA:
1113 return STUN_VALUE_BYTE_STRING;
1114 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1115 return STUN_VALUE_XOR_ADDRESS;
1116 case STUN_ATTR_EVEN_PORT:
1117 return STUN_VALUE_BYTE_STRING;
1118 case STUN_ATTR_REQUESTED_TRANSPORT:
1119 return STUN_VALUE_UINT32;
1120 case STUN_ATTR_DONT_FRAGMENT:
1121 return STUN_VALUE_BYTE_STRING;
1122 case STUN_ATTR_RESERVATION_TOKEN:
1123 return STUN_VALUE_BYTE_STRING;
1124 default:
1125 return StunMessage::GetAttributeValueType(type);
1126 }
1127}
1128
1129StunMessage* TurnMessage::CreateNew() const {
1130 return new TurnMessage();
1131}
1132
1133StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1134 switch (type) {
1135 case STUN_ATTR_PRIORITY:
1136 case STUN_ATTR_NETWORK_INFO:
1137 case STUN_ATTR_NOMINATION:
1138 return STUN_VALUE_UINT32;
1139 case STUN_ATTR_USE_CANDIDATE:
1140 return STUN_VALUE_BYTE_STRING;
1141 case STUN_ATTR_ICE_CONTROLLED:
1142 return STUN_VALUE_UINT64;
1143 case STUN_ATTR_ICE_CONTROLLING:
1144 return STUN_VALUE_UINT64;
1145 default:
1146 return StunMessage::GetAttributeValueType(type);
1147 }
1148}
1149
1150StunMessage* IceMessage::CreateNew() const {
1151 return new IceMessage();
1152}
1153
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001154} // namespace cricket