blob: 6e8f09826872e5575f1f34c6359121650fe499dd [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
kwiberg3ec46792016-04-27 07:22:53 -070015#include <memory>
Steve Anton6c38cc72017-11-29 10:25:58 -080016#include <utility>
kwiberg3ec46792016-04-27 07:22:53 -070017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/byteorder.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/crc32.h"
21#include "rtc_base/logging.h"
22#include "rtc_base/messagedigest.h"
23#include "rtc_base/ptr_util.h"
24#include "rtc_base/stringencode.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
29namespace cricket {
30
31const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
32const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
33const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
34const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
35const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
36const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
37const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
38const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
39const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
40const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
41const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
42
43const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
44const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020045const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000046
47// StunMessage
48
49StunMessage::StunMessage()
50 : type_(0),
51 length_(0),
52 transaction_id_(EMPTY_TRANSACTION_ID) {
nisseede5da42017-01-12 05:15:36 -080053 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000054}
55
Steve Antonca7d54e2017-10-25 14:42:51 -070056StunMessage::~StunMessage() = default;
57
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000058bool StunMessage::IsLegacy() const {
59 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
60 return true;
nisseede5da42017-01-12 05:15:36 -080061 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000062 return false;
63}
64
65bool StunMessage::SetTransactionID(const std::string& str) {
66 if (!IsValidTransactionId(str)) {
67 return false;
68 }
69 transaction_id_ = str;
70 return true;
71}
72
Steve Anton6c38cc72017-11-29 10:25:58 -080073static bool ImplementationDefinedRange(int attr_type) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020074 return attr_type >= 0xC000 && attr_type <= 0xFFFF;
75}
76
zsteinf42cc9d2017-03-27 16:17:19 -070077void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020078 // Fail any attributes that aren't valid for this type of message,
79 // but allow any type for the range that is "implementation defined"
80 // in the RFC.
81 if (!ImplementationDefinedRange(attr->type())) {
82 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
83 }
nissecc99bc22017-02-02 01:31:30 -080084
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000085 attr->SetOwner(this);
86 size_t attr_length = attr->length();
87 if (attr_length % 4 != 0) {
88 attr_length += (4 - (attr_length % 4));
89 }
Peter Boström0c4e06b2015-10-07 12:23:21 +020090 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -070091
92 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000093}
94
Jonas Oreland202994c2017-12-18 12:10:43 +010095std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
96 std::unique_ptr<StunAttribute> attribute;
97 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
98 if ((* it)->type() == type) {
99 attribute = std::move(* it);
100 attrs_.erase(std::next(it).base());
101 break;
102 }
103 }
104 if (attribute) {
105 attribute->SetOwner(nullptr);
106 size_t attr_length = attribute->length();
107 if (attr_length % 4 != 0) {
108 attr_length += (4 - (attr_length % 4));
109 }
110 length_ -= static_cast<uint16_t>(attr_length + 4);
111 }
112 return attribute;
113}
114
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000115const StunAddressAttribute* StunMessage::GetAddress(int type) const {
116 switch (type) {
117 case STUN_ATTR_MAPPED_ADDRESS: {
118 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
119 // missing.
120 const StunAttribute* mapped_address =
121 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
122 if (!mapped_address)
123 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
124 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
125 }
126
127 default:
128 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
129 }
130}
131
132const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
133 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
134}
135
136const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
137 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
138}
139
140const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
141 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
142}
143
144const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
145 return static_cast<const StunErrorCodeAttribute*>(
146 GetAttribute(STUN_ATTR_ERROR_CODE));
147}
148
deadbeef996fc6b2017-04-26 09:21:22 -0700149int StunMessage::GetErrorCodeValue() const {
150 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
151 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
152}
153
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000154const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
155 return static_cast<const StunUInt16ListAttribute*>(
156 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
157}
158
159// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
160// procedure outlined in RFC 5389, section 15.4.
161bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
162 const std::string& password) {
163 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700164 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000165 return false;
166 }
167
168 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200169 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000170 if (size != (msg_length + kStunHeaderSize)) {
171 return false;
172 }
173
174 // Finding Message Integrity attribute in stun message.
175 size_t current_pos = kStunHeaderSize;
176 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700177 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200178 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000179 // Getting attribute type and length.
180 attr_type = rtc::GetBE16(&data[current_pos]);
181 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
182
183 // If M-I, sanity check it, and break out.
184 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
185 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700186 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
187 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000188 return false;
189 }
190 has_message_integrity_attr = true;
191 break;
192 }
193
194 // Otherwise, skip to the next attribute.
195 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
196 if ((attr_length % 4) != 0) {
197 current_pos += (4 - (attr_length % 4));
198 }
199 }
200
201 if (!has_message_integrity_attr) {
202 return false;
203 }
204
205 // Getting length of the message to calculate Message Integrity.
206 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700207 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000208 memcpy(temp_data.get(), data, current_pos);
209 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
210 // Stun message has other attributes after message integrity.
211 // Adjust the length parameter in stun message to calculate HMAC.
212 size_t extra_offset = size -
213 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
214 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
215
216 // Writing new length of the STUN message @ Message Length in temp buffer.
217 // 0 1 2 3
218 // 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
219 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
220 // |0 0| STUN Message Type | Message Length |
221 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200222 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000223 }
224
225 char hmac[kStunMessageIntegritySize];
226 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
227 password.c_str(), password.size(),
228 temp_data.get(), mi_pos,
229 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800230 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000231 if (ret != sizeof(hmac))
232 return false;
233
234 // Comparing the calculated HMAC with the one present in the message.
235 return memcmp(data + current_pos + kStunAttributeHeaderSize,
236 hmac,
237 sizeof(hmac)) == 0;
238}
239
240bool StunMessage::AddMessageIntegrity(const std::string& password) {
241 return AddMessageIntegrity(password.c_str(), password.size());
242}
243
244bool StunMessage::AddMessageIntegrity(const char* key,
245 size_t keylen) {
246 // Add the attribute with a dummy value. Since this is a known attribute, it
247 // can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700248 auto msg_integrity_attr_ptr = rtc::MakeUnique<StunByteStringAttribute>(
249 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
250 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
251 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000252
253 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700254 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000255 if (!Write(&buf))
256 return false;
257
258 int msg_len_for_hmac = static_cast<int>(
259 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
260 char hmac[kStunMessageIntegritySize];
261 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
262 key, keylen,
263 buf.Data(), msg_len_for_hmac,
264 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800265 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000266 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100267 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
268 << "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000269 return false;
270 }
271
272 // Insert correct HMAC into the attribute.
273 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
274 return true;
275}
276
277// Verifies a message is in fact a STUN message, by performing the checks
278// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
279// in section 15.5.
280bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
281 // Check the message length.
282 size_t fingerprint_attr_size =
283 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
284 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
285 return false;
286
287 // Skip the rest if the magic cookie isn't present.
288 const char* magic_cookie =
289 data + kStunTransactionIdOffset - kStunMagicCookieLength;
290 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
291 return false;
292
293 // Check the fingerprint type and length.
294 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
295 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200296 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000297 StunUInt32Attribute::SIZE)
298 return false;
299
300 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200301 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000302 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
303 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
304 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
305}
306
307bool StunMessage::AddFingerprint() {
308 // Add the attribute with a dummy value. Since this is a known attribute,
309 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700310 auto fingerprint_attr_ptr =
311 rtc::MakeUnique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700312 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700313 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000314
315 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700316 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000317 if (!Write(&buf))
318 return false;
319
320 int msg_len_for_crc32 = static_cast<int>(
321 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200322 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000323
324 // Insert the correct CRC-32, XORed with a constant, into the attribute.
325 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
326 return true;
327}
328
jbauchf1f87202016-03-30 06:43:37 -0700329bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000330 if (!buf->ReadUInt16(&type_))
331 return false;
332
333 if (type_ & 0x8000) {
334 // RTP and RTCP set the MSB of first byte, since first two bits are version,
335 // and version is always 2 (10). If set, this is not a STUN packet.
336 return false;
337 }
338
339 if (!buf->ReadUInt16(&length_))
340 return false;
341
342 std::string magic_cookie;
343 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
344 return false;
345
346 std::string transaction_id;
347 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
348 return false;
349
Peter Boström0c4e06b2015-10-07 12:23:21 +0200350 uint32_t magic_cookie_int =
351 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000352 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
353 // If magic cookie is invalid it means that the peer implements
354 // RFC3489 instead of RFC5389.
355 transaction_id.insert(0, magic_cookie);
356 }
nisseede5da42017-01-12 05:15:36 -0800357 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000358 transaction_id_ = transaction_id;
359
360 if (length_ != buf->Length())
361 return false;
362
zsteinad94c4c2017-03-06 13:36:05 -0800363 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000364
365 size_t rest = buf->Length() - length_;
366 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200367 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000368 if (!buf->ReadUInt16(&attr_type))
369 return false;
370 if (!buf->ReadUInt16(&attr_length))
371 return false;
372
Honghai Zhang3e024302016-09-22 09:52:16 -0700373 std::unique_ptr<StunAttribute> attr(
374 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000375 if (!attr) {
376 // Skip any unknown or malformed attributes.
377 if ((attr_length % 4) != 0) {
378 attr_length += (4 - (attr_length % 4));
379 }
380 if (!buf->Consume(attr_length))
381 return false;
382 } else {
383 if (!attr->Read(buf))
384 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800385 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000386 }
387 }
388
nisseede5da42017-01-12 05:15:36 -0800389 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000390 return true;
391}
392
jbauchf1f87202016-03-30 06:43:37 -0700393bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000394 buf->WriteUInt16(type_);
395 buf->WriteUInt16(length_);
396 if (!IsLegacy())
397 buf->WriteUInt32(kStunMagicCookie);
398 buf->WriteString(transaction_id_);
399
zsteinad94c4c2017-03-06 13:36:05 -0800400 for (const auto& attr : attrs_) {
401 buf->WriteUInt16(attr->type());
402 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
403 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000404 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800405 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000406 }
407
408 return true;
409}
410
Steve Antonca7d54e2017-10-25 14:42:51 -0700411StunMessage* StunMessage::CreateNew() const {
412 return new StunMessage();
413}
414
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000415StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
416 switch (type) {
417 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
418 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
419 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
420 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
421 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
422 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
423 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
424 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
425 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
426 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS;
427 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000428 case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000429 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
430 default: return STUN_VALUE_UNKNOWN;
431 }
432}
433
434StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
435 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200436 if (value_type != STUN_VALUE_UNKNOWN) {
437 return StunAttribute::Create(value_type, type,
438 static_cast<uint16_t>(length), this);
439 } else if (ImplementationDefinedRange(type)) {
440 // Read unknown attributes as STUN_VALUE_BYTE_STRING
441 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
442 static_cast<uint16_t>(length), this);
443 } else {
444 return NULL;
445 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000446}
447
448const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800449 for (const auto& attr : attrs_) {
450 if (attr->type() == type) {
451 return attr.get();
452 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000453 }
454 return NULL;
455}
456
457bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
458 return transaction_id.size() == kStunTransactionIdLength ||
459 transaction_id.size() == kStunLegacyTransactionIdLength;
460}
461
462// StunAttribute
463
Peter Boström0c4e06b2015-10-07 12:23:21 +0200464StunAttribute::StunAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000465 : type_(type), length_(length) {
466}
467
jbauchf1f87202016-03-30 06:43:37 -0700468void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000469 int remainder = length_ % 4;
470 if (remainder > 0) {
471 buf->Consume(4 - remainder);
472 }
473}
474
jbauchf1f87202016-03-30 06:43:37 -0700475void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000476 int remainder = length_ % 4;
477 if (remainder > 0) {
478 char zeroes[4] = {0};
479 buf->WriteBytes(zeroes, 4 - remainder);
480 }
481}
482
483StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200484 uint16_t type,
485 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000486 StunMessage* owner) {
487 switch (value_type) {
488 case STUN_VALUE_ADDRESS:
489 return new StunAddressAttribute(type, length);
490 case STUN_VALUE_XOR_ADDRESS:
491 return new StunXorAddressAttribute(type, length, owner);
492 case STUN_VALUE_UINT32:
493 return new StunUInt32Attribute(type);
494 case STUN_VALUE_UINT64:
495 return new StunUInt64Attribute(type);
496 case STUN_VALUE_BYTE_STRING:
497 return new StunByteStringAttribute(type, length);
498 case STUN_VALUE_ERROR_CODE:
499 return new StunErrorCodeAttribute(type, length);
500 case STUN_VALUE_UINT16_LIST:
501 return new StunUInt16ListAttribute(type, length);
502 default:
503 return NULL;
504 }
505}
506
zsteinf42cc9d2017-03-27 16:17:19 -0700507std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
508 uint16_t type) {
509 return rtc::MakeUnique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000510}
511
zsteinf42cc9d2017-03-27 16:17:19 -0700512std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
513 uint16_t type) {
514 return rtc::MakeUnique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000515}
516
zsteinf42cc9d2017-03-27 16:17:19 -0700517std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
518 uint16_t type) {
519 return rtc::MakeUnique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000520}
521
zsteinf42cc9d2017-03-27 16:17:19 -0700522std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
523 uint16_t type) {
524 return rtc::MakeUnique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000525}
526
zsteinf42cc9d2017-03-27 16:17:19 -0700527std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
528 uint16_t type) {
529 return rtc::MakeUnique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000530}
531
zsteinf42cc9d2017-03-27 16:17:19 -0700532std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
533 return rtc::MakeUnique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000534 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
535}
536
zsteinf42cc9d2017-03-27 16:17:19 -0700537std::unique_ptr<StunUInt16ListAttribute>
538StunAttribute::CreateUnknownAttributes() {
539 return rtc::MakeUnique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
540 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000541}
542
Peter Boström0c4e06b2015-10-07 12:23:21 +0200543StunAddressAttribute::StunAddressAttribute(uint16_t type,
544 const rtc::SocketAddress& addr)
545 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000546 SetAddress(addr);
547}
548
Peter Boström0c4e06b2015-10-07 12:23:21 +0200549StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000550 : StunAttribute(type, length) {
551}
552
Steve Antonca7d54e2017-10-25 14:42:51 -0700553StunAttributeValueType StunAddressAttribute::value_type() const {
554 return STUN_VALUE_ADDRESS;
555}
556
jbauchf1f87202016-03-30 06:43:37 -0700557bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200558 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000559 if (!buf->ReadUInt8(&dummy))
560 return false;
561
Peter Boström0c4e06b2015-10-07 12:23:21 +0200562 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000563 if (!buf->ReadUInt8(&stun_family)) {
564 return false;
565 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200566 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000567 if (!buf->ReadUInt16(&port))
568 return false;
569 if (stun_family == STUN_ADDRESS_IPV4) {
570 in_addr v4addr;
571 if (length() != SIZE_IP4) {
572 return false;
573 }
574 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
575 return false;
576 }
577 rtc::IPAddress ipaddr(v4addr);
578 SetAddress(rtc::SocketAddress(ipaddr, port));
579 } else if (stun_family == STUN_ADDRESS_IPV6) {
580 in6_addr v6addr;
581 if (length() != SIZE_IP6) {
582 return false;
583 }
584 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
585 return false;
586 }
587 rtc::IPAddress ipaddr(v6addr);
588 SetAddress(rtc::SocketAddress(ipaddr, port));
589 } else {
590 return false;
591 }
592 return true;
593}
594
jbauchf1f87202016-03-30 06:43:37 -0700595bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000596 StunAddressFamily address_family = family();
597 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100598 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000599 return false;
600 }
601 buf->WriteUInt8(0);
602 buf->WriteUInt8(address_family);
603 buf->WriteUInt16(address_.port());
604 switch (address_.family()) {
605 case AF_INET: {
606 in_addr v4addr = address_.ipaddr().ipv4_address();
607 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
608 break;
609 }
610 case AF_INET6: {
611 in6_addr v6addr = address_.ipaddr().ipv6_address();
612 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
613 break;
614 }
615 }
616 return true;
617}
618
Peter Boström0c4e06b2015-10-07 12:23:21 +0200619StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
620 const rtc::SocketAddress& addr)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000621 : StunAddressAttribute(type, addr), owner_(NULL) {
622}
623
Peter Boström0c4e06b2015-10-07 12:23:21 +0200624StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
625 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000626 StunMessage* owner)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200627 : StunAddressAttribute(type, length), owner_(owner) {
628}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000629
Steve Antonca7d54e2017-10-25 14:42:51 -0700630StunAttributeValueType StunXorAddressAttribute::value_type() const {
631 return STUN_VALUE_XOR_ADDRESS;
632}
633
634void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
635 owner_ = owner;
636}
637
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000638rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
639 if (owner_) {
640 rtc::IPAddress ip = ipaddr();
641 switch (ip.family()) {
642 case AF_INET: {
643 in_addr v4addr = ip.ipv4_address();
644 v4addr.s_addr =
645 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
646 return rtc::IPAddress(v4addr);
647 }
648 case AF_INET6: {
649 in6_addr v6addr = ip.ipv6_address();
650 const std::string& transaction_id = owner_->transaction_id();
651 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200652 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000653 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
654 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200655 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000656 // Transaction ID is in network byte order, but magic cookie
657 // is stored in host byte order.
658 ip_as_ints[0] =
659 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
660 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
661 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
662 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
663 return rtc::IPAddress(v6addr);
664 }
665 break;
666 }
667 }
668 }
669 // Invalid ip family or transaction ID, or missing owner.
670 // Return an AF_UNSPEC address.
671 return rtc::IPAddress();
672}
673
jbauchf1f87202016-03-30 06:43:37 -0700674bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000675 if (!StunAddressAttribute::Read(buf))
676 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200677 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000678 rtc::IPAddress xored_ip = GetXoredIP();
679 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
680 return true;
681}
682
jbauchf1f87202016-03-30 06:43:37 -0700683bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000684 StunAddressFamily address_family = family();
685 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100686 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000687 return false;
688 }
689 rtc::IPAddress xored_ip = GetXoredIP();
690 if (xored_ip.family() == AF_UNSPEC) {
691 return false;
692 }
693 buf->WriteUInt8(0);
694 buf->WriteUInt8(family());
695 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
696 switch (xored_ip.family()) {
697 case AF_INET: {
698 in_addr v4addr = xored_ip.ipv4_address();
699 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
700 break;
701 }
702 case AF_INET6: {
703 in6_addr v6addr = xored_ip.ipv6_address();
704 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
705 break;
706 }
707 }
708 return true;
709}
710
Peter Boström0c4e06b2015-10-07 12:23:21 +0200711StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000712 : StunAttribute(type, SIZE), bits_(value) {
713}
714
Peter Boström0c4e06b2015-10-07 12:23:21 +0200715StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000716 : StunAttribute(type, SIZE), bits_(0) {
717}
718
Steve Antonca7d54e2017-10-25 14:42:51 -0700719StunAttributeValueType StunUInt32Attribute::value_type() const {
720 return STUN_VALUE_UINT32;
721}
722
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000723bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800724 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000725 return static_cast<bool>((bits_ >> index) & 0x1);
726}
727
728void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800729 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000730 bits_ &= ~(1 << index);
731 bits_ |= value ? (1 << index) : 0;
732}
733
jbauchf1f87202016-03-30 06:43:37 -0700734bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000735 if (length() != SIZE || !buf->ReadUInt32(&bits_))
736 return false;
737 return true;
738}
739
jbauchf1f87202016-03-30 06:43:37 -0700740bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000741 buf->WriteUInt32(bits_);
742 return true;
743}
744
Peter Boström0c4e06b2015-10-07 12:23:21 +0200745StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000746 : StunAttribute(type, SIZE), bits_(value) {
747}
748
Peter Boström0c4e06b2015-10-07 12:23:21 +0200749StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000750 : StunAttribute(type, SIZE), bits_(0) {
751}
752
Steve Antonca7d54e2017-10-25 14:42:51 -0700753StunAttributeValueType StunUInt64Attribute::value_type() const {
754 return STUN_VALUE_UINT64;
755}
756
jbauchf1f87202016-03-30 06:43:37 -0700757bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000758 if (length() != SIZE || !buf->ReadUInt64(&bits_))
759 return false;
760 return true;
761}
762
jbauchf1f87202016-03-30 06:43:37 -0700763bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000764 buf->WriteUInt64(bits_);
765 return true;
766}
767
Peter Boström0c4e06b2015-10-07 12:23:21 +0200768StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000769 : StunAttribute(type, 0), bytes_(NULL) {
770}
771
Peter Boström0c4e06b2015-10-07 12:23:21 +0200772StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000773 const std::string& str)
774 : StunAttribute(type, 0), bytes_(NULL) {
775 CopyBytes(str.c_str(), str.size());
776}
777
Peter Boström0c4e06b2015-10-07 12:23:21 +0200778StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000779 const void* bytes,
780 size_t length)
781 : StunAttribute(type, 0), bytes_(NULL) {
782 CopyBytes(bytes, length);
783}
784
Peter Boström0c4e06b2015-10-07 12:23:21 +0200785StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000786 : StunAttribute(type, length), bytes_(NULL) {
787}
788
789StunByteStringAttribute::~StunByteStringAttribute() {
790 delete [] bytes_;
791}
792
Steve Antonca7d54e2017-10-25 14:42:51 -0700793StunAttributeValueType StunByteStringAttribute::value_type() const {
794 return STUN_VALUE_BYTE_STRING;
795}
796
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000797void StunByteStringAttribute::CopyBytes(const char* bytes) {
798 CopyBytes(bytes, strlen(bytes));
799}
800
801void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
802 char* new_bytes = new char[length];
803 memcpy(new_bytes, bytes, length);
804 SetBytes(new_bytes, length);
805}
806
Peter Boström0c4e06b2015-10-07 12:23:21 +0200807uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800808 RTC_DCHECK(bytes_ != NULL);
809 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200810 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000811}
812
Peter Boström0c4e06b2015-10-07 12:23:21 +0200813void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800814 RTC_DCHECK(bytes_ != NULL);
815 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000816 bytes_[index] = value;
817}
818
jbauchf1f87202016-03-30 06:43:37 -0700819bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000820 bytes_ = new char[length()];
821 if (!buf->ReadBytes(bytes_, length())) {
822 return false;
823 }
824
825 ConsumePadding(buf);
826 return true;
827}
828
jbauchf1f87202016-03-30 06:43:37 -0700829bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000830 buf->WriteBytes(bytes_, length());
831 WritePadding(buf);
832 return true;
833}
834
835void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
836 delete [] bytes_;
837 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200838 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000839}
840
zsteinf42cc9d2017-03-27 16:17:19 -0700841const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
842
Peter Boström0c4e06b2015-10-07 12:23:21 +0200843StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
844 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000845 const std::string& reason)
846 : StunAttribute(type, 0) {
847 SetCode(code);
848 SetReason(reason);
849}
850
Peter Boström0c4e06b2015-10-07 12:23:21 +0200851StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000852 : StunAttribute(type, length), class_(0), number_(0) {
853}
854
855StunErrorCodeAttribute::~StunErrorCodeAttribute() {
856}
857
Steve Antonca7d54e2017-10-25 14:42:51 -0700858StunAttributeValueType StunErrorCodeAttribute::value_type() const {
859 return STUN_VALUE_ERROR_CODE;
860}
861
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000862int StunErrorCodeAttribute::code() const {
863 return class_ * 100 + number_;
864}
865
866void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200867 class_ = static_cast<uint8_t>(code / 100);
868 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000869}
870
871void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200872 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000873 reason_ = reason;
874}
875
jbauchf1f87202016-03-30 06:43:37 -0700876bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200877 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000878 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
879 return false;
880
881 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100882 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000883
884 class_ = ((val >> 8) & 0x7);
885 number_ = (val & 0xff);
886
887 if (!buf->ReadString(&reason_, length() - 4))
888 return false;
889
890 ConsumePadding(buf);
891 return true;
892}
893
jbauchf1f87202016-03-30 06:43:37 -0700894bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000895 buf->WriteUInt32(class_ << 8 | number_);
896 buf->WriteString(reason_);
897 WritePadding(buf);
898 return true;
899}
900
Peter Boström0c4e06b2015-10-07 12:23:21 +0200901StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000902 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200903 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000904}
905
906StunUInt16ListAttribute::~StunUInt16ListAttribute() {
907 delete attr_types_;
908}
909
Steve Antonca7d54e2017-10-25 14:42:51 -0700910StunAttributeValueType StunUInt16ListAttribute::value_type() const {
911 return STUN_VALUE_UINT16_LIST;
912}
913
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000914size_t StunUInt16ListAttribute::Size() const {
915 return attr_types_->size();
916}
917
Peter Boström0c4e06b2015-10-07 12:23:21 +0200918uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000919 return (*attr_types_)[index];
920}
921
Peter Boström0c4e06b2015-10-07 12:23:21 +0200922void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000923 (*attr_types_)[index] = value;
924}
925
Peter Boström0c4e06b2015-10-07 12:23:21 +0200926void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000927 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200928 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000929}
930
jbauchf1f87202016-03-30 06:43:37 -0700931bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000932 if (length() % 2)
933 return false;
934
935 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200936 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000937 if (!buf->ReadUInt16(&attr))
938 return false;
939 attr_types_->push_back(attr);
940 }
941 // Padding of these attributes is done in RFC 5389 style. This is
942 // slightly different from RFC3489, but it shouldn't be important.
943 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
944 // entries in the list (not necessarily the last one - it's unspecified).
945 // RFC5389 pads on the end, and the bytes are always ignored.
946 ConsumePadding(buf);
947 return true;
948}
949
jbauchf1f87202016-03-30 06:43:37 -0700950bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000951 for (size_t i = 0; i < attr_types_->size(); ++i) {
952 buf->WriteUInt16((*attr_types_)[i]);
953 }
954 WritePadding(buf);
955 return true;
956}
957
958int GetStunSuccessResponseType(int req_type) {
959 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
960}
961
962int GetStunErrorResponseType(int req_type) {
963 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
964}
965
966bool IsStunRequestType(int msg_type) {
967 return ((msg_type & kStunTypeMask) == 0x000);
968}
969
970bool IsStunIndicationType(int msg_type) {
971 return ((msg_type & kStunTypeMask) == 0x010);
972}
973
974bool IsStunSuccessResponseType(int msg_type) {
975 return ((msg_type & kStunTypeMask) == 0x100);
976}
977
978bool IsStunErrorResponseType(int msg_type) {
979 return ((msg_type & kStunTypeMask) == 0x110);
980}
981
982bool ComputeStunCredentialHash(const std::string& username,
983 const std::string& realm,
984 const std::string& password,
985 std::string* hash) {
986 // http://tools.ietf.org/html/rfc5389#section-15.4
987 // long-term credentials will be calculated using the key and key is
988 // key = MD5(username ":" realm ":" SASLprep(password))
989 std::string input = username;
990 input += ':';
991 input += realm;
992 input += ':';
993 input += password;
994
995 char digest[rtc::MessageDigest::kMaxSize];
996 size_t size = rtc::ComputeDigest(
997 rtc::DIGEST_MD5, input.c_str(), input.size(),
998 digest, sizeof(digest));
999 if (size == 0) {
1000 return false;
1001 }
1002
1003 *hash = std::string(digest, size);
1004 return true;
1005}
1006
Jonas Oreland202994c2017-12-18 12:10:43 +01001007std::unique_ptr<StunAttribute> CopyStunAttribute(
1008 const StunAttribute& attribute,
1009 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1010 ByteBufferWriter tmpBuffer;
1011 if (tmp_buffer_ptr == nullptr) {
1012 tmp_buffer_ptr = &tmpBuffer;
1013 }
1014
1015 std::unique_ptr<StunAttribute> copy(
1016 StunAttribute::Create(attribute.value_type(),
1017 attribute.type(),
1018 static_cast<uint16_t>(attribute.length()),
1019 nullptr));
1020
1021 if (!copy) {
1022 return nullptr;
1023 }
1024 tmp_buffer_ptr->Clear();
1025 if (!attribute.Write(tmp_buffer_ptr)) {
1026 return nullptr;
1027 }
1028 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1029 if (!copy->Read(&reader)) {
1030 return nullptr;
1031 }
1032
1033 return copy;
1034}
1035
Steve Antonca7d54e2017-10-25 14:42:51 -07001036StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1037 switch (type) {
1038 case STUN_ATTR_LIFETIME:
1039 return STUN_VALUE_UINT32;
1040 case STUN_ATTR_MAGIC_COOKIE:
1041 return STUN_VALUE_BYTE_STRING;
1042 case STUN_ATTR_BANDWIDTH:
1043 return STUN_VALUE_UINT32;
1044 case STUN_ATTR_DESTINATION_ADDRESS:
1045 return STUN_VALUE_ADDRESS;
1046 case STUN_ATTR_SOURCE_ADDRESS2:
1047 return STUN_VALUE_ADDRESS;
1048 case STUN_ATTR_DATA:
1049 return STUN_VALUE_BYTE_STRING;
1050 case STUN_ATTR_OPTIONS:
1051 return STUN_VALUE_UINT32;
1052 default:
1053 return StunMessage::GetAttributeValueType(type);
1054 }
1055}
1056
1057StunMessage* RelayMessage::CreateNew() const {
1058 return new RelayMessage();
1059}
1060
1061StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1062 switch (type) {
1063 case STUN_ATTR_CHANNEL_NUMBER:
1064 return STUN_VALUE_UINT32;
1065 case STUN_ATTR_TURN_LIFETIME:
1066 return STUN_VALUE_UINT32;
1067 case STUN_ATTR_XOR_PEER_ADDRESS:
1068 return STUN_VALUE_XOR_ADDRESS;
1069 case STUN_ATTR_DATA:
1070 return STUN_VALUE_BYTE_STRING;
1071 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1072 return STUN_VALUE_XOR_ADDRESS;
1073 case STUN_ATTR_EVEN_PORT:
1074 return STUN_VALUE_BYTE_STRING;
1075 case STUN_ATTR_REQUESTED_TRANSPORT:
1076 return STUN_VALUE_UINT32;
1077 case STUN_ATTR_DONT_FRAGMENT:
1078 return STUN_VALUE_BYTE_STRING;
1079 case STUN_ATTR_RESERVATION_TOKEN:
1080 return STUN_VALUE_BYTE_STRING;
1081 default:
1082 return StunMessage::GetAttributeValueType(type);
1083 }
1084}
1085
1086StunMessage* TurnMessage::CreateNew() const {
1087 return new TurnMessage();
1088}
1089
1090StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1091 switch (type) {
1092 case STUN_ATTR_PRIORITY:
1093 case STUN_ATTR_NETWORK_INFO:
1094 case STUN_ATTR_NOMINATION:
1095 return STUN_VALUE_UINT32;
1096 case STUN_ATTR_USE_CANDIDATE:
1097 return STUN_VALUE_BYTE_STRING;
1098 case STUN_ATTR_ICE_CONTROLLED:
1099 return STUN_VALUE_UINT64;
1100 case STUN_ATTR_ICE_CONTROLLING:
1101 return STUN_VALUE_UINT64;
1102 default:
1103 return StunMessage::GetAttributeValueType(type);
1104 }
1105}
1106
1107StunMessage* IceMessage::CreateNew() const {
1108 return new IceMessage();
1109}
1110
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001111} // namespace cricket