blob: 9d76b1c71104f4481818fdd98d2a7a6538adebc7 [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>
16
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/byteorder.h"
18#include "rtc_base/checks.h"
19#include "rtc_base/crc32.h"
20#include "rtc_base/logging.h"
21#include "rtc_base/messagedigest.h"
22#include "rtc_base/ptr_util.h"
23#include "rtc_base/stringencode.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024
jbauchf1f87202016-03-30 06:43:37 -070025using rtc::ByteBufferReader;
26using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000027
28namespace cricket {
29
30const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
31const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
32const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
33const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
34const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
35const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
36const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
37const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
38const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
39const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
40const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
41
42const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
43const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020044const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000045
46// StunMessage
47
48StunMessage::StunMessage()
49 : type_(0),
50 length_(0),
51 transaction_id_(EMPTY_TRANSACTION_ID) {
nisseede5da42017-01-12 05:15:36 -080052 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000053}
54
Steve Antonca7d54e2017-10-25 14:42:51 -070055StunMessage::~StunMessage() = default;
56
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000057bool StunMessage::IsLegacy() const {
58 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
59 return true;
nisseede5da42017-01-12 05:15:36 -080060 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000061 return false;
62}
63
64bool StunMessage::SetTransactionID(const std::string& str) {
65 if (!IsValidTransactionId(str)) {
66 return false;
67 }
68 transaction_id_ = str;
69 return true;
70}
71
Jonas Orelandbdcee282017-10-10 14:01:40 +020072static bool ImplementationDefinedRange(int attr_type)
73{
74 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
95const StunAddressAttribute* StunMessage::GetAddress(int type) const {
96 switch (type) {
97 case STUN_ATTR_MAPPED_ADDRESS: {
98 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
99 // missing.
100 const StunAttribute* mapped_address =
101 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
102 if (!mapped_address)
103 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
104 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
105 }
106
107 default:
108 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
109 }
110}
111
112const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
113 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
114}
115
116const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
117 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
118}
119
120const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
121 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
122}
123
124const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
125 return static_cast<const StunErrorCodeAttribute*>(
126 GetAttribute(STUN_ATTR_ERROR_CODE));
127}
128
deadbeef996fc6b2017-04-26 09:21:22 -0700129int StunMessage::GetErrorCodeValue() const {
130 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
131 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
132}
133
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000134const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
135 return static_cast<const StunUInt16ListAttribute*>(
136 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
137}
138
139// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
140// procedure outlined in RFC 5389, section 15.4.
141bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
142 const std::string& password) {
143 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700144 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000145 return false;
146 }
147
148 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200149 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000150 if (size != (msg_length + kStunHeaderSize)) {
151 return false;
152 }
153
154 // Finding Message Integrity attribute in stun message.
155 size_t current_pos = kStunHeaderSize;
156 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700157 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200158 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000159 // Getting attribute type and length.
160 attr_type = rtc::GetBE16(&data[current_pos]);
161 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
162
163 // If M-I, sanity check it, and break out.
164 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
165 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700166 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
167 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000168 return false;
169 }
170 has_message_integrity_attr = true;
171 break;
172 }
173
174 // Otherwise, skip to the next attribute.
175 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
176 if ((attr_length % 4) != 0) {
177 current_pos += (4 - (attr_length % 4));
178 }
179 }
180
181 if (!has_message_integrity_attr) {
182 return false;
183 }
184
185 // Getting length of the message to calculate Message Integrity.
186 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700187 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000188 memcpy(temp_data.get(), data, current_pos);
189 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
190 // Stun message has other attributes after message integrity.
191 // Adjust the length parameter in stun message to calculate HMAC.
192 size_t extra_offset = size -
193 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
194 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
195
196 // Writing new length of the STUN message @ Message Length in temp buffer.
197 // 0 1 2 3
198 // 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
199 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
200 // |0 0| STUN Message Type | Message Length |
201 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200202 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000203 }
204
205 char hmac[kStunMessageIntegritySize];
206 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
207 password.c_str(), password.size(),
208 temp_data.get(), mi_pos,
209 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800210 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000211 if (ret != sizeof(hmac))
212 return false;
213
214 // Comparing the calculated HMAC with the one present in the message.
215 return memcmp(data + current_pos + kStunAttributeHeaderSize,
216 hmac,
217 sizeof(hmac)) == 0;
218}
219
220bool StunMessage::AddMessageIntegrity(const std::string& password) {
221 return AddMessageIntegrity(password.c_str(), password.size());
222}
223
224bool StunMessage::AddMessageIntegrity(const char* key,
225 size_t keylen) {
226 // Add the attribute with a dummy value. Since this is a known attribute, it
227 // can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700228 auto msg_integrity_attr_ptr = rtc::MakeUnique<StunByteStringAttribute>(
229 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
230 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
231 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000232
233 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700234 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000235 if (!Write(&buf))
236 return false;
237
238 int msg_len_for_hmac = static_cast<int>(
239 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
240 char hmac[kStunMessageIntegritySize];
241 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
242 key, keylen,
243 buf.Data(), msg_len_for_hmac,
244 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800245 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000246 if (ret != sizeof(hmac)) {
247 LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
248 << "has dummy value.";
249 return false;
250 }
251
252 // Insert correct HMAC into the attribute.
253 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
254 return true;
255}
256
257// Verifies a message is in fact a STUN message, by performing the checks
258// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
259// in section 15.5.
260bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
261 // Check the message length.
262 size_t fingerprint_attr_size =
263 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
264 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
265 return false;
266
267 // Skip the rest if the magic cookie isn't present.
268 const char* magic_cookie =
269 data + kStunTransactionIdOffset - kStunMagicCookieLength;
270 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
271 return false;
272
273 // Check the fingerprint type and length.
274 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
275 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200276 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000277 StunUInt32Attribute::SIZE)
278 return false;
279
280 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200281 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000282 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
283 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
284 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
285}
286
287bool StunMessage::AddFingerprint() {
288 // Add the attribute with a dummy value. Since this is a known attribute,
289 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700290 auto fingerprint_attr_ptr =
291 rtc::MakeUnique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700292 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700293 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000294
295 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700296 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000297 if (!Write(&buf))
298 return false;
299
300 int msg_len_for_crc32 = static_cast<int>(
301 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200302 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000303
304 // Insert the correct CRC-32, XORed with a constant, into the attribute.
305 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
306 return true;
307}
308
jbauchf1f87202016-03-30 06:43:37 -0700309bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000310 if (!buf->ReadUInt16(&type_))
311 return false;
312
313 if (type_ & 0x8000) {
314 // RTP and RTCP set the MSB of first byte, since first two bits are version,
315 // and version is always 2 (10). If set, this is not a STUN packet.
316 return false;
317 }
318
319 if (!buf->ReadUInt16(&length_))
320 return false;
321
322 std::string magic_cookie;
323 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
324 return false;
325
326 std::string transaction_id;
327 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
328 return false;
329
Peter Boström0c4e06b2015-10-07 12:23:21 +0200330 uint32_t magic_cookie_int =
331 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000332 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
333 // If magic cookie is invalid it means that the peer implements
334 // RFC3489 instead of RFC5389.
335 transaction_id.insert(0, magic_cookie);
336 }
nisseede5da42017-01-12 05:15:36 -0800337 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000338 transaction_id_ = transaction_id;
339
340 if (length_ != buf->Length())
341 return false;
342
zsteinad94c4c2017-03-06 13:36:05 -0800343 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000344
345 size_t rest = buf->Length() - length_;
346 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200347 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000348 if (!buf->ReadUInt16(&attr_type))
349 return false;
350 if (!buf->ReadUInt16(&attr_length))
351 return false;
352
Honghai Zhang3e024302016-09-22 09:52:16 -0700353 std::unique_ptr<StunAttribute> attr(
354 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000355 if (!attr) {
356 // Skip any unknown or malformed attributes.
357 if ((attr_length % 4) != 0) {
358 attr_length += (4 - (attr_length % 4));
359 }
360 if (!buf->Consume(attr_length))
361 return false;
362 } else {
363 if (!attr->Read(buf))
364 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800365 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000366 }
367 }
368
nisseede5da42017-01-12 05:15:36 -0800369 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000370 return true;
371}
372
jbauchf1f87202016-03-30 06:43:37 -0700373bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000374 buf->WriteUInt16(type_);
375 buf->WriteUInt16(length_);
376 if (!IsLegacy())
377 buf->WriteUInt32(kStunMagicCookie);
378 buf->WriteString(transaction_id_);
379
zsteinad94c4c2017-03-06 13:36:05 -0800380 for (const auto& attr : attrs_) {
381 buf->WriteUInt16(attr->type());
382 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
383 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000384 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800385 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000386 }
387
388 return true;
389}
390
Steve Antonca7d54e2017-10-25 14:42:51 -0700391StunMessage* StunMessage::CreateNew() const {
392 return new StunMessage();
393}
394
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000395StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
396 switch (type) {
397 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
398 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
399 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
400 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
401 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
402 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
403 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
404 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
405 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
406 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS;
407 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000408 case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000409 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
410 default: return STUN_VALUE_UNKNOWN;
411 }
412}
413
414StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
415 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200416 if (value_type != STUN_VALUE_UNKNOWN) {
417 return StunAttribute::Create(value_type, type,
418 static_cast<uint16_t>(length), this);
419 } else if (ImplementationDefinedRange(type)) {
420 // Read unknown attributes as STUN_VALUE_BYTE_STRING
421 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
422 static_cast<uint16_t>(length), this);
423 } else {
424 return NULL;
425 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000426}
427
428const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800429 for (const auto& attr : attrs_) {
430 if (attr->type() == type) {
431 return attr.get();
432 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000433 }
434 return NULL;
435}
436
437bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
438 return transaction_id.size() == kStunTransactionIdLength ||
439 transaction_id.size() == kStunLegacyTransactionIdLength;
440}
441
442// StunAttribute
443
Peter Boström0c4e06b2015-10-07 12:23:21 +0200444StunAttribute::StunAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000445 : type_(type), length_(length) {
446}
447
jbauchf1f87202016-03-30 06:43:37 -0700448void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000449 int remainder = length_ % 4;
450 if (remainder > 0) {
451 buf->Consume(4 - remainder);
452 }
453}
454
jbauchf1f87202016-03-30 06:43:37 -0700455void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000456 int remainder = length_ % 4;
457 if (remainder > 0) {
458 char zeroes[4] = {0};
459 buf->WriteBytes(zeroes, 4 - remainder);
460 }
461}
462
463StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200464 uint16_t type,
465 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000466 StunMessage* owner) {
467 switch (value_type) {
468 case STUN_VALUE_ADDRESS:
469 return new StunAddressAttribute(type, length);
470 case STUN_VALUE_XOR_ADDRESS:
471 return new StunXorAddressAttribute(type, length, owner);
472 case STUN_VALUE_UINT32:
473 return new StunUInt32Attribute(type);
474 case STUN_VALUE_UINT64:
475 return new StunUInt64Attribute(type);
476 case STUN_VALUE_BYTE_STRING:
477 return new StunByteStringAttribute(type, length);
478 case STUN_VALUE_ERROR_CODE:
479 return new StunErrorCodeAttribute(type, length);
480 case STUN_VALUE_UINT16_LIST:
481 return new StunUInt16ListAttribute(type, length);
482 default:
483 return NULL;
484 }
485}
486
zsteinf42cc9d2017-03-27 16:17:19 -0700487std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
488 uint16_t type) {
489 return rtc::MakeUnique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000490}
491
zsteinf42cc9d2017-03-27 16:17:19 -0700492std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
493 uint16_t type) {
494 return rtc::MakeUnique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000495}
496
zsteinf42cc9d2017-03-27 16:17:19 -0700497std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
498 uint16_t type) {
499 return rtc::MakeUnique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000500}
501
zsteinf42cc9d2017-03-27 16:17:19 -0700502std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
503 uint16_t type) {
504 return rtc::MakeUnique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000505}
506
zsteinf42cc9d2017-03-27 16:17:19 -0700507std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
508 uint16_t type) {
509 return rtc::MakeUnique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000510}
511
zsteinf42cc9d2017-03-27 16:17:19 -0700512std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
513 return rtc::MakeUnique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000514 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
515}
516
zsteinf42cc9d2017-03-27 16:17:19 -0700517std::unique_ptr<StunUInt16ListAttribute>
518StunAttribute::CreateUnknownAttributes() {
519 return rtc::MakeUnique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
520 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000521}
522
Peter Boström0c4e06b2015-10-07 12:23:21 +0200523StunAddressAttribute::StunAddressAttribute(uint16_t type,
524 const rtc::SocketAddress& addr)
525 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000526 SetAddress(addr);
527}
528
Peter Boström0c4e06b2015-10-07 12:23:21 +0200529StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000530 : StunAttribute(type, length) {
531}
532
Steve Antonca7d54e2017-10-25 14:42:51 -0700533StunAttributeValueType StunAddressAttribute::value_type() const {
534 return STUN_VALUE_ADDRESS;
535}
536
jbauchf1f87202016-03-30 06:43:37 -0700537bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200538 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000539 if (!buf->ReadUInt8(&dummy))
540 return false;
541
Peter Boström0c4e06b2015-10-07 12:23:21 +0200542 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000543 if (!buf->ReadUInt8(&stun_family)) {
544 return false;
545 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200546 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000547 if (!buf->ReadUInt16(&port))
548 return false;
549 if (stun_family == STUN_ADDRESS_IPV4) {
550 in_addr v4addr;
551 if (length() != SIZE_IP4) {
552 return false;
553 }
554 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
555 return false;
556 }
557 rtc::IPAddress ipaddr(v4addr);
558 SetAddress(rtc::SocketAddress(ipaddr, port));
559 } else if (stun_family == STUN_ADDRESS_IPV6) {
560 in6_addr v6addr;
561 if (length() != SIZE_IP6) {
562 return false;
563 }
564 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
565 return false;
566 }
567 rtc::IPAddress ipaddr(v6addr);
568 SetAddress(rtc::SocketAddress(ipaddr, port));
569 } else {
570 return false;
571 }
572 return true;
573}
574
jbauchf1f87202016-03-30 06:43:37 -0700575bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000576 StunAddressFamily address_family = family();
577 if (address_family == STUN_ADDRESS_UNDEF) {
578 LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
579 return false;
580 }
581 buf->WriteUInt8(0);
582 buf->WriteUInt8(address_family);
583 buf->WriteUInt16(address_.port());
584 switch (address_.family()) {
585 case AF_INET: {
586 in_addr v4addr = address_.ipaddr().ipv4_address();
587 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
588 break;
589 }
590 case AF_INET6: {
591 in6_addr v6addr = address_.ipaddr().ipv6_address();
592 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
593 break;
594 }
595 }
596 return true;
597}
598
Peter Boström0c4e06b2015-10-07 12:23:21 +0200599StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
600 const rtc::SocketAddress& addr)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000601 : StunAddressAttribute(type, addr), owner_(NULL) {
602}
603
Peter Boström0c4e06b2015-10-07 12:23:21 +0200604StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
605 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000606 StunMessage* owner)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200607 : StunAddressAttribute(type, length), owner_(owner) {
608}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000609
Steve Antonca7d54e2017-10-25 14:42:51 -0700610StunAttributeValueType StunXorAddressAttribute::value_type() const {
611 return STUN_VALUE_XOR_ADDRESS;
612}
613
614void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
615 owner_ = owner;
616}
617
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000618rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
619 if (owner_) {
620 rtc::IPAddress ip = ipaddr();
621 switch (ip.family()) {
622 case AF_INET: {
623 in_addr v4addr = ip.ipv4_address();
624 v4addr.s_addr =
625 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
626 return rtc::IPAddress(v4addr);
627 }
628 case AF_INET6: {
629 in6_addr v6addr = ip.ipv6_address();
630 const std::string& transaction_id = owner_->transaction_id();
631 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200632 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000633 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
634 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200635 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000636 // Transaction ID is in network byte order, but magic cookie
637 // is stored in host byte order.
638 ip_as_ints[0] =
639 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
640 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
641 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
642 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
643 return rtc::IPAddress(v6addr);
644 }
645 break;
646 }
647 }
648 }
649 // Invalid ip family or transaction ID, or missing owner.
650 // Return an AF_UNSPEC address.
651 return rtc::IPAddress();
652}
653
jbauchf1f87202016-03-30 06:43:37 -0700654bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000655 if (!StunAddressAttribute::Read(buf))
656 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200657 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000658 rtc::IPAddress xored_ip = GetXoredIP();
659 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
660 return true;
661}
662
jbauchf1f87202016-03-30 06:43:37 -0700663bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000664 StunAddressFamily address_family = family();
665 if (address_family == STUN_ADDRESS_UNDEF) {
666 LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
667 return false;
668 }
669 rtc::IPAddress xored_ip = GetXoredIP();
670 if (xored_ip.family() == AF_UNSPEC) {
671 return false;
672 }
673 buf->WriteUInt8(0);
674 buf->WriteUInt8(family());
675 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
676 switch (xored_ip.family()) {
677 case AF_INET: {
678 in_addr v4addr = xored_ip.ipv4_address();
679 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
680 break;
681 }
682 case AF_INET6: {
683 in6_addr v6addr = xored_ip.ipv6_address();
684 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
685 break;
686 }
687 }
688 return true;
689}
690
Peter Boström0c4e06b2015-10-07 12:23:21 +0200691StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000692 : StunAttribute(type, SIZE), bits_(value) {
693}
694
Peter Boström0c4e06b2015-10-07 12:23:21 +0200695StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000696 : StunAttribute(type, SIZE), bits_(0) {
697}
698
Steve Antonca7d54e2017-10-25 14:42:51 -0700699StunAttributeValueType StunUInt32Attribute::value_type() const {
700 return STUN_VALUE_UINT32;
701}
702
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000703bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800704 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000705 return static_cast<bool>((bits_ >> index) & 0x1);
706}
707
708void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800709 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000710 bits_ &= ~(1 << index);
711 bits_ |= value ? (1 << index) : 0;
712}
713
jbauchf1f87202016-03-30 06:43:37 -0700714bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000715 if (length() != SIZE || !buf->ReadUInt32(&bits_))
716 return false;
717 return true;
718}
719
jbauchf1f87202016-03-30 06:43:37 -0700720bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000721 buf->WriteUInt32(bits_);
722 return true;
723}
724
Peter Boström0c4e06b2015-10-07 12:23:21 +0200725StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000726 : StunAttribute(type, SIZE), bits_(value) {
727}
728
Peter Boström0c4e06b2015-10-07 12:23:21 +0200729StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000730 : StunAttribute(type, SIZE), bits_(0) {
731}
732
Steve Antonca7d54e2017-10-25 14:42:51 -0700733StunAttributeValueType StunUInt64Attribute::value_type() const {
734 return STUN_VALUE_UINT64;
735}
736
jbauchf1f87202016-03-30 06:43:37 -0700737bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000738 if (length() != SIZE || !buf->ReadUInt64(&bits_))
739 return false;
740 return true;
741}
742
jbauchf1f87202016-03-30 06:43:37 -0700743bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000744 buf->WriteUInt64(bits_);
745 return true;
746}
747
Peter Boström0c4e06b2015-10-07 12:23:21 +0200748StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000749 : StunAttribute(type, 0), bytes_(NULL) {
750}
751
Peter Boström0c4e06b2015-10-07 12:23:21 +0200752StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000753 const std::string& str)
754 : StunAttribute(type, 0), bytes_(NULL) {
755 CopyBytes(str.c_str(), str.size());
756}
757
Peter Boström0c4e06b2015-10-07 12:23:21 +0200758StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000759 const void* bytes,
760 size_t length)
761 : StunAttribute(type, 0), bytes_(NULL) {
762 CopyBytes(bytes, length);
763}
764
Peter Boström0c4e06b2015-10-07 12:23:21 +0200765StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000766 : StunAttribute(type, length), bytes_(NULL) {
767}
768
769StunByteStringAttribute::~StunByteStringAttribute() {
770 delete [] bytes_;
771}
772
Steve Antonca7d54e2017-10-25 14:42:51 -0700773StunAttributeValueType StunByteStringAttribute::value_type() const {
774 return STUN_VALUE_BYTE_STRING;
775}
776
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000777void StunByteStringAttribute::CopyBytes(const char* bytes) {
778 CopyBytes(bytes, strlen(bytes));
779}
780
781void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
782 char* new_bytes = new char[length];
783 memcpy(new_bytes, bytes, length);
784 SetBytes(new_bytes, length);
785}
786
Peter Boström0c4e06b2015-10-07 12:23:21 +0200787uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800788 RTC_DCHECK(bytes_ != NULL);
789 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200790 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000791}
792
Peter Boström0c4e06b2015-10-07 12:23:21 +0200793void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800794 RTC_DCHECK(bytes_ != NULL);
795 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000796 bytes_[index] = value;
797}
798
jbauchf1f87202016-03-30 06:43:37 -0700799bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000800 bytes_ = new char[length()];
801 if (!buf->ReadBytes(bytes_, length())) {
802 return false;
803 }
804
805 ConsumePadding(buf);
806 return true;
807}
808
jbauchf1f87202016-03-30 06:43:37 -0700809bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000810 buf->WriteBytes(bytes_, length());
811 WritePadding(buf);
812 return true;
813}
814
815void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
816 delete [] bytes_;
817 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200818 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000819}
820
zsteinf42cc9d2017-03-27 16:17:19 -0700821const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
822
Peter Boström0c4e06b2015-10-07 12:23:21 +0200823StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
824 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000825 const std::string& reason)
826 : StunAttribute(type, 0) {
827 SetCode(code);
828 SetReason(reason);
829}
830
Peter Boström0c4e06b2015-10-07 12:23:21 +0200831StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000832 : StunAttribute(type, length), class_(0), number_(0) {
833}
834
835StunErrorCodeAttribute::~StunErrorCodeAttribute() {
836}
837
Steve Antonca7d54e2017-10-25 14:42:51 -0700838StunAttributeValueType StunErrorCodeAttribute::value_type() const {
839 return STUN_VALUE_ERROR_CODE;
840}
841
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000842int StunErrorCodeAttribute::code() const {
843 return class_ * 100 + number_;
844}
845
846void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200847 class_ = static_cast<uint8_t>(code / 100);
848 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000849}
850
851void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200852 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000853 reason_ = reason;
854}
855
jbauchf1f87202016-03-30 06:43:37 -0700856bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200857 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000858 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
859 return false;
860
861 if ((val >> 11) != 0)
862 LOG(LS_ERROR) << "error-code bits not zero";
863
864 class_ = ((val >> 8) & 0x7);
865 number_ = (val & 0xff);
866
867 if (!buf->ReadString(&reason_, length() - 4))
868 return false;
869
870 ConsumePadding(buf);
871 return true;
872}
873
jbauchf1f87202016-03-30 06:43:37 -0700874bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000875 buf->WriteUInt32(class_ << 8 | number_);
876 buf->WriteString(reason_);
877 WritePadding(buf);
878 return true;
879}
880
Peter Boström0c4e06b2015-10-07 12:23:21 +0200881StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000882 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200883 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000884}
885
886StunUInt16ListAttribute::~StunUInt16ListAttribute() {
887 delete attr_types_;
888}
889
Steve Antonca7d54e2017-10-25 14:42:51 -0700890StunAttributeValueType StunUInt16ListAttribute::value_type() const {
891 return STUN_VALUE_UINT16_LIST;
892}
893
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000894size_t StunUInt16ListAttribute::Size() const {
895 return attr_types_->size();
896}
897
Peter Boström0c4e06b2015-10-07 12:23:21 +0200898uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000899 return (*attr_types_)[index];
900}
901
Peter Boström0c4e06b2015-10-07 12:23:21 +0200902void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000903 (*attr_types_)[index] = value;
904}
905
Peter Boström0c4e06b2015-10-07 12:23:21 +0200906void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000907 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200908 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000909}
910
jbauchf1f87202016-03-30 06:43:37 -0700911bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000912 if (length() % 2)
913 return false;
914
915 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200916 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000917 if (!buf->ReadUInt16(&attr))
918 return false;
919 attr_types_->push_back(attr);
920 }
921 // Padding of these attributes is done in RFC 5389 style. This is
922 // slightly different from RFC3489, but it shouldn't be important.
923 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
924 // entries in the list (not necessarily the last one - it's unspecified).
925 // RFC5389 pads on the end, and the bytes are always ignored.
926 ConsumePadding(buf);
927 return true;
928}
929
jbauchf1f87202016-03-30 06:43:37 -0700930bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000931 for (size_t i = 0; i < attr_types_->size(); ++i) {
932 buf->WriteUInt16((*attr_types_)[i]);
933 }
934 WritePadding(buf);
935 return true;
936}
937
938int GetStunSuccessResponseType(int req_type) {
939 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
940}
941
942int GetStunErrorResponseType(int req_type) {
943 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
944}
945
946bool IsStunRequestType(int msg_type) {
947 return ((msg_type & kStunTypeMask) == 0x000);
948}
949
950bool IsStunIndicationType(int msg_type) {
951 return ((msg_type & kStunTypeMask) == 0x010);
952}
953
954bool IsStunSuccessResponseType(int msg_type) {
955 return ((msg_type & kStunTypeMask) == 0x100);
956}
957
958bool IsStunErrorResponseType(int msg_type) {
959 return ((msg_type & kStunTypeMask) == 0x110);
960}
961
962bool ComputeStunCredentialHash(const std::string& username,
963 const std::string& realm,
964 const std::string& password,
965 std::string* hash) {
966 // http://tools.ietf.org/html/rfc5389#section-15.4
967 // long-term credentials will be calculated using the key and key is
968 // key = MD5(username ":" realm ":" SASLprep(password))
969 std::string input = username;
970 input += ':';
971 input += realm;
972 input += ':';
973 input += password;
974
975 char digest[rtc::MessageDigest::kMaxSize];
976 size_t size = rtc::ComputeDigest(
977 rtc::DIGEST_MD5, input.c_str(), input.size(),
978 digest, sizeof(digest));
979 if (size == 0) {
980 return false;
981 }
982
983 *hash = std::string(digest, size);
984 return true;
985}
986
Steve Antonca7d54e2017-10-25 14:42:51 -0700987StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
988 switch (type) {
989 case STUN_ATTR_LIFETIME:
990 return STUN_VALUE_UINT32;
991 case STUN_ATTR_MAGIC_COOKIE:
992 return STUN_VALUE_BYTE_STRING;
993 case STUN_ATTR_BANDWIDTH:
994 return STUN_VALUE_UINT32;
995 case STUN_ATTR_DESTINATION_ADDRESS:
996 return STUN_VALUE_ADDRESS;
997 case STUN_ATTR_SOURCE_ADDRESS2:
998 return STUN_VALUE_ADDRESS;
999 case STUN_ATTR_DATA:
1000 return STUN_VALUE_BYTE_STRING;
1001 case STUN_ATTR_OPTIONS:
1002 return STUN_VALUE_UINT32;
1003 default:
1004 return StunMessage::GetAttributeValueType(type);
1005 }
1006}
1007
1008StunMessage* RelayMessage::CreateNew() const {
1009 return new RelayMessage();
1010}
1011
1012StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1013 switch (type) {
1014 case STUN_ATTR_CHANNEL_NUMBER:
1015 return STUN_VALUE_UINT32;
1016 case STUN_ATTR_TURN_LIFETIME:
1017 return STUN_VALUE_UINT32;
1018 case STUN_ATTR_XOR_PEER_ADDRESS:
1019 return STUN_VALUE_XOR_ADDRESS;
1020 case STUN_ATTR_DATA:
1021 return STUN_VALUE_BYTE_STRING;
1022 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1023 return STUN_VALUE_XOR_ADDRESS;
1024 case STUN_ATTR_EVEN_PORT:
1025 return STUN_VALUE_BYTE_STRING;
1026 case STUN_ATTR_REQUESTED_TRANSPORT:
1027 return STUN_VALUE_UINT32;
1028 case STUN_ATTR_DONT_FRAGMENT:
1029 return STUN_VALUE_BYTE_STRING;
1030 case STUN_ATTR_RESERVATION_TOKEN:
1031 return STUN_VALUE_BYTE_STRING;
1032 default:
1033 return StunMessage::GetAttributeValueType(type);
1034 }
1035}
1036
1037StunMessage* TurnMessage::CreateNew() const {
1038 return new TurnMessage();
1039}
1040
1041StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1042 switch (type) {
1043 case STUN_ATTR_PRIORITY:
1044 case STUN_ATTR_NETWORK_INFO:
1045 case STUN_ATTR_NOMINATION:
1046 return STUN_VALUE_UINT32;
1047 case STUN_ATTR_USE_CANDIDATE:
1048 return STUN_VALUE_BYTE_STRING;
1049 case STUN_ATTR_ICE_CONTROLLED:
1050 return STUN_VALUE_UINT64;
1051 case STUN_ATTR_ICE_CONTROLLING:
1052 return STUN_VALUE_UINT64;
1053 default:
1054 return StunMessage::GetAttributeValueType(type);
1055 }
1056}
1057
1058StunMessage* IceMessage::CreateNew() const {
1059 return new IceMessage();
1060}
1061
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001062} // namespace cricket