blob: f40395bde358eb25859390a4391acea9d16a1f2a [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "p2p/base/stun.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000012
13#include <string.h>
14
Yves Gerey665174f2018-06-19 15:03:05 +020015#include <algorithm>
kwiberg3ec46792016-04-27 07:22:53 -070016#include <memory>
Steve Anton6c38cc72017-11-29 10:25:58 -080017#include <utility>
kwiberg3ec46792016-04-27 07:22:53 -070018
Karl Wiberg918f50c2018-07-05 11:40:33 +020019#include "absl/memory/memory.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/checks.h"
22#include "rtc_base/crc32.h"
23#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "rtc_base/message_digest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000025
jbauchf1f87202016-03-30 06:43:37 -070026using rtc::ByteBufferReader;
27using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000028
Zach Stein92c42892018-11-28 11:38:52 -080029namespace {
30
31uint32_t ReduceTransactionId(const std::string& transaction_id) {
32 RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
33 transaction_id.length() ==
34 cricket::kStunLegacyTransactionIdLength);
Zach Steinff71a492018-12-07 11:25:12 -080035 ByteBufferReader reader(transaction_id.c_str(), transaction_id.length(),
36 rtc::ByteBuffer::ORDER_NETWORK);
Zach Stein92c42892018-11-28 11:38:52 -080037 uint32_t result = 0;
Zach Steinff71a492018-12-07 11:25:12 -080038 uint32_t next;
39 while (reader.ReadUInt32(&next)) {
40 result ^= next;
Zach Stein92c42892018-11-28 11:38:52 -080041 }
42 return result;
43}
44
45} // namespace
46
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000047namespace cricket {
48
49const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
50const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
51const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
52const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
53const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
54const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
55const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
56const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
57const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
58const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
59const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
60
Yves Gerey665174f2018-06-19 15:03:05 +020061const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000062const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020063const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
Eldar Relloda13ea22019-06-01 12:23:43 +030064const int SERVER_NOT_REACHABLE_ERROR = 701;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000065
66// StunMessage
67
68StunMessage::StunMessage()
69 : type_(0),
70 length_(0),
Jonas Oreland7ca63112018-02-27 08:45:13 +010071 transaction_id_(EMPTY_TRANSACTION_ID),
72 stun_magic_cookie_(kStunMagicCookie) {
nisseede5da42017-01-12 05:15:36 -080073 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000074}
75
Steve Antonca7d54e2017-10-25 14:42:51 -070076StunMessage::~StunMessage() = default;
77
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000078bool StunMessage::IsLegacy() const {
79 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
80 return true;
nisseede5da42017-01-12 05:15:36 -080081 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000082 return false;
83}
84
85bool StunMessage::SetTransactionID(const std::string& str) {
86 if (!IsValidTransactionId(str)) {
87 return false;
88 }
89 transaction_id_ = str;
Zach Stein92c42892018-11-28 11:38:52 -080090 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000091 return true;
92}
93
Jonas Oreland16ccef72018-03-27 09:02:43 +020094static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +020095 return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
96 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +020097}
98
zsteinf42cc9d2017-03-27 16:17:19 -070099void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200100 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +0200101 // but allow any type for the range that in the RFC is reserved for
102 // the "designated experts".
103 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200104 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
105 }
nissecc99bc22017-02-02 01:31:30 -0800106
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000107 attr->SetOwner(this);
108 size_t attr_length = attr->length();
109 if (attr_length % 4 != 0) {
110 attr_length += (4 - (attr_length % 4));
111 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200112 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -0700113
114 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000115}
116
Jonas Oreland202994c2017-12-18 12:10:43 +0100117std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
118 std::unique_ptr<StunAttribute> attribute;
119 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
Yves Gerey665174f2018-06-19 15:03:05 +0200120 if ((*it)->type() == type) {
121 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100122 attrs_.erase(std::next(it).base());
123 break;
124 }
125 }
126 if (attribute) {
127 attribute->SetOwner(nullptr);
128 size_t attr_length = attribute->length();
129 if (attr_length % 4 != 0) {
130 attr_length += (4 - (attr_length % 4));
131 }
132 length_ -= static_cast<uint16_t>(attr_length + 4);
133 }
134 return attribute;
135}
136
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000137const StunAddressAttribute* StunMessage::GetAddress(int type) const {
138 switch (type) {
139 case STUN_ATTR_MAPPED_ADDRESS: {
140 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
141 // missing.
142 const StunAttribute* mapped_address =
143 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
144 if (!mapped_address)
145 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
146 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
147 }
148
149 default:
150 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
151 }
152}
153
154const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
155 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
156}
157
158const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
159 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
160}
161
162const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
163 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
164}
165
166const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
167 return static_cast<const StunErrorCodeAttribute*>(
168 GetAttribute(STUN_ATTR_ERROR_CODE));
169}
170
deadbeef996fc6b2017-04-26 09:21:22 -0700171int StunMessage::GetErrorCodeValue() const {
172 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
173 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
174}
175
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000176const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
177 return static_cast<const StunUInt16ListAttribute*>(
178 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
179}
180
181// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
182// procedure outlined in RFC 5389, section 15.4.
Yves Gerey665174f2018-06-19 15:03:05 +0200183bool StunMessage::ValidateMessageIntegrity(const char* data,
184 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000185 const std::string& password) {
186 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700187 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000188 return false;
189 }
190
191 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200192 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000193 if (size != (msg_length + kStunHeaderSize)) {
194 return false;
195 }
196
197 // Finding Message Integrity attribute in stun message.
198 size_t current_pos = kStunHeaderSize;
199 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700200 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200201 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000202 // Getting attribute type and length.
203 attr_type = rtc::GetBE16(&data[current_pos]);
204 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
205
206 // If M-I, sanity check it, and break out.
207 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
208 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700209 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
210 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000211 return false;
212 }
213 has_message_integrity_attr = true;
214 break;
215 }
216
217 // Otherwise, skip to the next attribute.
218 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
219 if ((attr_length % 4) != 0) {
220 current_pos += (4 - (attr_length % 4));
221 }
222 }
223
224 if (!has_message_integrity_attr) {
225 return false;
226 }
227
228 // Getting length of the message to calculate Message Integrity.
229 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700230 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000231 memcpy(temp_data.get(), data, current_pos);
232 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
233 // Stun message has other attributes after message integrity.
234 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200235 size_t extra_offset =
236 size - (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000237 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
238
239 // Writing new length of the STUN message @ Message Length in temp buffer.
240 // 0 1 2 3
241 // 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
242 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
243 // |0 0| STUN Message Type | Message Length |
244 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200245 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000246 }
247
248 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200249 size_t ret =
250 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
251 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800252 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000253 if (ret != sizeof(hmac))
254 return false;
255
256 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200257 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000258 sizeof(hmac)) == 0;
259}
260
261bool StunMessage::AddMessageIntegrity(const std::string& password) {
262 return AddMessageIntegrity(password.c_str(), password.size());
263}
264
Yves Gerey665174f2018-06-19 15:03:05 +0200265bool StunMessage::AddMessageIntegrity(const char* key, size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000266 // Add the attribute with a dummy value. Since this is a known attribute, it
267 // can't fail.
Karl Wiberg918f50c2018-07-05 11:40:33 +0200268 auto msg_integrity_attr_ptr = absl::make_unique<StunByteStringAttribute>(
zsteinf42cc9d2017-03-27 16:17:19 -0700269 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
270 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
271 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000272
273 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700274 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000275 if (!Write(&buf))
276 return false;
277
278 int msg_len_for_hmac = static_cast<int>(
279 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
280 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200281 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
282 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800283 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000284 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100285 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200286 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000287 return false;
288 }
289
290 // Insert correct HMAC into the attribute.
291 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
292 return true;
293}
294
295// Verifies a message is in fact a STUN message, by performing the checks
296// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
297// in section 15.5.
298bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
299 // Check the message length.
300 size_t fingerprint_attr_size =
301 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
302 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
303 return false;
304
305 // Skip the rest if the magic cookie isn't present.
306 const char* magic_cookie =
307 data + kStunTransactionIdOffset - kStunMagicCookieLength;
308 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
309 return false;
310
311 // Check the fingerprint type and length.
312 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
313 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200314 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000315 StunUInt32Attribute::SIZE)
316 return false;
317
318 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200319 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
321 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200322 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000323}
324
325bool StunMessage::AddFingerprint() {
326 // Add the attribute with a dummy value. Since this is a known attribute,
327 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700328 auto fingerprint_attr_ptr =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200329 absl::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700330 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700331 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000332
333 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700334 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000335 if (!Write(&buf))
336 return false;
337
338 int msg_len_for_crc32 = static_cast<int>(
339 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200340 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000341
342 // Insert the correct CRC-32, XORed with a constant, into the attribute.
343 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
344 return true;
345}
346
jbauchf1f87202016-03-30 06:43:37 -0700347bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000348 if (!buf->ReadUInt16(&type_))
349 return false;
350
351 if (type_ & 0x8000) {
352 // RTP and RTCP set the MSB of first byte, since first two bits are version,
353 // and version is always 2 (10). If set, this is not a STUN packet.
354 return false;
355 }
356
357 if (!buf->ReadUInt16(&length_))
358 return false;
359
360 std::string magic_cookie;
361 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
362 return false;
363
364 std::string transaction_id;
365 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
366 return false;
367
Andrew Royes154d8392019-03-14 10:38:31 -0700368 uint32_t magic_cookie_int;
369 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
370 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
371 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000372 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
373 // If magic cookie is invalid it means that the peer implements
374 // RFC3489 instead of RFC5389.
375 transaction_id.insert(0, magic_cookie);
376 }
nisseede5da42017-01-12 05:15:36 -0800377 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000378 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800379 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000380
381 if (length_ != buf->Length())
382 return false;
383
zsteinad94c4c2017-03-06 13:36:05 -0800384 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000385
386 size_t rest = buf->Length() - length_;
387 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200388 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000389 if (!buf->ReadUInt16(&attr_type))
390 return false;
391 if (!buf->ReadUInt16(&attr_length))
392 return false;
393
Honghai Zhang3e024302016-09-22 09:52:16 -0700394 std::unique_ptr<StunAttribute> attr(
395 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000396 if (!attr) {
397 // Skip any unknown or malformed attributes.
398 if ((attr_length % 4) != 0) {
399 attr_length += (4 - (attr_length % 4));
400 }
401 if (!buf->Consume(attr_length))
402 return false;
403 } else {
404 if (!attr->Read(buf))
405 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800406 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000407 }
408 }
409
nisseede5da42017-01-12 05:15:36 -0800410 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000411 return true;
412}
413
jbauchf1f87202016-03-30 06:43:37 -0700414bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000415 buf->WriteUInt16(type_);
416 buf->WriteUInt16(length_);
417 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100418 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000419 buf->WriteString(transaction_id_);
420
zsteinad94c4c2017-03-06 13:36:05 -0800421 for (const auto& attr : attrs_) {
422 buf->WriteUInt16(attr->type());
423 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
424 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000425 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800426 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000427 }
428
429 return true;
430}
431
Steve Antonca7d54e2017-10-25 14:42:51 -0700432StunMessage* StunMessage::CreateNew() const {
433 return new StunMessage();
434}
435
Jonas Oreland7ca63112018-02-27 08:45:13 +0100436void StunMessage::SetStunMagicCookie(uint32_t val) {
437 stun_magic_cookie_ = val;
438}
439
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000440StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
441 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200442 case STUN_ATTR_MAPPED_ADDRESS:
443 return STUN_VALUE_ADDRESS;
444 case STUN_ATTR_USERNAME:
445 return STUN_VALUE_BYTE_STRING;
446 case STUN_ATTR_MESSAGE_INTEGRITY:
447 return STUN_VALUE_BYTE_STRING;
448 case STUN_ATTR_ERROR_CODE:
449 return STUN_VALUE_ERROR_CODE;
450 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
451 return STUN_VALUE_UINT16_LIST;
452 case STUN_ATTR_REALM:
453 return STUN_VALUE_BYTE_STRING;
454 case STUN_ATTR_NONCE:
455 return STUN_VALUE_BYTE_STRING;
456 case STUN_ATTR_XOR_MAPPED_ADDRESS:
457 return STUN_VALUE_XOR_ADDRESS;
458 case STUN_ATTR_SOFTWARE:
459 return STUN_VALUE_BYTE_STRING;
460 case STUN_ATTR_ALTERNATE_SERVER:
461 return STUN_VALUE_ADDRESS;
462 case STUN_ATTR_FINGERPRINT:
463 return STUN_VALUE_UINT32;
464 case STUN_ATTR_ORIGIN:
465 return STUN_VALUE_BYTE_STRING;
466 case STUN_ATTR_RETRANSMIT_COUNT:
467 return STUN_VALUE_UINT32;
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700468 case STUN_ATTR_LAST_ICE_CHECK_RECEIVED:
469 return STUN_VALUE_BYTE_STRING;
Yves Gerey665174f2018-06-19 15:03:05 +0200470 default:
471 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000472 }
473}
474
475StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
476 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200477 if (value_type != STUN_VALUE_UNKNOWN) {
478 return StunAttribute::Create(value_type, type,
479 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200480 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200481 // Read unknown attributes as STUN_VALUE_BYTE_STRING
482 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
483 static_cast<uint16_t>(length), this);
484 } else {
485 return NULL;
486 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000487}
488
489const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800490 for (const auto& attr : attrs_) {
491 if (attr->type() == type) {
492 return attr.get();
493 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000494 }
495 return NULL;
496}
497
498bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
499 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200500 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000501}
502
503// StunAttribute
504
Peter Boström0c4e06b2015-10-07 12:23:21 +0200505StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200506 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000507
jbauchf1f87202016-03-30 06:43:37 -0700508void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000509 int remainder = length_ % 4;
510 if (remainder > 0) {
511 buf->Consume(4 - remainder);
512 }
513}
514
jbauchf1f87202016-03-30 06:43:37 -0700515void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000516 int remainder = length_ % 4;
517 if (remainder > 0) {
518 char zeroes[4] = {0};
519 buf->WriteBytes(zeroes, 4 - remainder);
520 }
521}
522
523StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200524 uint16_t type,
525 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000526 StunMessage* owner) {
527 switch (value_type) {
528 case STUN_VALUE_ADDRESS:
529 return new StunAddressAttribute(type, length);
530 case STUN_VALUE_XOR_ADDRESS:
531 return new StunXorAddressAttribute(type, length, owner);
532 case STUN_VALUE_UINT32:
533 return new StunUInt32Attribute(type);
534 case STUN_VALUE_UINT64:
535 return new StunUInt64Attribute(type);
536 case STUN_VALUE_BYTE_STRING:
537 return new StunByteStringAttribute(type, length);
538 case STUN_VALUE_ERROR_CODE:
539 return new StunErrorCodeAttribute(type, length);
540 case STUN_VALUE_UINT16_LIST:
541 return new StunUInt16ListAttribute(type, length);
542 default:
543 return NULL;
544 }
545}
546
zsteinf42cc9d2017-03-27 16:17:19 -0700547std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
548 uint16_t type) {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200549 return absl::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000550}
551
zsteinf42cc9d2017-03-27 16:17:19 -0700552std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
553 uint16_t type) {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200554 return absl::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000555}
556
zsteinf42cc9d2017-03-27 16:17:19 -0700557std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
558 uint16_t type) {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200559 return absl::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000560}
561
zsteinf42cc9d2017-03-27 16:17:19 -0700562std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
563 uint16_t type) {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200564 return absl::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000565}
566
zsteinf42cc9d2017-03-27 16:17:19 -0700567std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
568 uint16_t type) {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200569 return absl::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000570}
571
zsteinf42cc9d2017-03-27 16:17:19 -0700572std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200573 return absl::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
575}
576
zsteinf42cc9d2017-03-27 16:17:19 -0700577std::unique_ptr<StunUInt16ListAttribute>
578StunAttribute::CreateUnknownAttributes() {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200579 return absl::make_unique<StunUInt16ListAttribute>(
580 STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000581}
582
Peter Boström0c4e06b2015-10-07 12:23:21 +0200583StunAddressAttribute::StunAddressAttribute(uint16_t type,
584 const rtc::SocketAddress& addr)
585 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000586 SetAddress(addr);
587}
588
Peter Boström0c4e06b2015-10-07 12:23:21 +0200589StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200590 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000591
Steve Antonca7d54e2017-10-25 14:42:51 -0700592StunAttributeValueType StunAddressAttribute::value_type() const {
593 return STUN_VALUE_ADDRESS;
594}
595
jbauchf1f87202016-03-30 06:43:37 -0700596bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200597 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000598 if (!buf->ReadUInt8(&dummy))
599 return false;
600
Peter Boström0c4e06b2015-10-07 12:23:21 +0200601 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000602 if (!buf->ReadUInt8(&stun_family)) {
603 return false;
604 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200605 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000606 if (!buf->ReadUInt16(&port))
607 return false;
608 if (stun_family == STUN_ADDRESS_IPV4) {
609 in_addr v4addr;
610 if (length() != SIZE_IP4) {
611 return false;
612 }
613 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
614 return false;
615 }
616 rtc::IPAddress ipaddr(v4addr);
617 SetAddress(rtc::SocketAddress(ipaddr, port));
618 } else if (stun_family == STUN_ADDRESS_IPV6) {
619 in6_addr v6addr;
620 if (length() != SIZE_IP6) {
621 return false;
622 }
623 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
624 return false;
625 }
626 rtc::IPAddress ipaddr(v6addr);
627 SetAddress(rtc::SocketAddress(ipaddr, port));
628 } else {
629 return false;
630 }
631 return true;
632}
633
jbauchf1f87202016-03-30 06:43:37 -0700634bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000635 StunAddressFamily address_family = family();
636 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100637 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000638 return false;
639 }
640 buf->WriteUInt8(0);
641 buf->WriteUInt8(address_family);
642 buf->WriteUInt16(address_.port());
643 switch (address_.family()) {
644 case AF_INET: {
645 in_addr v4addr = address_.ipaddr().ipv4_address();
646 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
647 break;
648 }
649 case AF_INET6: {
650 in6_addr v6addr = address_.ipaddr().ipv6_address();
651 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
652 break;
653 }
654 }
655 return true;
656}
657
Peter Boström0c4e06b2015-10-07 12:23:21 +0200658StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
659 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200660 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000661
Peter Boström0c4e06b2015-10-07 12:23:21 +0200662StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
663 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000664 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200665 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000666
Steve Antonca7d54e2017-10-25 14:42:51 -0700667StunAttributeValueType StunXorAddressAttribute::value_type() const {
668 return STUN_VALUE_XOR_ADDRESS;
669}
670
671void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
672 owner_ = owner;
673}
674
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000675rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
676 if (owner_) {
677 rtc::IPAddress ip = ipaddr();
678 switch (ip.family()) {
679 case AF_INET: {
680 in_addr v4addr = ip.ipv4_address();
681 v4addr.s_addr =
682 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
683 return rtc::IPAddress(v4addr);
684 }
685 case AF_INET6: {
686 in6_addr v6addr = ip.ipv6_address();
687 const std::string& transaction_id = owner_->transaction_id();
688 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200689 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000690 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
691 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200692 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000693 // Transaction ID is in network byte order, but magic cookie
694 // is stored in host byte order.
695 ip_as_ints[0] =
696 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
697 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
698 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
699 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
700 return rtc::IPAddress(v6addr);
701 }
702 break;
703 }
704 }
705 }
706 // Invalid ip family or transaction ID, or missing owner.
707 // Return an AF_UNSPEC address.
708 return rtc::IPAddress();
709}
710
jbauchf1f87202016-03-30 06:43:37 -0700711bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000712 if (!StunAddressAttribute::Read(buf))
713 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200714 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000715 rtc::IPAddress xored_ip = GetXoredIP();
716 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
717 return true;
718}
719
jbauchf1f87202016-03-30 06:43:37 -0700720bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000721 StunAddressFamily address_family = family();
722 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100723 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000724 return false;
725 }
726 rtc::IPAddress xored_ip = GetXoredIP();
727 if (xored_ip.family() == AF_UNSPEC) {
728 return false;
729 }
730 buf->WriteUInt8(0);
731 buf->WriteUInt8(family());
732 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
733 switch (xored_ip.family()) {
734 case AF_INET: {
735 in_addr v4addr = xored_ip.ipv4_address();
736 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
737 break;
738 }
739 case AF_INET6: {
740 in6_addr v6addr = xored_ip.ipv6_address();
741 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
742 break;
743 }
744 }
745 return true;
746}
747
Peter Boström0c4e06b2015-10-07 12:23:21 +0200748StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200749 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000750
Peter Boström0c4e06b2015-10-07 12:23:21 +0200751StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200752 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000753
Steve Antonca7d54e2017-10-25 14:42:51 -0700754StunAttributeValueType StunUInt32Attribute::value_type() const {
755 return STUN_VALUE_UINT32;
756}
757
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000758bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800759 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000760 return static_cast<bool>((bits_ >> index) & 0x1);
761}
762
763void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800764 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000765 bits_ &= ~(1 << index);
766 bits_ |= value ? (1 << index) : 0;
767}
768
jbauchf1f87202016-03-30 06:43:37 -0700769bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000770 if (length() != SIZE || !buf->ReadUInt32(&bits_))
771 return false;
772 return true;
773}
774
jbauchf1f87202016-03-30 06:43:37 -0700775bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000776 buf->WriteUInt32(bits_);
777 return true;
778}
779
Peter Boström0c4e06b2015-10-07 12:23:21 +0200780StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200781 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000782
Peter Boström0c4e06b2015-10-07 12:23:21 +0200783StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200784 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000785
Steve Antonca7d54e2017-10-25 14:42:51 -0700786StunAttributeValueType StunUInt64Attribute::value_type() const {
787 return STUN_VALUE_UINT64;
788}
789
jbauchf1f87202016-03-30 06:43:37 -0700790bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000791 if (length() != SIZE || !buf->ReadUInt64(&bits_))
792 return false;
793 return true;
794}
795
jbauchf1f87202016-03-30 06:43:37 -0700796bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000797 buf->WriteUInt64(bits_);
798 return true;
799}
800
Peter Boström0c4e06b2015-10-07 12:23:21 +0200801StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200802 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000803
Peter Boström0c4e06b2015-10-07 12:23:21 +0200804StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000805 const std::string& str)
806 : StunAttribute(type, 0), bytes_(NULL) {
807 CopyBytes(str.c_str(), str.size());
808}
809
Peter Boström0c4e06b2015-10-07 12:23:21 +0200810StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000811 const void* bytes,
812 size_t length)
813 : StunAttribute(type, 0), bytes_(NULL) {
814 CopyBytes(bytes, length);
815}
816
Peter Boström0c4e06b2015-10-07 12:23:21 +0200817StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200818 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000819
820StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +0200821 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000822}
823
Steve Antonca7d54e2017-10-25 14:42:51 -0700824StunAttributeValueType StunByteStringAttribute::value_type() const {
825 return STUN_VALUE_BYTE_STRING;
826}
827
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000828void StunByteStringAttribute::CopyBytes(const char* bytes) {
829 CopyBytes(bytes, strlen(bytes));
830}
831
832void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
833 char* new_bytes = new char[length];
834 memcpy(new_bytes, bytes, length);
835 SetBytes(new_bytes, length);
836}
837
Peter Boström0c4e06b2015-10-07 12:23:21 +0200838uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800839 RTC_DCHECK(bytes_ != NULL);
840 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200841 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000842}
843
Peter Boström0c4e06b2015-10-07 12:23:21 +0200844void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800845 RTC_DCHECK(bytes_ != NULL);
846 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000847 bytes_[index] = value;
848}
849
jbauchf1f87202016-03-30 06:43:37 -0700850bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000851 bytes_ = new char[length()];
852 if (!buf->ReadBytes(bytes_, length())) {
853 return false;
854 }
855
856 ConsumePadding(buf);
857 return true;
858}
859
jbauchf1f87202016-03-30 06:43:37 -0700860bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000861 buf->WriteBytes(bytes_, length());
862 WritePadding(buf);
863 return true;
864}
865
866void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +0200867 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000868 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200869 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000870}
871
zsteinf42cc9d2017-03-27 16:17:19 -0700872const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
873
Peter Boström0c4e06b2015-10-07 12:23:21 +0200874StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
875 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000876 const std::string& reason)
877 : StunAttribute(type, 0) {
878 SetCode(code);
879 SetReason(reason);
880}
881
Peter Boström0c4e06b2015-10-07 12:23:21 +0200882StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200883 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000884
Yves Gerey665174f2018-06-19 15:03:05 +0200885StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000886
Steve Antonca7d54e2017-10-25 14:42:51 -0700887StunAttributeValueType StunErrorCodeAttribute::value_type() const {
888 return STUN_VALUE_ERROR_CODE;
889}
890
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000891int StunErrorCodeAttribute::code() const {
892 return class_ * 100 + number_;
893}
894
895void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200896 class_ = static_cast<uint8_t>(code / 100);
897 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000898}
899
900void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200901 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000902 reason_ = reason;
903}
904
jbauchf1f87202016-03-30 06:43:37 -0700905bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200906 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000907 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
908 return false;
909
910 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100911 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000912
913 class_ = ((val >> 8) & 0x7);
914 number_ = (val & 0xff);
915
916 if (!buf->ReadString(&reason_, length() - 4))
917 return false;
918
919 ConsumePadding(buf);
920 return true;
921}
922
jbauchf1f87202016-03-30 06:43:37 -0700923bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000924 buf->WriteUInt32(class_ << 8 | number_);
925 buf->WriteString(reason_);
926 WritePadding(buf);
927 return true;
928}
929
Peter Boström0c4e06b2015-10-07 12:23:21 +0200930StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000931 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200932 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000933}
934
935StunUInt16ListAttribute::~StunUInt16ListAttribute() {
936 delete attr_types_;
937}
938
Steve Antonca7d54e2017-10-25 14:42:51 -0700939StunAttributeValueType StunUInt16ListAttribute::value_type() const {
940 return STUN_VALUE_UINT16_LIST;
941}
942
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000943size_t StunUInt16ListAttribute::Size() const {
944 return attr_types_->size();
945}
946
Peter Boström0c4e06b2015-10-07 12:23:21 +0200947uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000948 return (*attr_types_)[index];
949}
950
Peter Boström0c4e06b2015-10-07 12:23:21 +0200951void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000952 (*attr_types_)[index] = value;
953}
954
Peter Boström0c4e06b2015-10-07 12:23:21 +0200955void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000956 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200957 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000958}
959
jbauchf1f87202016-03-30 06:43:37 -0700960bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000961 if (length() % 2)
962 return false;
963
964 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200965 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000966 if (!buf->ReadUInt16(&attr))
967 return false;
968 attr_types_->push_back(attr);
969 }
970 // Padding of these attributes is done in RFC 5389 style. This is
971 // slightly different from RFC3489, but it shouldn't be important.
972 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
973 // entries in the list (not necessarily the last one - it's unspecified).
974 // RFC5389 pads on the end, and the bytes are always ignored.
975 ConsumePadding(buf);
976 return true;
977}
978
jbauchf1f87202016-03-30 06:43:37 -0700979bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000980 for (size_t i = 0; i < attr_types_->size(); ++i) {
981 buf->WriteUInt16((*attr_types_)[i]);
982 }
983 WritePadding(buf);
984 return true;
985}
986
987int GetStunSuccessResponseType(int req_type) {
988 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
989}
990
991int GetStunErrorResponseType(int req_type) {
992 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
993}
994
995bool IsStunRequestType(int msg_type) {
996 return ((msg_type & kStunTypeMask) == 0x000);
997}
998
999bool IsStunIndicationType(int msg_type) {
1000 return ((msg_type & kStunTypeMask) == 0x010);
1001}
1002
1003bool IsStunSuccessResponseType(int msg_type) {
1004 return ((msg_type & kStunTypeMask) == 0x100);
1005}
1006
1007bool IsStunErrorResponseType(int msg_type) {
1008 return ((msg_type & kStunTypeMask) == 0x110);
1009}
1010
1011bool ComputeStunCredentialHash(const std::string& username,
1012 const std::string& realm,
1013 const std::string& password,
1014 std::string* hash) {
1015 // http://tools.ietf.org/html/rfc5389#section-15.4
1016 // long-term credentials will be calculated using the key and key is
1017 // key = MD5(username ":" realm ":" SASLprep(password))
1018 std::string input = username;
1019 input += ':';
1020 input += realm;
1021 input += ':';
1022 input += password;
1023
1024 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001025 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1026 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001027 if (size == 0) {
1028 return false;
1029 }
1030
1031 *hash = std::string(digest, size);
1032 return true;
1033}
1034
Jonas Oreland202994c2017-12-18 12:10:43 +01001035std::unique_ptr<StunAttribute> CopyStunAttribute(
1036 const StunAttribute& attribute,
1037 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1038 ByteBufferWriter tmpBuffer;
1039 if (tmp_buffer_ptr == nullptr) {
1040 tmp_buffer_ptr = &tmpBuffer;
1041 }
1042
Yves Gerey665174f2018-06-19 15:03:05 +02001043 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1044 attribute.value_type(), attribute.type(),
1045 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001046
1047 if (!copy) {
1048 return nullptr;
1049 }
1050 tmp_buffer_ptr->Clear();
1051 if (!attribute.Write(tmp_buffer_ptr)) {
1052 return nullptr;
1053 }
1054 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1055 if (!copy->Read(&reader)) {
1056 return nullptr;
1057 }
1058
1059 return copy;
1060}
1061
Steve Antonca7d54e2017-10-25 14:42:51 -07001062StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1063 switch (type) {
1064 case STUN_ATTR_LIFETIME:
1065 return STUN_VALUE_UINT32;
1066 case STUN_ATTR_MAGIC_COOKIE:
1067 return STUN_VALUE_BYTE_STRING;
1068 case STUN_ATTR_BANDWIDTH:
1069 return STUN_VALUE_UINT32;
1070 case STUN_ATTR_DESTINATION_ADDRESS:
1071 return STUN_VALUE_ADDRESS;
1072 case STUN_ATTR_SOURCE_ADDRESS2:
1073 return STUN_VALUE_ADDRESS;
1074 case STUN_ATTR_DATA:
1075 return STUN_VALUE_BYTE_STRING;
1076 case STUN_ATTR_OPTIONS:
1077 return STUN_VALUE_UINT32;
1078 default:
1079 return StunMessage::GetAttributeValueType(type);
1080 }
1081}
1082
1083StunMessage* RelayMessage::CreateNew() const {
1084 return new RelayMessage();
1085}
1086
1087StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1088 switch (type) {
1089 case STUN_ATTR_CHANNEL_NUMBER:
1090 return STUN_VALUE_UINT32;
1091 case STUN_ATTR_TURN_LIFETIME:
1092 return STUN_VALUE_UINT32;
1093 case STUN_ATTR_XOR_PEER_ADDRESS:
1094 return STUN_VALUE_XOR_ADDRESS;
1095 case STUN_ATTR_DATA:
1096 return STUN_VALUE_BYTE_STRING;
1097 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1098 return STUN_VALUE_XOR_ADDRESS;
1099 case STUN_ATTR_EVEN_PORT:
1100 return STUN_VALUE_BYTE_STRING;
1101 case STUN_ATTR_REQUESTED_TRANSPORT:
1102 return STUN_VALUE_UINT32;
1103 case STUN_ATTR_DONT_FRAGMENT:
1104 return STUN_VALUE_BYTE_STRING;
1105 case STUN_ATTR_RESERVATION_TOKEN:
1106 return STUN_VALUE_BYTE_STRING;
1107 default:
1108 return StunMessage::GetAttributeValueType(type);
1109 }
1110}
1111
1112StunMessage* TurnMessage::CreateNew() const {
1113 return new TurnMessage();
1114}
1115
1116StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1117 switch (type) {
1118 case STUN_ATTR_PRIORITY:
1119 case STUN_ATTR_NETWORK_INFO:
1120 case STUN_ATTR_NOMINATION:
1121 return STUN_VALUE_UINT32;
1122 case STUN_ATTR_USE_CANDIDATE:
1123 return STUN_VALUE_BYTE_STRING;
1124 case STUN_ATTR_ICE_CONTROLLED:
1125 return STUN_VALUE_UINT64;
1126 case STUN_ATTR_ICE_CONTROLLING:
1127 return STUN_VALUE_UINT64;
1128 default:
1129 return StunMessage::GetAttributeValueType(type);
1130 }
1131}
1132
1133StunMessage* IceMessage::CreateNew() const {
1134 return new IceMessage();
1135}
1136
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001137} // namespace cricket