blob: 80b7b82d9ad3b60295128caf18fa64a5daa73bcb [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Patrik Höglund56d94522019-11-18 15:53:32 +010011#include "api/transport/stun.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000012
13#include <string.h>
14
Yves Gerey665174f2018-06-19 15:03:05 +020015#include <algorithm>
kwiberg3ec46792016-04-27 07:22:53 -070016#include <memory>
Steve Anton6c38cc72017-11-29 10:25:58 -080017#include <utility>
kwiberg3ec46792016-04-27 07:22:53 -070018
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/checks.h"
21#include "rtc_base/crc32.h"
22#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "rtc_base/message_digest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024
jbauchf1f87202016-03-30 06:43:37 -070025using rtc::ByteBufferReader;
26using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000027
Zach Stein92c42892018-11-28 11:38:52 -080028namespace {
29
30uint32_t ReduceTransactionId(const std::string& transaction_id) {
31 RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
32 transaction_id.length() ==
33 cricket::kStunLegacyTransactionIdLength);
Danil Chapovalov7b46e172019-11-14 17:40:23 +010034 ByteBufferReader reader(transaction_id.c_str(), transaction_id.length());
Zach Stein92c42892018-11-28 11:38:52 -080035 uint32_t result = 0;
Zach Steinff71a492018-12-07 11:25:12 -080036 uint32_t next;
37 while (reader.ReadUInt32(&next)) {
38 result ^= next;
Zach Stein92c42892018-11-28 11:38:52 -080039 }
40 return result;
41}
42
43} // namespace
44
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000045namespace cricket {
46
47const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
48const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
49const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
50const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
51const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
52const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
53const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
54const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
55const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
56const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
57const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
58
Yves Gerey665174f2018-06-19 15:03:05 +020059const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000060const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020061const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
Eldar Relloda13ea22019-06-01 12:23:43 +030062const int SERVER_NOT_REACHABLE_ERROR = 701;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000063
64// StunMessage
65
66StunMessage::StunMessage()
67 : type_(0),
68 length_(0),
Jonas Oreland7ca63112018-02-27 08:45:13 +010069 transaction_id_(EMPTY_TRANSACTION_ID),
70 stun_magic_cookie_(kStunMagicCookie) {
nisseede5da42017-01-12 05:15:36 -080071 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000072}
73
Steve Antonca7d54e2017-10-25 14:42:51 -070074StunMessage::~StunMessage() = default;
75
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000076bool StunMessage::IsLegacy() const {
77 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
78 return true;
nisseede5da42017-01-12 05:15:36 -080079 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000080 return false;
81}
82
83bool StunMessage::SetTransactionID(const std::string& str) {
84 if (!IsValidTransactionId(str)) {
85 return false;
86 }
87 transaction_id_ = str;
Zach Stein92c42892018-11-28 11:38:52 -080088 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000089 return true;
90}
91
Jonas Oreland16ccef72018-03-27 09:02:43 +020092static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +020093 return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
94 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +020095}
96
zsteinf42cc9d2017-03-27 16:17:19 -070097void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020098 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +020099 // but allow any type for the range that in the RFC is reserved for
100 // the "designated experts".
101 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200102 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
103 }
nissecc99bc22017-02-02 01:31:30 -0800104
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000105 attr->SetOwner(this);
106 size_t attr_length = attr->length();
107 if (attr_length % 4 != 0) {
108 attr_length += (4 - (attr_length % 4));
109 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200110 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -0700111
112 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000113}
114
Jonas Oreland202994c2017-12-18 12:10:43 +0100115std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
116 std::unique_ptr<StunAttribute> attribute;
117 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
Yves Gerey665174f2018-06-19 15:03:05 +0200118 if ((*it)->type() == type) {
119 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100120 attrs_.erase(std::next(it).base());
121 break;
122 }
123 }
124 if (attribute) {
125 attribute->SetOwner(nullptr);
126 size_t attr_length = attribute->length();
127 if (attr_length % 4 != 0) {
128 attr_length += (4 - (attr_length % 4));
129 }
130 length_ -= static_cast<uint16_t>(attr_length + 4);
131 }
132 return attribute;
133}
134
Jonas Oreland63737a92019-11-21 15:12:14 +0100135void StunMessage::ClearAttributes() {
136 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
137 (*it)->SetOwner(nullptr);
138 }
139 attrs_.clear();
140 length_ = 0;
141}
142
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143const StunAddressAttribute* StunMessage::GetAddress(int type) const {
144 switch (type) {
145 case STUN_ATTR_MAPPED_ADDRESS: {
146 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
147 // missing.
148 const StunAttribute* mapped_address =
149 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
150 if (!mapped_address)
151 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
152 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
153 }
154
155 default:
156 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
157 }
158}
159
160const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
161 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
162}
163
164const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
165 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
166}
167
168const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
169 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
170}
171
Jonas Oreland1721de12019-11-20 12:10:39 +0100172const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
173 return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
174}
175
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000176const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
177 return static_cast<const StunErrorCodeAttribute*>(
178 GetAttribute(STUN_ATTR_ERROR_CODE));
179}
180
deadbeef996fc6b2017-04-26 09:21:22 -0700181int StunMessage::GetErrorCodeValue() const {
182 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
183 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
184}
185
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000186const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
187 return static_cast<const StunUInt16ListAttribute*>(
188 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
189}
190
Yves Gerey665174f2018-06-19 15:03:05 +0200191bool StunMessage::ValidateMessageIntegrity(const char* data,
192 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000193 const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100194 return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
195 kStunMessageIntegritySize, data, size,
196 password);
197}
198
199bool StunMessage::ValidateMessageIntegrity32(const char* data,
200 size_t size,
201 const std::string& password) {
202 return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
203 kStunMessageIntegrity32Size, data, size,
204 password);
205}
206
207// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
208// procedure outlined in RFC 5389, section 15.4.
209bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
210 size_t mi_attr_size,
211 const char* data,
212 size_t size,
213 const std::string& password) {
214 RTC_DCHECK(mi_attr_size <= kStunMessageIntegritySize);
215
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000216 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700217 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000218 return false;
219 }
220
221 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200222 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000223 if (size != (msg_length + kStunHeaderSize)) {
224 return false;
225 }
226
227 // Finding Message Integrity attribute in stun message.
228 size_t current_pos = kStunHeaderSize;
229 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700230 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200231 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000232 // Getting attribute type and length.
233 attr_type = rtc::GetBE16(&data[current_pos]);
234 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
235
236 // If M-I, sanity check it, and break out.
Jonas Oreland63737a92019-11-21 15:12:14 +0100237 if (attr_type == mi_attr_type) {
238 if (attr_length != mi_attr_size ||
katrielc1a206102016-06-20 05:13:16 -0700239 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
240 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000241 return false;
242 }
243 has_message_integrity_attr = true;
244 break;
245 }
246
247 // Otherwise, skip to the next attribute.
248 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
249 if ((attr_length % 4) != 0) {
250 current_pos += (4 - (attr_length % 4));
251 }
252 }
253
254 if (!has_message_integrity_attr) {
255 return false;
256 }
257
258 // Getting length of the message to calculate Message Integrity.
259 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700260 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000261 memcpy(temp_data.get(), data, current_pos);
Jonas Oreland63737a92019-11-21 15:12:14 +0100262 if (size > mi_pos + kStunAttributeHeaderSize + mi_attr_size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000263 // Stun message has other attributes after message integrity.
264 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200265 size_t extra_offset =
Jonas Oreland63737a92019-11-21 15:12:14 +0100266 size - (mi_pos + kStunAttributeHeaderSize + mi_attr_size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000267 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
268
269 // Writing new length of the STUN message @ Message Length in temp buffer.
270 // 0 1 2 3
271 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
272 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
273 // |0 0| STUN Message Type | Message Length |
274 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200275 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000276 }
277
278 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200279 size_t ret =
280 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
281 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800282 RTC_DCHECK(ret == sizeof(hmac));
Jonas Oreland63737a92019-11-21 15:12:14 +0100283 if (ret != sizeof(hmac)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000284 return false;
Jonas Oreland63737a92019-11-21 15:12:14 +0100285 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000286
287 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200288 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
Jonas Oreland63737a92019-11-21 15:12:14 +0100289 mi_attr_size) == 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000290}
291
292bool StunMessage::AddMessageIntegrity(const std::string& password) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100293 return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
294 kStunMessageIntegritySize, password.c_str(),
295 password.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000296}
297
Yves Gerey665174f2018-06-19 15:03:05 +0200298bool StunMessage::AddMessageIntegrity(const char* key, size_t keylen) {
Jonas Oreland63737a92019-11-21 15:12:14 +0100299 return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
300 kStunMessageIntegritySize, key, keylen);
301}
302
303bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
304 return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
305 kStunMessageIntegrity32Size, password.data(),
306 password.length());
307}
308
309bool StunMessage::AddMessageIntegrityOfType(int attr_type,
310 size_t attr_size,
311 const char* key,
312 size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000313 // Add the attribute with a dummy value. Since this is a known attribute, it
314 // can't fail.
Jonas Oreland63737a92019-11-21 15:12:14 +0100315 RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200316 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
Jonas Oreland63737a92019-11-21 15:12:14 +0100317 attr_type, std::string(attr_size, '0'));
zsteinf42cc9d2017-03-27 16:17:19 -0700318 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
319 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320
321 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700322 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000323 if (!Write(&buf))
324 return false;
325
326 int msg_len_for_hmac = static_cast<int>(
327 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
328 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200329 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
330 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800331 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000332 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100333 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200334 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000335 return false;
336 }
337
338 // Insert correct HMAC into the attribute.
Jonas Oreland63737a92019-11-21 15:12:14 +0100339 msg_integrity_attr->CopyBytes(hmac, attr_size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000340 return true;
341}
342
343// Verifies a message is in fact a STUN message, by performing the checks
344// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
345// in section 15.5.
346bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
347 // Check the message length.
348 size_t fingerprint_attr_size =
349 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
350 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
351 return false;
352
353 // Skip the rest if the magic cookie isn't present.
354 const char* magic_cookie =
355 data + kStunTransactionIdOffset - kStunMagicCookieLength;
356 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
357 return false;
358
359 // Check the fingerprint type and length.
360 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
361 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200362 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000363 StunUInt32Attribute::SIZE)
364 return false;
365
366 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200367 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000368 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
369 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200370 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371}
372
373bool StunMessage::AddFingerprint() {
374 // Add the attribute with a dummy value. Since this is a known attribute,
375 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700376 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200377 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700378 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700379 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000380
381 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700382 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000383 if (!Write(&buf))
384 return false;
385
386 int msg_len_for_crc32 = static_cast<int>(
387 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200388 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000389
390 // Insert the correct CRC-32, XORed with a constant, into the attribute.
391 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
392 return true;
393}
394
jbauchf1f87202016-03-30 06:43:37 -0700395bool StunMessage::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +0100396 if (!buf->ReadUInt16(&type_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000397 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100398 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000399
400 if (type_ & 0x8000) {
401 // RTP and RTCP set the MSB of first byte, since first two bits are version,
402 // and version is always 2 (10). If set, this is not a STUN packet.
403 return false;
404 }
405
Jonas Oreland1721de12019-11-20 12:10:39 +0100406 if (!buf->ReadUInt16(&length_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000407 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100408 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000409
410 std::string magic_cookie;
Jonas Oreland1721de12019-11-20 12:10:39 +0100411 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000412 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100413 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000414
415 std::string transaction_id;
Jonas Oreland1721de12019-11-20 12:10:39 +0100416 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000417 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100418 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000419
Andrew Royes154d8392019-03-14 10:38:31 -0700420 uint32_t magic_cookie_int;
421 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
422 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
423 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000424 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
425 // If magic cookie is invalid it means that the peer implements
426 // RFC3489 instead of RFC5389.
427 transaction_id.insert(0, magic_cookie);
428 }
nisseede5da42017-01-12 05:15:36 -0800429 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000430 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800431 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000432
Jonas Oreland1721de12019-11-20 12:10:39 +0100433 if (length_ != buf->Length()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000434 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100435 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000436
zsteinad94c4c2017-03-06 13:36:05 -0800437 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000438
439 size_t rest = buf->Length() - length_;
440 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200441 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000442 if (!buf->ReadUInt16(&attr_type))
443 return false;
444 if (!buf->ReadUInt16(&attr_length))
445 return false;
446
Honghai Zhang3e024302016-09-22 09:52:16 -0700447 std::unique_ptr<StunAttribute> attr(
448 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000449 if (!attr) {
450 // Skip any unknown or malformed attributes.
451 if ((attr_length % 4) != 0) {
452 attr_length += (4 - (attr_length % 4));
453 }
Jonas Oreland1721de12019-11-20 12:10:39 +0100454 if (!buf->Consume(attr_length)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000455 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100456 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000457 } else {
Jonas Oreland1721de12019-11-20 12:10:39 +0100458 if (!attr->Read(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000459 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +0100460 }
zsteinad94c4c2017-03-06 13:36:05 -0800461 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000462 }
463 }
464
nisseede5da42017-01-12 05:15:36 -0800465 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000466 return true;
467}
468
jbauchf1f87202016-03-30 06:43:37 -0700469bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000470 buf->WriteUInt16(type_);
471 buf->WriteUInt16(length_);
472 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100473 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000474 buf->WriteString(transaction_id_);
475
zsteinad94c4c2017-03-06 13:36:05 -0800476 for (const auto& attr : attrs_) {
477 buf->WriteUInt16(attr->type());
478 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
479 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000480 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800481 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000482 }
483
484 return true;
485}
486
Steve Antonca7d54e2017-10-25 14:42:51 -0700487StunMessage* StunMessage::CreateNew() const {
488 return new StunMessage();
489}
490
Jonas Oreland7ca63112018-02-27 08:45:13 +0100491void StunMessage::SetStunMagicCookie(uint32_t val) {
492 stun_magic_cookie_ = val;
493}
494
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000495StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
496 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200497 case STUN_ATTR_MAPPED_ADDRESS:
498 return STUN_VALUE_ADDRESS;
499 case STUN_ATTR_USERNAME:
500 return STUN_VALUE_BYTE_STRING;
501 case STUN_ATTR_MESSAGE_INTEGRITY:
502 return STUN_VALUE_BYTE_STRING;
503 case STUN_ATTR_ERROR_CODE:
504 return STUN_VALUE_ERROR_CODE;
505 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
506 return STUN_VALUE_UINT16_LIST;
507 case STUN_ATTR_REALM:
508 return STUN_VALUE_BYTE_STRING;
509 case STUN_ATTR_NONCE:
510 return STUN_VALUE_BYTE_STRING;
511 case STUN_ATTR_XOR_MAPPED_ADDRESS:
512 return STUN_VALUE_XOR_ADDRESS;
513 case STUN_ATTR_SOFTWARE:
514 return STUN_VALUE_BYTE_STRING;
515 case STUN_ATTR_ALTERNATE_SERVER:
516 return STUN_VALUE_ADDRESS;
517 case STUN_ATTR_FINGERPRINT:
518 return STUN_VALUE_UINT32;
519 case STUN_ATTR_ORIGIN:
520 return STUN_VALUE_BYTE_STRING;
521 case STUN_ATTR_RETRANSMIT_COUNT:
522 return STUN_VALUE_UINT32;
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700523 case STUN_ATTR_LAST_ICE_CHECK_RECEIVED:
524 return STUN_VALUE_BYTE_STRING;
Jonas Oreland1721de12019-11-20 12:10:39 +0100525 case STUN_ATTR_GOOG_MISC_INFO:
526 return STUN_VALUE_UINT16_LIST;
Yves Gerey665174f2018-06-19 15:03:05 +0200527 default:
528 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000529 }
530}
531
532StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
533 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200534 if (value_type != STUN_VALUE_UNKNOWN) {
535 return StunAttribute::Create(value_type, type,
536 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200537 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200538 // Read unknown attributes as STUN_VALUE_BYTE_STRING
539 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
540 static_cast<uint16_t>(length), this);
541 } else {
542 return NULL;
543 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000544}
545
546const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800547 for (const auto& attr : attrs_) {
548 if (attr->type() == type) {
549 return attr.get();
550 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000551 }
552 return NULL;
553}
554
555bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
556 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200557 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000558}
559
560// StunAttribute
561
Peter Boström0c4e06b2015-10-07 12:23:21 +0200562StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200563 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564
jbauchf1f87202016-03-30 06:43:37 -0700565void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000566 int remainder = length_ % 4;
567 if (remainder > 0) {
568 buf->Consume(4 - remainder);
569 }
570}
571
jbauchf1f87202016-03-30 06:43:37 -0700572void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000573 int remainder = length_ % 4;
574 if (remainder > 0) {
575 char zeroes[4] = {0};
576 buf->WriteBytes(zeroes, 4 - remainder);
577 }
578}
579
580StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200581 uint16_t type,
582 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000583 StunMessage* owner) {
584 switch (value_type) {
585 case STUN_VALUE_ADDRESS:
586 return new StunAddressAttribute(type, length);
587 case STUN_VALUE_XOR_ADDRESS:
588 return new StunXorAddressAttribute(type, length, owner);
589 case STUN_VALUE_UINT32:
590 return new StunUInt32Attribute(type);
591 case STUN_VALUE_UINT64:
592 return new StunUInt64Attribute(type);
593 case STUN_VALUE_BYTE_STRING:
594 return new StunByteStringAttribute(type, length);
595 case STUN_VALUE_ERROR_CODE:
596 return new StunErrorCodeAttribute(type, length);
597 case STUN_VALUE_UINT16_LIST:
598 return new StunUInt16ListAttribute(type, length);
599 default:
600 return NULL;
601 }
602}
603
zsteinf42cc9d2017-03-27 16:17:19 -0700604std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
605 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200606 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000607}
608
zsteinf42cc9d2017-03-27 16:17:19 -0700609std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
610 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200611 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000612}
613
zsteinf42cc9d2017-03-27 16:17:19 -0700614std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
615 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200616 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000617}
618
zsteinf42cc9d2017-03-27 16:17:19 -0700619std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
620 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200621 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000622}
623
zsteinf42cc9d2017-03-27 16:17:19 -0700624std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
625 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200626 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000627}
628
zsteinf42cc9d2017-03-27 16:17:19 -0700629std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200630 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000631 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
632}
633
zsteinf42cc9d2017-03-27 16:17:19 -0700634std::unique_ptr<StunUInt16ListAttribute>
Jonas Oreland1721de12019-11-20 12:10:39 +0100635StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
636 return std::make_unique<StunUInt16ListAttribute>(type, 0);
637}
638
639std::unique_ptr<StunUInt16ListAttribute>
zsteinf42cc9d2017-03-27 16:17:19 -0700640StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200641 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
642 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000643}
644
Peter Boström0c4e06b2015-10-07 12:23:21 +0200645StunAddressAttribute::StunAddressAttribute(uint16_t type,
646 const rtc::SocketAddress& addr)
647 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000648 SetAddress(addr);
649}
650
Peter Boström0c4e06b2015-10-07 12:23:21 +0200651StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200652 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000653
Steve Antonca7d54e2017-10-25 14:42:51 -0700654StunAttributeValueType StunAddressAttribute::value_type() const {
655 return STUN_VALUE_ADDRESS;
656}
657
jbauchf1f87202016-03-30 06:43:37 -0700658bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200659 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000660 if (!buf->ReadUInt8(&dummy))
661 return false;
662
Peter Boström0c4e06b2015-10-07 12:23:21 +0200663 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000664 if (!buf->ReadUInt8(&stun_family)) {
665 return false;
666 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200667 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000668 if (!buf->ReadUInt16(&port))
669 return false;
670 if (stun_family == STUN_ADDRESS_IPV4) {
671 in_addr v4addr;
672 if (length() != SIZE_IP4) {
673 return false;
674 }
675 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
676 return false;
677 }
678 rtc::IPAddress ipaddr(v4addr);
679 SetAddress(rtc::SocketAddress(ipaddr, port));
680 } else if (stun_family == STUN_ADDRESS_IPV6) {
681 in6_addr v6addr;
682 if (length() != SIZE_IP6) {
683 return false;
684 }
685 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
686 return false;
687 }
688 rtc::IPAddress ipaddr(v6addr);
689 SetAddress(rtc::SocketAddress(ipaddr, port));
690 } else {
691 return false;
692 }
693 return true;
694}
695
jbauchf1f87202016-03-30 06:43:37 -0700696bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000697 StunAddressFamily address_family = family();
698 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100699 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000700 return false;
701 }
702 buf->WriteUInt8(0);
703 buf->WriteUInt8(address_family);
704 buf->WriteUInt16(address_.port());
705 switch (address_.family()) {
706 case AF_INET: {
707 in_addr v4addr = address_.ipaddr().ipv4_address();
708 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
709 break;
710 }
711 case AF_INET6: {
712 in6_addr v6addr = address_.ipaddr().ipv6_address();
713 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
714 break;
715 }
716 }
717 return true;
718}
719
Peter Boström0c4e06b2015-10-07 12:23:21 +0200720StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
721 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200722 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000723
Peter Boström0c4e06b2015-10-07 12:23:21 +0200724StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
725 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000726 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200727 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000728
Steve Antonca7d54e2017-10-25 14:42:51 -0700729StunAttributeValueType StunXorAddressAttribute::value_type() const {
730 return STUN_VALUE_XOR_ADDRESS;
731}
732
733void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
734 owner_ = owner;
735}
736
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000737rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
738 if (owner_) {
739 rtc::IPAddress ip = ipaddr();
740 switch (ip.family()) {
741 case AF_INET: {
742 in_addr v4addr = ip.ipv4_address();
743 v4addr.s_addr =
744 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
745 return rtc::IPAddress(v4addr);
746 }
747 case AF_INET6: {
748 in6_addr v6addr = ip.ipv6_address();
749 const std::string& transaction_id = owner_->transaction_id();
750 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200751 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000752 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
753 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200754 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000755 // Transaction ID is in network byte order, but magic cookie
756 // is stored in host byte order.
757 ip_as_ints[0] =
758 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
759 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
760 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
761 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
762 return rtc::IPAddress(v6addr);
763 }
764 break;
765 }
766 }
767 }
768 // Invalid ip family or transaction ID, or missing owner.
769 // Return an AF_UNSPEC address.
770 return rtc::IPAddress();
771}
772
jbauchf1f87202016-03-30 06:43:37 -0700773bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000774 if (!StunAddressAttribute::Read(buf))
775 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200776 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000777 rtc::IPAddress xored_ip = GetXoredIP();
778 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
779 return true;
780}
781
jbauchf1f87202016-03-30 06:43:37 -0700782bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000783 StunAddressFamily address_family = family();
784 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100785 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000786 return false;
787 }
788 rtc::IPAddress xored_ip = GetXoredIP();
789 if (xored_ip.family() == AF_UNSPEC) {
790 return false;
791 }
792 buf->WriteUInt8(0);
793 buf->WriteUInt8(family());
794 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
795 switch (xored_ip.family()) {
796 case AF_INET: {
797 in_addr v4addr = xored_ip.ipv4_address();
798 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
799 break;
800 }
801 case AF_INET6: {
802 in6_addr v6addr = xored_ip.ipv6_address();
803 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
804 break;
805 }
806 }
807 return true;
808}
809
Peter Boström0c4e06b2015-10-07 12:23:21 +0200810StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200811 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000812
Peter Boström0c4e06b2015-10-07 12:23:21 +0200813StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200814 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000815
Steve Antonca7d54e2017-10-25 14:42:51 -0700816StunAttributeValueType StunUInt32Attribute::value_type() const {
817 return STUN_VALUE_UINT32;
818}
819
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000820bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800821 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000822 return static_cast<bool>((bits_ >> index) & 0x1);
823}
824
825void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800826 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000827 bits_ &= ~(1 << index);
828 bits_ |= value ? (1 << index) : 0;
829}
830
jbauchf1f87202016-03-30 06:43:37 -0700831bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000832 if (length() != SIZE || !buf->ReadUInt32(&bits_))
833 return false;
834 return true;
835}
836
jbauchf1f87202016-03-30 06:43:37 -0700837bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000838 buf->WriteUInt32(bits_);
839 return true;
840}
841
Peter Boström0c4e06b2015-10-07 12:23:21 +0200842StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200843 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000844
Peter Boström0c4e06b2015-10-07 12:23:21 +0200845StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200846 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000847
Steve Antonca7d54e2017-10-25 14:42:51 -0700848StunAttributeValueType StunUInt64Attribute::value_type() const {
849 return STUN_VALUE_UINT64;
850}
851
jbauchf1f87202016-03-30 06:43:37 -0700852bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000853 if (length() != SIZE || !buf->ReadUInt64(&bits_))
854 return false;
855 return true;
856}
857
jbauchf1f87202016-03-30 06:43:37 -0700858bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000859 buf->WriteUInt64(bits_);
860 return true;
861}
862
Peter Boström0c4e06b2015-10-07 12:23:21 +0200863StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200864 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000865
Peter Boström0c4e06b2015-10-07 12:23:21 +0200866StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000867 const std::string& str)
868 : StunAttribute(type, 0), bytes_(NULL) {
869 CopyBytes(str.c_str(), str.size());
870}
871
Peter Boström0c4e06b2015-10-07 12:23:21 +0200872StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000873 const void* bytes,
874 size_t length)
875 : StunAttribute(type, 0), bytes_(NULL) {
876 CopyBytes(bytes, length);
877}
878
Peter Boström0c4e06b2015-10-07 12:23:21 +0200879StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200880 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000881
882StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +0200883 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000884}
885
Steve Antonca7d54e2017-10-25 14:42:51 -0700886StunAttributeValueType StunByteStringAttribute::value_type() const {
887 return STUN_VALUE_BYTE_STRING;
888}
889
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000890void StunByteStringAttribute::CopyBytes(const char* bytes) {
891 CopyBytes(bytes, strlen(bytes));
892}
893
894void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
895 char* new_bytes = new char[length];
896 memcpy(new_bytes, bytes, length);
897 SetBytes(new_bytes, length);
898}
899
Peter Boström0c4e06b2015-10-07 12:23:21 +0200900uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800901 RTC_DCHECK(bytes_ != NULL);
902 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200903 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000904}
905
Peter Boström0c4e06b2015-10-07 12:23:21 +0200906void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800907 RTC_DCHECK(bytes_ != NULL);
908 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000909 bytes_[index] = value;
910}
911
jbauchf1f87202016-03-30 06:43:37 -0700912bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000913 bytes_ = new char[length()];
914 if (!buf->ReadBytes(bytes_, length())) {
915 return false;
916 }
917
918 ConsumePadding(buf);
919 return true;
920}
921
jbauchf1f87202016-03-30 06:43:37 -0700922bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000923 buf->WriteBytes(bytes_, length());
924 WritePadding(buf);
925 return true;
926}
927
928void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +0200929 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000930 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200931 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000932}
933
zsteinf42cc9d2017-03-27 16:17:19 -0700934const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
935
Peter Boström0c4e06b2015-10-07 12:23:21 +0200936StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
937 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000938 const std::string& reason)
939 : StunAttribute(type, 0) {
940 SetCode(code);
941 SetReason(reason);
942}
943
Peter Boström0c4e06b2015-10-07 12:23:21 +0200944StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200945 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000946
Yves Gerey665174f2018-06-19 15:03:05 +0200947StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000948
Steve Antonca7d54e2017-10-25 14:42:51 -0700949StunAttributeValueType StunErrorCodeAttribute::value_type() const {
950 return STUN_VALUE_ERROR_CODE;
951}
952
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000953int StunErrorCodeAttribute::code() const {
954 return class_ * 100 + number_;
955}
956
957void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200958 class_ = static_cast<uint8_t>(code / 100);
959 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000960}
961
962void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200963 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000964 reason_ = reason;
965}
966
jbauchf1f87202016-03-30 06:43:37 -0700967bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200968 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000969 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
970 return false;
971
972 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100973 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000974
975 class_ = ((val >> 8) & 0x7);
976 number_ = (val & 0xff);
977
978 if (!buf->ReadString(&reason_, length() - 4))
979 return false;
980
981 ConsumePadding(buf);
982 return true;
983}
984
jbauchf1f87202016-03-30 06:43:37 -0700985bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000986 buf->WriteUInt32(class_ << 8 | number_);
987 buf->WriteString(reason_);
988 WritePadding(buf);
989 return true;
990}
991
Peter Boström0c4e06b2015-10-07 12:23:21 +0200992StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000993 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200994 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000995}
996
997StunUInt16ListAttribute::~StunUInt16ListAttribute() {
998 delete attr_types_;
999}
1000
Steve Antonca7d54e2017-10-25 14:42:51 -07001001StunAttributeValueType StunUInt16ListAttribute::value_type() const {
1002 return STUN_VALUE_UINT16_LIST;
1003}
1004
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001005size_t StunUInt16ListAttribute::Size() const {
1006 return attr_types_->size();
1007}
1008
Peter Boström0c4e06b2015-10-07 12:23:21 +02001009uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001010 return (*attr_types_)[index];
1011}
1012
Peter Boström0c4e06b2015-10-07 12:23:21 +02001013void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001014 (*attr_types_)[index] = value;
1015}
1016
Peter Boström0c4e06b2015-10-07 12:23:21 +02001017void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001018 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001019 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001020}
1021
Jonas Oreland63737a92019-11-21 15:12:14 +01001022void StunUInt16ListAttribute::AddTypeAtIndex(uint16_t index, uint16_t value) {
1023 if (attr_types_->size() < static_cast<size_t>(index + 1)) {
1024 attr_types_->resize(index + 1);
1025 }
1026 (*attr_types_)[index] = value;
1027 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
1028}
1029
jbauchf1f87202016-03-30 06:43:37 -07001030bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
Jonas Oreland1721de12019-11-20 12:10:39 +01001031 if (length() % 2) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001032 return false;
Jonas Oreland1721de12019-11-20 12:10:39 +01001033 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001034
1035 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001036 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001037 if (!buf->ReadUInt16(&attr))
1038 return false;
1039 attr_types_->push_back(attr);
1040 }
1041 // Padding of these attributes is done in RFC 5389 style. This is
1042 // slightly different from RFC3489, but it shouldn't be important.
1043 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
1044 // entries in the list (not necessarily the last one - it's unspecified).
1045 // RFC5389 pads on the end, and the bytes are always ignored.
1046 ConsumePadding(buf);
1047 return true;
1048}
1049
jbauchf1f87202016-03-30 06:43:37 -07001050bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001051 for (size_t i = 0; i < attr_types_->size(); ++i) {
1052 buf->WriteUInt16((*attr_types_)[i]);
1053 }
1054 WritePadding(buf);
1055 return true;
1056}
1057
1058int GetStunSuccessResponseType(int req_type) {
1059 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
1060}
1061
1062int GetStunErrorResponseType(int req_type) {
1063 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
1064}
1065
1066bool IsStunRequestType(int msg_type) {
1067 return ((msg_type & kStunTypeMask) == 0x000);
1068}
1069
1070bool IsStunIndicationType(int msg_type) {
1071 return ((msg_type & kStunTypeMask) == 0x010);
1072}
1073
1074bool IsStunSuccessResponseType(int msg_type) {
1075 return ((msg_type & kStunTypeMask) == 0x100);
1076}
1077
1078bool IsStunErrorResponseType(int msg_type) {
1079 return ((msg_type & kStunTypeMask) == 0x110);
1080}
1081
1082bool ComputeStunCredentialHash(const std::string& username,
1083 const std::string& realm,
1084 const std::string& password,
1085 std::string* hash) {
1086 // http://tools.ietf.org/html/rfc5389#section-15.4
1087 // long-term credentials will be calculated using the key and key is
1088 // key = MD5(username ":" realm ":" SASLprep(password))
1089 std::string input = username;
1090 input += ':';
1091 input += realm;
1092 input += ':';
1093 input += password;
1094
1095 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001096 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1097 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001098 if (size == 0) {
1099 return false;
1100 }
1101
1102 *hash = std::string(digest, size);
1103 return true;
1104}
1105
Jonas Oreland202994c2017-12-18 12:10:43 +01001106std::unique_ptr<StunAttribute> CopyStunAttribute(
1107 const StunAttribute& attribute,
1108 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1109 ByteBufferWriter tmpBuffer;
1110 if (tmp_buffer_ptr == nullptr) {
1111 tmp_buffer_ptr = &tmpBuffer;
1112 }
1113
Yves Gerey665174f2018-06-19 15:03:05 +02001114 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1115 attribute.value_type(), attribute.type(),
1116 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001117
1118 if (!copy) {
1119 return nullptr;
1120 }
1121 tmp_buffer_ptr->Clear();
1122 if (!attribute.Write(tmp_buffer_ptr)) {
1123 return nullptr;
1124 }
1125 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1126 if (!copy->Read(&reader)) {
1127 return nullptr;
1128 }
1129
1130 return copy;
1131}
1132
Steve Antonca7d54e2017-10-25 14:42:51 -07001133StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1134 switch (type) {
1135 case STUN_ATTR_LIFETIME:
1136 return STUN_VALUE_UINT32;
1137 case STUN_ATTR_MAGIC_COOKIE:
1138 return STUN_VALUE_BYTE_STRING;
1139 case STUN_ATTR_BANDWIDTH:
1140 return STUN_VALUE_UINT32;
1141 case STUN_ATTR_DESTINATION_ADDRESS:
1142 return STUN_VALUE_ADDRESS;
1143 case STUN_ATTR_SOURCE_ADDRESS2:
1144 return STUN_VALUE_ADDRESS;
1145 case STUN_ATTR_DATA:
1146 return STUN_VALUE_BYTE_STRING;
1147 case STUN_ATTR_OPTIONS:
1148 return STUN_VALUE_UINT32;
1149 default:
1150 return StunMessage::GetAttributeValueType(type);
1151 }
1152}
1153
1154StunMessage* RelayMessage::CreateNew() const {
1155 return new RelayMessage();
1156}
1157
1158StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1159 switch (type) {
1160 case STUN_ATTR_CHANNEL_NUMBER:
1161 return STUN_VALUE_UINT32;
1162 case STUN_ATTR_TURN_LIFETIME:
1163 return STUN_VALUE_UINT32;
1164 case STUN_ATTR_XOR_PEER_ADDRESS:
1165 return STUN_VALUE_XOR_ADDRESS;
1166 case STUN_ATTR_DATA:
1167 return STUN_VALUE_BYTE_STRING;
1168 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1169 return STUN_VALUE_XOR_ADDRESS;
1170 case STUN_ATTR_EVEN_PORT:
1171 return STUN_VALUE_BYTE_STRING;
1172 case STUN_ATTR_REQUESTED_TRANSPORT:
1173 return STUN_VALUE_UINT32;
1174 case STUN_ATTR_DONT_FRAGMENT:
1175 return STUN_VALUE_BYTE_STRING;
1176 case STUN_ATTR_RESERVATION_TOKEN:
1177 return STUN_VALUE_BYTE_STRING;
1178 default:
1179 return StunMessage::GetAttributeValueType(type);
1180 }
1181}
1182
1183StunMessage* TurnMessage::CreateNew() const {
1184 return new TurnMessage();
1185}
1186
1187StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1188 switch (type) {
1189 case STUN_ATTR_PRIORITY:
1190 case STUN_ATTR_NETWORK_INFO:
1191 case STUN_ATTR_NOMINATION:
1192 return STUN_VALUE_UINT32;
1193 case STUN_ATTR_USE_CANDIDATE:
1194 return STUN_VALUE_BYTE_STRING;
1195 case STUN_ATTR_ICE_CONTROLLED:
1196 return STUN_VALUE_UINT64;
1197 case STUN_ATTR_ICE_CONTROLLING:
1198 return STUN_VALUE_UINT64;
1199 default:
1200 return StunMessage::GetAttributeValueType(type);
1201 }
1202}
1203
1204StunMessage* IceMessage::CreateNew() const {
1205 return new IceMessage();
1206}
1207
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001208} // namespace cricket