blob: a5aa46f7cb6f5f9e315cad4c7d9849fb420de4ac [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),
Jonas Oreland7ca63112018-02-27 08:45:13 +010052 transaction_id_(EMPTY_TRANSACTION_ID),
53 stun_magic_cookie_(kStunMagicCookie) {
nisseede5da42017-01-12 05:15:36 -080054 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000055}
56
Steve Antonca7d54e2017-10-25 14:42:51 -070057StunMessage::~StunMessage() = default;
58
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059bool StunMessage::IsLegacy() const {
60 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
61 return true;
nisseede5da42017-01-12 05:15:36 -080062 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000063 return false;
64}
65
66bool StunMessage::SetTransactionID(const std::string& str) {
67 if (!IsValidTransactionId(str)) {
68 return false;
69 }
70 transaction_id_ = str;
71 return true;
72}
73
Steve Anton6c38cc72017-11-29 10:25:58 -080074static bool ImplementationDefinedRange(int attr_type) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020075 return attr_type >= 0xC000 && attr_type <= 0xFFFF;
76}
77
zsteinf42cc9d2017-03-27 16:17:19 -070078void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020079 // Fail any attributes that aren't valid for this type of message,
80 // but allow any type for the range that is "implementation defined"
81 // in the RFC.
82 if (!ImplementationDefinedRange(attr->type())) {
83 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
84 }
nissecc99bc22017-02-02 01:31:30 -080085
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000086 attr->SetOwner(this);
87 size_t attr_length = attr->length();
88 if (attr_length % 4 != 0) {
89 attr_length += (4 - (attr_length % 4));
90 }
Peter Boström0c4e06b2015-10-07 12:23:21 +020091 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -070092
93 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000094}
95
Jonas Oreland202994c2017-12-18 12:10:43 +010096std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
97 std::unique_ptr<StunAttribute> attribute;
98 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
99 if ((* it)->type() == type) {
100 attribute = std::move(* it);
101 attrs_.erase(std::next(it).base());
102 break;
103 }
104 }
105 if (attribute) {
106 attribute->SetOwner(nullptr);
107 size_t attr_length = attribute->length();
108 if (attr_length % 4 != 0) {
109 attr_length += (4 - (attr_length % 4));
110 }
111 length_ -= static_cast<uint16_t>(attr_length + 4);
112 }
113 return attribute;
114}
115
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000116const StunAddressAttribute* StunMessage::GetAddress(int type) const {
117 switch (type) {
118 case STUN_ATTR_MAPPED_ADDRESS: {
119 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
120 // missing.
121 const StunAttribute* mapped_address =
122 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
123 if (!mapped_address)
124 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
125 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
126 }
127
128 default:
129 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
130 }
131}
132
133const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
134 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
135}
136
137const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
138 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
139}
140
141const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
142 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
143}
144
145const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
146 return static_cast<const StunErrorCodeAttribute*>(
147 GetAttribute(STUN_ATTR_ERROR_CODE));
148}
149
deadbeef996fc6b2017-04-26 09:21:22 -0700150int StunMessage::GetErrorCodeValue() const {
151 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
152 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
153}
154
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000155const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
156 return static_cast<const StunUInt16ListAttribute*>(
157 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
158}
159
160// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
161// procedure outlined in RFC 5389, section 15.4.
162bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
163 const std::string& password) {
164 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700165 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 return false;
167 }
168
169 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200170 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000171 if (size != (msg_length + kStunHeaderSize)) {
172 return false;
173 }
174
175 // Finding Message Integrity attribute in stun message.
176 size_t current_pos = kStunHeaderSize;
177 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700178 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200179 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000180 // Getting attribute type and length.
181 attr_type = rtc::GetBE16(&data[current_pos]);
182 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
183
184 // If M-I, sanity check it, and break out.
185 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
186 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700187 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
188 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000189 return false;
190 }
191 has_message_integrity_attr = true;
192 break;
193 }
194
195 // Otherwise, skip to the next attribute.
196 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
197 if ((attr_length % 4) != 0) {
198 current_pos += (4 - (attr_length % 4));
199 }
200 }
201
202 if (!has_message_integrity_attr) {
203 return false;
204 }
205
206 // Getting length of the message to calculate Message Integrity.
207 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700208 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000209 memcpy(temp_data.get(), data, current_pos);
210 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
211 // Stun message has other attributes after message integrity.
212 // Adjust the length parameter in stun message to calculate HMAC.
213 size_t extra_offset = size -
214 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
215 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
216
217 // Writing new length of the STUN message @ Message Length in temp buffer.
218 // 0 1 2 3
219 // 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
220 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
221 // |0 0| STUN Message Type | Message Length |
222 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200223 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000224 }
225
226 char hmac[kStunMessageIntegritySize];
227 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
228 password.c_str(), password.size(),
229 temp_data.get(), mi_pos,
230 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800231 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000232 if (ret != sizeof(hmac))
233 return false;
234
235 // Comparing the calculated HMAC with the one present in the message.
236 return memcmp(data + current_pos + kStunAttributeHeaderSize,
237 hmac,
238 sizeof(hmac)) == 0;
239}
240
241bool StunMessage::AddMessageIntegrity(const std::string& password) {
242 return AddMessageIntegrity(password.c_str(), password.size());
243}
244
245bool StunMessage::AddMessageIntegrity(const char* key,
246 size_t keylen) {
247 // Add the attribute with a dummy value. Since this is a known attribute, it
248 // can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700249 auto msg_integrity_attr_ptr = rtc::MakeUnique<StunByteStringAttribute>(
250 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
251 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
252 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000253
254 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700255 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000256 if (!Write(&buf))
257 return false;
258
259 int msg_len_for_hmac = static_cast<int>(
260 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
261 char hmac[kStunMessageIntegritySize];
262 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
263 key, keylen,
264 buf.Data(), msg_len_for_hmac,
265 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800266 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000267 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100268 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
269 << "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000270 return false;
271 }
272
273 // Insert correct HMAC into the attribute.
274 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
275 return true;
276}
277
278// Verifies a message is in fact a STUN message, by performing the checks
279// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
280// in section 15.5.
281bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
282 // Check the message length.
283 size_t fingerprint_attr_size =
284 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
285 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
286 return false;
287
288 // Skip the rest if the magic cookie isn't present.
289 const char* magic_cookie =
290 data + kStunTransactionIdOffset - kStunMagicCookieLength;
291 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
292 return false;
293
294 // Check the fingerprint type and length.
295 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
296 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200297 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000298 StunUInt32Attribute::SIZE)
299 return false;
300
301 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200302 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000303 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
304 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
305 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
306}
307
308bool StunMessage::AddFingerprint() {
309 // Add the attribute with a dummy value. Since this is a known attribute,
310 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700311 auto fingerprint_attr_ptr =
312 rtc::MakeUnique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700313 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700314 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000315
316 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700317 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000318 if (!Write(&buf))
319 return false;
320
321 int msg_len_for_crc32 = static_cast<int>(
322 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200323 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000324
325 // Insert the correct CRC-32, XORed with a constant, into the attribute.
326 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
327 return true;
328}
329
jbauchf1f87202016-03-30 06:43:37 -0700330bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000331 if (!buf->ReadUInt16(&type_))
332 return false;
333
334 if (type_ & 0x8000) {
335 // RTP and RTCP set the MSB of first byte, since first two bits are version,
336 // and version is always 2 (10). If set, this is not a STUN packet.
337 return false;
338 }
339
340 if (!buf->ReadUInt16(&length_))
341 return false;
342
343 std::string magic_cookie;
344 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
345 return false;
346
347 std::string transaction_id;
348 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
349 return false;
350
Peter Boström0c4e06b2015-10-07 12:23:21 +0200351 uint32_t magic_cookie_int =
352 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000353 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
354 // If magic cookie is invalid it means that the peer implements
355 // RFC3489 instead of RFC5389.
356 transaction_id.insert(0, magic_cookie);
357 }
nisseede5da42017-01-12 05:15:36 -0800358 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000359 transaction_id_ = transaction_id;
360
361 if (length_ != buf->Length())
362 return false;
363
zsteinad94c4c2017-03-06 13:36:05 -0800364 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000365
366 size_t rest = buf->Length() - length_;
367 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200368 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000369 if (!buf->ReadUInt16(&attr_type))
370 return false;
371 if (!buf->ReadUInt16(&attr_length))
372 return false;
373
Honghai Zhang3e024302016-09-22 09:52:16 -0700374 std::unique_ptr<StunAttribute> attr(
375 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000376 if (!attr) {
377 // Skip any unknown or malformed attributes.
378 if ((attr_length % 4) != 0) {
379 attr_length += (4 - (attr_length % 4));
380 }
381 if (!buf->Consume(attr_length))
382 return false;
383 } else {
384 if (!attr->Read(buf))
385 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800386 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000387 }
388 }
389
nisseede5da42017-01-12 05:15:36 -0800390 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000391 return true;
392}
393
jbauchf1f87202016-03-30 06:43:37 -0700394bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000395 buf->WriteUInt16(type_);
396 buf->WriteUInt16(length_);
397 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100398 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000399 buf->WriteString(transaction_id_);
400
zsteinad94c4c2017-03-06 13:36:05 -0800401 for (const auto& attr : attrs_) {
402 buf->WriteUInt16(attr->type());
403 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
404 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000405 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800406 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000407 }
408
409 return true;
410}
411
Steve Antonca7d54e2017-10-25 14:42:51 -0700412StunMessage* StunMessage::CreateNew() const {
413 return new StunMessage();
414}
415
Jonas Oreland7ca63112018-02-27 08:45:13 +0100416void StunMessage::SetStunMagicCookie(uint32_t val) {
417 stun_magic_cookie_ = val;
418}
419
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000420StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
421 switch (type) {
422 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
423 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
424 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
425 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
426 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
427 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
428 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
429 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
430 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
431 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS;
432 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000433 case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000434 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
435 default: return STUN_VALUE_UNKNOWN;
436 }
437}
438
439StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
440 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200441 if (value_type != STUN_VALUE_UNKNOWN) {
442 return StunAttribute::Create(value_type, type,
443 static_cast<uint16_t>(length), this);
444 } else if (ImplementationDefinedRange(type)) {
445 // Read unknown attributes as STUN_VALUE_BYTE_STRING
446 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
447 static_cast<uint16_t>(length), this);
448 } else {
449 return NULL;
450 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000451}
452
453const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800454 for (const auto& attr : attrs_) {
455 if (attr->type() == type) {
456 return attr.get();
457 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000458 }
459 return NULL;
460}
461
462bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
463 return transaction_id.size() == kStunTransactionIdLength ||
464 transaction_id.size() == kStunLegacyTransactionIdLength;
465}
466
467// StunAttribute
468
Peter Boström0c4e06b2015-10-07 12:23:21 +0200469StunAttribute::StunAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000470 : type_(type), length_(length) {
471}
472
jbauchf1f87202016-03-30 06:43:37 -0700473void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000474 int remainder = length_ % 4;
475 if (remainder > 0) {
476 buf->Consume(4 - remainder);
477 }
478}
479
jbauchf1f87202016-03-30 06:43:37 -0700480void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000481 int remainder = length_ % 4;
482 if (remainder > 0) {
483 char zeroes[4] = {0};
484 buf->WriteBytes(zeroes, 4 - remainder);
485 }
486}
487
488StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200489 uint16_t type,
490 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000491 StunMessage* owner) {
492 switch (value_type) {
493 case STUN_VALUE_ADDRESS:
494 return new StunAddressAttribute(type, length);
495 case STUN_VALUE_XOR_ADDRESS:
496 return new StunXorAddressAttribute(type, length, owner);
497 case STUN_VALUE_UINT32:
498 return new StunUInt32Attribute(type);
499 case STUN_VALUE_UINT64:
500 return new StunUInt64Attribute(type);
501 case STUN_VALUE_BYTE_STRING:
502 return new StunByteStringAttribute(type, length);
503 case STUN_VALUE_ERROR_CODE:
504 return new StunErrorCodeAttribute(type, length);
505 case STUN_VALUE_UINT16_LIST:
506 return new StunUInt16ListAttribute(type, length);
507 default:
508 return NULL;
509 }
510}
511
zsteinf42cc9d2017-03-27 16:17:19 -0700512std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
513 uint16_t type) {
514 return rtc::MakeUnique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000515}
516
zsteinf42cc9d2017-03-27 16:17:19 -0700517std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
518 uint16_t type) {
519 return rtc::MakeUnique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000520}
521
zsteinf42cc9d2017-03-27 16:17:19 -0700522std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
523 uint16_t type) {
524 return rtc::MakeUnique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000525}
526
zsteinf42cc9d2017-03-27 16:17:19 -0700527std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
528 uint16_t type) {
529 return rtc::MakeUnique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000530}
531
zsteinf42cc9d2017-03-27 16:17:19 -0700532std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
533 uint16_t type) {
534 return rtc::MakeUnique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000535}
536
zsteinf42cc9d2017-03-27 16:17:19 -0700537std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
538 return rtc::MakeUnique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000539 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
540}
541
zsteinf42cc9d2017-03-27 16:17:19 -0700542std::unique_ptr<StunUInt16ListAttribute>
543StunAttribute::CreateUnknownAttributes() {
544 return rtc::MakeUnique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
545 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000546}
547
Peter Boström0c4e06b2015-10-07 12:23:21 +0200548StunAddressAttribute::StunAddressAttribute(uint16_t type,
549 const rtc::SocketAddress& addr)
550 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000551 SetAddress(addr);
552}
553
Peter Boström0c4e06b2015-10-07 12:23:21 +0200554StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000555 : StunAttribute(type, length) {
556}
557
Steve Antonca7d54e2017-10-25 14:42:51 -0700558StunAttributeValueType StunAddressAttribute::value_type() const {
559 return STUN_VALUE_ADDRESS;
560}
561
jbauchf1f87202016-03-30 06:43:37 -0700562bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200563 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564 if (!buf->ReadUInt8(&dummy))
565 return false;
566
Peter Boström0c4e06b2015-10-07 12:23:21 +0200567 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000568 if (!buf->ReadUInt8(&stun_family)) {
569 return false;
570 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200571 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000572 if (!buf->ReadUInt16(&port))
573 return false;
574 if (stun_family == STUN_ADDRESS_IPV4) {
575 in_addr v4addr;
576 if (length() != SIZE_IP4) {
577 return false;
578 }
579 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
580 return false;
581 }
582 rtc::IPAddress ipaddr(v4addr);
583 SetAddress(rtc::SocketAddress(ipaddr, port));
584 } else if (stun_family == STUN_ADDRESS_IPV6) {
585 in6_addr v6addr;
586 if (length() != SIZE_IP6) {
587 return false;
588 }
589 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
590 return false;
591 }
592 rtc::IPAddress ipaddr(v6addr);
593 SetAddress(rtc::SocketAddress(ipaddr, port));
594 } else {
595 return false;
596 }
597 return true;
598}
599
jbauchf1f87202016-03-30 06:43:37 -0700600bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000601 StunAddressFamily address_family = family();
602 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100603 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000604 return false;
605 }
606 buf->WriteUInt8(0);
607 buf->WriteUInt8(address_family);
608 buf->WriteUInt16(address_.port());
609 switch (address_.family()) {
610 case AF_INET: {
611 in_addr v4addr = address_.ipaddr().ipv4_address();
612 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
613 break;
614 }
615 case AF_INET6: {
616 in6_addr v6addr = address_.ipaddr().ipv6_address();
617 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
618 break;
619 }
620 }
621 return true;
622}
623
Peter Boström0c4e06b2015-10-07 12:23:21 +0200624StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
625 const rtc::SocketAddress& addr)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000626 : StunAddressAttribute(type, addr), owner_(NULL) {
627}
628
Peter Boström0c4e06b2015-10-07 12:23:21 +0200629StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
630 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000631 StunMessage* owner)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200632 : StunAddressAttribute(type, length), owner_(owner) {
633}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000634
Steve Antonca7d54e2017-10-25 14:42:51 -0700635StunAttributeValueType StunXorAddressAttribute::value_type() const {
636 return STUN_VALUE_XOR_ADDRESS;
637}
638
639void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
640 owner_ = owner;
641}
642
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000643rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
644 if (owner_) {
645 rtc::IPAddress ip = ipaddr();
646 switch (ip.family()) {
647 case AF_INET: {
648 in_addr v4addr = ip.ipv4_address();
649 v4addr.s_addr =
650 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
651 return rtc::IPAddress(v4addr);
652 }
653 case AF_INET6: {
654 in6_addr v6addr = ip.ipv6_address();
655 const std::string& transaction_id = owner_->transaction_id();
656 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200657 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000658 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
659 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200660 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000661 // Transaction ID is in network byte order, but magic cookie
662 // is stored in host byte order.
663 ip_as_ints[0] =
664 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
665 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
666 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
667 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
668 return rtc::IPAddress(v6addr);
669 }
670 break;
671 }
672 }
673 }
674 // Invalid ip family or transaction ID, or missing owner.
675 // Return an AF_UNSPEC address.
676 return rtc::IPAddress();
677}
678
jbauchf1f87202016-03-30 06:43:37 -0700679bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000680 if (!StunAddressAttribute::Read(buf))
681 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200682 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000683 rtc::IPAddress xored_ip = GetXoredIP();
684 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
685 return true;
686}
687
jbauchf1f87202016-03-30 06:43:37 -0700688bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000689 StunAddressFamily address_family = family();
690 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100691 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000692 return false;
693 }
694 rtc::IPAddress xored_ip = GetXoredIP();
695 if (xored_ip.family() == AF_UNSPEC) {
696 return false;
697 }
698 buf->WriteUInt8(0);
699 buf->WriteUInt8(family());
700 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
701 switch (xored_ip.family()) {
702 case AF_INET: {
703 in_addr v4addr = xored_ip.ipv4_address();
704 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
705 break;
706 }
707 case AF_INET6: {
708 in6_addr v6addr = xored_ip.ipv6_address();
709 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
710 break;
711 }
712 }
713 return true;
714}
715
Peter Boström0c4e06b2015-10-07 12:23:21 +0200716StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000717 : StunAttribute(type, SIZE), bits_(value) {
718}
719
Peter Boström0c4e06b2015-10-07 12:23:21 +0200720StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000721 : StunAttribute(type, SIZE), bits_(0) {
722}
723
Steve Antonca7d54e2017-10-25 14:42:51 -0700724StunAttributeValueType StunUInt32Attribute::value_type() const {
725 return STUN_VALUE_UINT32;
726}
727
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000728bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800729 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000730 return static_cast<bool>((bits_ >> index) & 0x1);
731}
732
733void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800734 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000735 bits_ &= ~(1 << index);
736 bits_ |= value ? (1 << index) : 0;
737}
738
jbauchf1f87202016-03-30 06:43:37 -0700739bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000740 if (length() != SIZE || !buf->ReadUInt32(&bits_))
741 return false;
742 return true;
743}
744
jbauchf1f87202016-03-30 06:43:37 -0700745bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000746 buf->WriteUInt32(bits_);
747 return true;
748}
749
Peter Boström0c4e06b2015-10-07 12:23:21 +0200750StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000751 : StunAttribute(type, SIZE), bits_(value) {
752}
753
Peter Boström0c4e06b2015-10-07 12:23:21 +0200754StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000755 : StunAttribute(type, SIZE), bits_(0) {
756}
757
Steve Antonca7d54e2017-10-25 14:42:51 -0700758StunAttributeValueType StunUInt64Attribute::value_type() const {
759 return STUN_VALUE_UINT64;
760}
761
jbauchf1f87202016-03-30 06:43:37 -0700762bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000763 if (length() != SIZE || !buf->ReadUInt64(&bits_))
764 return false;
765 return true;
766}
767
jbauchf1f87202016-03-30 06:43:37 -0700768bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000769 buf->WriteUInt64(bits_);
770 return true;
771}
772
Peter Boström0c4e06b2015-10-07 12:23:21 +0200773StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000774 : StunAttribute(type, 0), bytes_(NULL) {
775}
776
Peter Boström0c4e06b2015-10-07 12:23:21 +0200777StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000778 const std::string& str)
779 : StunAttribute(type, 0), bytes_(NULL) {
780 CopyBytes(str.c_str(), str.size());
781}
782
Peter Boström0c4e06b2015-10-07 12:23:21 +0200783StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000784 const void* bytes,
785 size_t length)
786 : StunAttribute(type, 0), bytes_(NULL) {
787 CopyBytes(bytes, length);
788}
789
Peter Boström0c4e06b2015-10-07 12:23:21 +0200790StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000791 : StunAttribute(type, length), bytes_(NULL) {
792}
793
794StunByteStringAttribute::~StunByteStringAttribute() {
795 delete [] bytes_;
796}
797
Steve Antonca7d54e2017-10-25 14:42:51 -0700798StunAttributeValueType StunByteStringAttribute::value_type() const {
799 return STUN_VALUE_BYTE_STRING;
800}
801
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000802void StunByteStringAttribute::CopyBytes(const char* bytes) {
803 CopyBytes(bytes, strlen(bytes));
804}
805
806void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
807 char* new_bytes = new char[length];
808 memcpy(new_bytes, bytes, length);
809 SetBytes(new_bytes, length);
810}
811
Peter Boström0c4e06b2015-10-07 12:23:21 +0200812uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800813 RTC_DCHECK(bytes_ != NULL);
814 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200815 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000816}
817
Peter Boström0c4e06b2015-10-07 12:23:21 +0200818void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800819 RTC_DCHECK(bytes_ != NULL);
820 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000821 bytes_[index] = value;
822}
823
jbauchf1f87202016-03-30 06:43:37 -0700824bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000825 bytes_ = new char[length()];
826 if (!buf->ReadBytes(bytes_, length())) {
827 return false;
828 }
829
830 ConsumePadding(buf);
831 return true;
832}
833
jbauchf1f87202016-03-30 06:43:37 -0700834bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000835 buf->WriteBytes(bytes_, length());
836 WritePadding(buf);
837 return true;
838}
839
840void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
841 delete [] bytes_;
842 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200843 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000844}
845
zsteinf42cc9d2017-03-27 16:17:19 -0700846const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
847
Peter Boström0c4e06b2015-10-07 12:23:21 +0200848StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
849 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000850 const std::string& reason)
851 : StunAttribute(type, 0) {
852 SetCode(code);
853 SetReason(reason);
854}
855
Peter Boström0c4e06b2015-10-07 12:23:21 +0200856StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000857 : StunAttribute(type, length), class_(0), number_(0) {
858}
859
860StunErrorCodeAttribute::~StunErrorCodeAttribute() {
861}
862
Steve Antonca7d54e2017-10-25 14:42:51 -0700863StunAttributeValueType StunErrorCodeAttribute::value_type() const {
864 return STUN_VALUE_ERROR_CODE;
865}
866
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000867int StunErrorCodeAttribute::code() const {
868 return class_ * 100 + number_;
869}
870
871void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200872 class_ = static_cast<uint8_t>(code / 100);
873 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000874}
875
876void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200877 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000878 reason_ = reason;
879}
880
jbauchf1f87202016-03-30 06:43:37 -0700881bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200882 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000883 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
884 return false;
885
886 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100887 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000888
889 class_ = ((val >> 8) & 0x7);
890 number_ = (val & 0xff);
891
892 if (!buf->ReadString(&reason_, length() - 4))
893 return false;
894
895 ConsumePadding(buf);
896 return true;
897}
898
jbauchf1f87202016-03-30 06:43:37 -0700899bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000900 buf->WriteUInt32(class_ << 8 | number_);
901 buf->WriteString(reason_);
902 WritePadding(buf);
903 return true;
904}
905
Peter Boström0c4e06b2015-10-07 12:23:21 +0200906StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000907 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200908 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000909}
910
911StunUInt16ListAttribute::~StunUInt16ListAttribute() {
912 delete attr_types_;
913}
914
Steve Antonca7d54e2017-10-25 14:42:51 -0700915StunAttributeValueType StunUInt16ListAttribute::value_type() const {
916 return STUN_VALUE_UINT16_LIST;
917}
918
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000919size_t StunUInt16ListAttribute::Size() const {
920 return attr_types_->size();
921}
922
Peter Boström0c4e06b2015-10-07 12:23:21 +0200923uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000924 return (*attr_types_)[index];
925}
926
Peter Boström0c4e06b2015-10-07 12:23:21 +0200927void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000928 (*attr_types_)[index] = value;
929}
930
Peter Boström0c4e06b2015-10-07 12:23:21 +0200931void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000932 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200933 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000934}
935
jbauchf1f87202016-03-30 06:43:37 -0700936bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000937 if (length() % 2)
938 return false;
939
940 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200941 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000942 if (!buf->ReadUInt16(&attr))
943 return false;
944 attr_types_->push_back(attr);
945 }
946 // Padding of these attributes is done in RFC 5389 style. This is
947 // slightly different from RFC3489, but it shouldn't be important.
948 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
949 // entries in the list (not necessarily the last one - it's unspecified).
950 // RFC5389 pads on the end, and the bytes are always ignored.
951 ConsumePadding(buf);
952 return true;
953}
954
jbauchf1f87202016-03-30 06:43:37 -0700955bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000956 for (size_t i = 0; i < attr_types_->size(); ++i) {
957 buf->WriteUInt16((*attr_types_)[i]);
958 }
959 WritePadding(buf);
960 return true;
961}
962
963int GetStunSuccessResponseType(int req_type) {
964 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
965}
966
967int GetStunErrorResponseType(int req_type) {
968 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
969}
970
971bool IsStunRequestType(int msg_type) {
972 return ((msg_type & kStunTypeMask) == 0x000);
973}
974
975bool IsStunIndicationType(int msg_type) {
976 return ((msg_type & kStunTypeMask) == 0x010);
977}
978
979bool IsStunSuccessResponseType(int msg_type) {
980 return ((msg_type & kStunTypeMask) == 0x100);
981}
982
983bool IsStunErrorResponseType(int msg_type) {
984 return ((msg_type & kStunTypeMask) == 0x110);
985}
986
987bool ComputeStunCredentialHash(const std::string& username,
988 const std::string& realm,
989 const std::string& password,
990 std::string* hash) {
991 // http://tools.ietf.org/html/rfc5389#section-15.4
992 // long-term credentials will be calculated using the key and key is
993 // key = MD5(username ":" realm ":" SASLprep(password))
994 std::string input = username;
995 input += ':';
996 input += realm;
997 input += ':';
998 input += password;
999
1000 char digest[rtc::MessageDigest::kMaxSize];
1001 size_t size = rtc::ComputeDigest(
1002 rtc::DIGEST_MD5, input.c_str(), input.size(),
1003 digest, sizeof(digest));
1004 if (size == 0) {
1005 return false;
1006 }
1007
1008 *hash = std::string(digest, size);
1009 return true;
1010}
1011
Jonas Oreland202994c2017-12-18 12:10:43 +01001012std::unique_ptr<StunAttribute> CopyStunAttribute(
1013 const StunAttribute& attribute,
1014 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1015 ByteBufferWriter tmpBuffer;
1016 if (tmp_buffer_ptr == nullptr) {
1017 tmp_buffer_ptr = &tmpBuffer;
1018 }
1019
1020 std::unique_ptr<StunAttribute> copy(
1021 StunAttribute::Create(attribute.value_type(),
1022 attribute.type(),
1023 static_cast<uint16_t>(attribute.length()),
1024 nullptr));
1025
1026 if (!copy) {
1027 return nullptr;
1028 }
1029 tmp_buffer_ptr->Clear();
1030 if (!attribute.Write(tmp_buffer_ptr)) {
1031 return nullptr;
1032 }
1033 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1034 if (!copy->Read(&reader)) {
1035 return nullptr;
1036 }
1037
1038 return copy;
1039}
1040
Steve Antonca7d54e2017-10-25 14:42:51 -07001041StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1042 switch (type) {
1043 case STUN_ATTR_LIFETIME:
1044 return STUN_VALUE_UINT32;
1045 case STUN_ATTR_MAGIC_COOKIE:
1046 return STUN_VALUE_BYTE_STRING;
1047 case STUN_ATTR_BANDWIDTH:
1048 return STUN_VALUE_UINT32;
1049 case STUN_ATTR_DESTINATION_ADDRESS:
1050 return STUN_VALUE_ADDRESS;
1051 case STUN_ATTR_SOURCE_ADDRESS2:
1052 return STUN_VALUE_ADDRESS;
1053 case STUN_ATTR_DATA:
1054 return STUN_VALUE_BYTE_STRING;
1055 case STUN_ATTR_OPTIONS:
1056 return STUN_VALUE_UINT32;
1057 default:
1058 return StunMessage::GetAttributeValueType(type);
1059 }
1060}
1061
1062StunMessage* RelayMessage::CreateNew() const {
1063 return new RelayMessage();
1064}
1065
1066StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1067 switch (type) {
1068 case STUN_ATTR_CHANNEL_NUMBER:
1069 return STUN_VALUE_UINT32;
1070 case STUN_ATTR_TURN_LIFETIME:
1071 return STUN_VALUE_UINT32;
1072 case STUN_ATTR_XOR_PEER_ADDRESS:
1073 return STUN_VALUE_XOR_ADDRESS;
1074 case STUN_ATTR_DATA:
1075 return STUN_VALUE_BYTE_STRING;
1076 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1077 return STUN_VALUE_XOR_ADDRESS;
1078 case STUN_ATTR_EVEN_PORT:
1079 return STUN_VALUE_BYTE_STRING;
1080 case STUN_ATTR_REQUESTED_TRANSPORT:
1081 return STUN_VALUE_UINT32;
1082 case STUN_ATTR_DONT_FRAGMENT:
1083 return STUN_VALUE_BYTE_STRING;
1084 case STUN_ATTR_RESERVATION_TOKEN:
1085 return STUN_VALUE_BYTE_STRING;
1086 default:
1087 return StunMessage::GetAttributeValueType(type);
1088 }
1089}
1090
1091StunMessage* TurnMessage::CreateNew() const {
1092 return new TurnMessage();
1093}
1094
1095StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1096 switch (type) {
1097 case STUN_ATTR_PRIORITY:
1098 case STUN_ATTR_NETWORK_INFO:
1099 case STUN_ATTR_NOMINATION:
1100 return STUN_VALUE_UINT32;
1101 case STUN_ATTR_USE_CANDIDATE:
1102 return STUN_VALUE_BYTE_STRING;
1103 case STUN_ATTR_ICE_CONTROLLED:
1104 return STUN_VALUE_UINT64;
1105 case STUN_ATTR_ICE_CONTROLLING:
1106 return STUN_VALUE_UINT64;
1107 default:
1108 return StunMessage::GetAttributeValueType(type);
1109 }
1110}
1111
1112StunMessage* IceMessage::CreateNew() const {
1113 return new IceMessage();
1114}
1115
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001116} // namespace cricket