blob: 2bedde07a28ad0ba10782d90817131fe405496a4 [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
Jonas Oreland16ccef72018-03-27 09:02:43 +020074static bool DesignatedExpertRange(int attr_type) {
75 return
76 (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
77 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +020078}
79
zsteinf42cc9d2017-03-27 16:17:19 -070080void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020081 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +020082 // but allow any type for the range that in the RFC is reserved for
83 // the "designated experts".
84 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020085 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
86 }
nissecc99bc22017-02-02 01:31:30 -080087
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000088 attr->SetOwner(this);
89 size_t attr_length = attr->length();
90 if (attr_length % 4 != 0) {
91 attr_length += (4 - (attr_length % 4));
92 }
Peter Boström0c4e06b2015-10-07 12:23:21 +020093 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -070094
95 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000096}
97
Jonas Oreland202994c2017-12-18 12:10:43 +010098std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
99 std::unique_ptr<StunAttribute> attribute;
100 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
101 if ((* it)->type() == type) {
102 attribute = std::move(* it);
103 attrs_.erase(std::next(it).base());
104 break;
105 }
106 }
107 if (attribute) {
108 attribute->SetOwner(nullptr);
109 size_t attr_length = attribute->length();
110 if (attr_length % 4 != 0) {
111 attr_length += (4 - (attr_length % 4));
112 }
113 length_ -= static_cast<uint16_t>(attr_length + 4);
114 }
115 return attribute;
116}
117
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000118const StunAddressAttribute* StunMessage::GetAddress(int type) const {
119 switch (type) {
120 case STUN_ATTR_MAPPED_ADDRESS: {
121 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
122 // missing.
123 const StunAttribute* mapped_address =
124 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
125 if (!mapped_address)
126 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
127 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
128 }
129
130 default:
131 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
132 }
133}
134
135const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
136 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
137}
138
139const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
140 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
141}
142
143const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
144 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
145}
146
147const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
148 return static_cast<const StunErrorCodeAttribute*>(
149 GetAttribute(STUN_ATTR_ERROR_CODE));
150}
151
deadbeef996fc6b2017-04-26 09:21:22 -0700152int StunMessage::GetErrorCodeValue() const {
153 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
154 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
155}
156
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000157const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
158 return static_cast<const StunUInt16ListAttribute*>(
159 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
160}
161
162// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
163// procedure outlined in RFC 5389, section 15.4.
164bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
165 const std::string& password) {
166 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700167 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000168 return false;
169 }
170
171 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200172 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000173 if (size != (msg_length + kStunHeaderSize)) {
174 return false;
175 }
176
177 // Finding Message Integrity attribute in stun message.
178 size_t current_pos = kStunHeaderSize;
179 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700180 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200181 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000182 // Getting attribute type and length.
183 attr_type = rtc::GetBE16(&data[current_pos]);
184 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
185
186 // If M-I, sanity check it, and break out.
187 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
188 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700189 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
190 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000191 return false;
192 }
193 has_message_integrity_attr = true;
194 break;
195 }
196
197 // Otherwise, skip to the next attribute.
198 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
199 if ((attr_length % 4) != 0) {
200 current_pos += (4 - (attr_length % 4));
201 }
202 }
203
204 if (!has_message_integrity_attr) {
205 return false;
206 }
207
208 // Getting length of the message to calculate Message Integrity.
209 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700210 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000211 memcpy(temp_data.get(), data, current_pos);
212 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
213 // Stun message has other attributes after message integrity.
214 // Adjust the length parameter in stun message to calculate HMAC.
215 size_t extra_offset = size -
216 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
217 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
218
219 // Writing new length of the STUN message @ Message Length in temp buffer.
220 // 0 1 2 3
221 // 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
222 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
223 // |0 0| STUN Message Type | Message Length |
224 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200225 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000226 }
227
228 char hmac[kStunMessageIntegritySize];
229 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
230 password.c_str(), password.size(),
231 temp_data.get(), mi_pos,
232 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800233 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000234 if (ret != sizeof(hmac))
235 return false;
236
237 // Comparing the calculated HMAC with the one present in the message.
238 return memcmp(data + current_pos + kStunAttributeHeaderSize,
239 hmac,
240 sizeof(hmac)) == 0;
241}
242
243bool StunMessage::AddMessageIntegrity(const std::string& password) {
244 return AddMessageIntegrity(password.c_str(), password.size());
245}
246
247bool StunMessage::AddMessageIntegrity(const char* key,
248 size_t keylen) {
249 // Add the attribute with a dummy value. Since this is a known attribute, it
250 // can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700251 auto msg_integrity_attr_ptr = rtc::MakeUnique<StunByteStringAttribute>(
252 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
253 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
254 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000255
256 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700257 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000258 if (!Write(&buf))
259 return false;
260
261 int msg_len_for_hmac = static_cast<int>(
262 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
263 char hmac[kStunMessageIntegritySize];
264 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
265 key, keylen,
266 buf.Data(), msg_len_for_hmac,
267 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800268 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000269 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100270 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200271 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000272 return false;
273 }
274
275 // Insert correct HMAC into the attribute.
276 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
277 return true;
278}
279
280// Verifies a message is in fact a STUN message, by performing the checks
281// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
282// in section 15.5.
283bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
284 // Check the message length.
285 size_t fingerprint_attr_size =
286 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
287 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
288 return false;
289
290 // Skip the rest if the magic cookie isn't present.
291 const char* magic_cookie =
292 data + kStunTransactionIdOffset - kStunMagicCookieLength;
293 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
294 return false;
295
296 // Check the fingerprint type and length.
297 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
298 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200299 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000300 StunUInt32Attribute::SIZE)
301 return false;
302
303 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200304 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000305 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
306 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
307 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
308}
309
310bool StunMessage::AddFingerprint() {
311 // Add the attribute with a dummy value. Since this is a known attribute,
312 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700313 auto fingerprint_attr_ptr =
314 rtc::MakeUnique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700315 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700316 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000317
318 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700319 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000320 if (!Write(&buf))
321 return false;
322
323 int msg_len_for_crc32 = static_cast<int>(
324 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200325 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000326
327 // Insert the correct CRC-32, XORed with a constant, into the attribute.
328 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
329 return true;
330}
331
jbauchf1f87202016-03-30 06:43:37 -0700332bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000333 if (!buf->ReadUInt16(&type_))
334 return false;
335
336 if (type_ & 0x8000) {
337 // RTP and RTCP set the MSB of first byte, since first two bits are version,
338 // and version is always 2 (10). If set, this is not a STUN packet.
339 return false;
340 }
341
342 if (!buf->ReadUInt16(&length_))
343 return false;
344
345 std::string magic_cookie;
346 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
347 return false;
348
349 std::string transaction_id;
350 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
351 return false;
352
Peter Boström0c4e06b2015-10-07 12:23:21 +0200353 uint32_t magic_cookie_int =
354 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000355 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
356 // If magic cookie is invalid it means that the peer implements
357 // RFC3489 instead of RFC5389.
358 transaction_id.insert(0, magic_cookie);
359 }
nisseede5da42017-01-12 05:15:36 -0800360 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000361 transaction_id_ = transaction_id;
362
363 if (length_ != buf->Length())
364 return false;
365
zsteinad94c4c2017-03-06 13:36:05 -0800366 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000367
368 size_t rest = buf->Length() - length_;
369 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200370 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371 if (!buf->ReadUInt16(&attr_type))
372 return false;
373 if (!buf->ReadUInt16(&attr_length))
374 return false;
375
Honghai Zhang3e024302016-09-22 09:52:16 -0700376 std::unique_ptr<StunAttribute> attr(
377 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000378 if (!attr) {
379 // Skip any unknown or malformed attributes.
380 if ((attr_length % 4) != 0) {
381 attr_length += (4 - (attr_length % 4));
382 }
383 if (!buf->Consume(attr_length))
384 return false;
385 } else {
386 if (!attr->Read(buf))
387 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800388 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000389 }
390 }
391
nisseede5da42017-01-12 05:15:36 -0800392 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000393 return true;
394}
395
jbauchf1f87202016-03-30 06:43:37 -0700396bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000397 buf->WriteUInt16(type_);
398 buf->WriteUInt16(length_);
399 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100400 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000401 buf->WriteString(transaction_id_);
402
zsteinad94c4c2017-03-06 13:36:05 -0800403 for (const auto& attr : attrs_) {
404 buf->WriteUInt16(attr->type());
405 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
406 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000407 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800408 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000409 }
410
411 return true;
412}
413
Steve Antonca7d54e2017-10-25 14:42:51 -0700414StunMessage* StunMessage::CreateNew() const {
415 return new StunMessage();
416}
417
Jonas Oreland7ca63112018-02-27 08:45:13 +0100418void StunMessage::SetStunMagicCookie(uint32_t val) {
419 stun_magic_cookie_ = val;
420}
421
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000422StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
423 switch (type) {
424 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
425 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
426 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
427 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
428 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
429 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
430 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
431 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
432 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
433 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS;
434 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000435 case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000436 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
437 default: return STUN_VALUE_UNKNOWN;
438 }
439}
440
441StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
442 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200443 if (value_type != STUN_VALUE_UNKNOWN) {
444 return StunAttribute::Create(value_type, type,
445 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200446 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200447 // Read unknown attributes as STUN_VALUE_BYTE_STRING
448 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
449 static_cast<uint16_t>(length), this);
450 } else {
451 return NULL;
452 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000453}
454
455const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800456 for (const auto& attr : attrs_) {
457 if (attr->type() == type) {
458 return attr.get();
459 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000460 }
461 return NULL;
462}
463
464bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
465 return transaction_id.size() == kStunTransactionIdLength ||
466 transaction_id.size() == kStunLegacyTransactionIdLength;
467}
468
469// StunAttribute
470
Peter Boström0c4e06b2015-10-07 12:23:21 +0200471StunAttribute::StunAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000472 : type_(type), length_(length) {
473}
474
jbauchf1f87202016-03-30 06:43:37 -0700475void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000476 int remainder = length_ % 4;
477 if (remainder > 0) {
478 buf->Consume(4 - remainder);
479 }
480}
481
jbauchf1f87202016-03-30 06:43:37 -0700482void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000483 int remainder = length_ % 4;
484 if (remainder > 0) {
485 char zeroes[4] = {0};
486 buf->WriteBytes(zeroes, 4 - remainder);
487 }
488}
489
490StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200491 uint16_t type,
492 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000493 StunMessage* owner) {
494 switch (value_type) {
495 case STUN_VALUE_ADDRESS:
496 return new StunAddressAttribute(type, length);
497 case STUN_VALUE_XOR_ADDRESS:
498 return new StunXorAddressAttribute(type, length, owner);
499 case STUN_VALUE_UINT32:
500 return new StunUInt32Attribute(type);
501 case STUN_VALUE_UINT64:
502 return new StunUInt64Attribute(type);
503 case STUN_VALUE_BYTE_STRING:
504 return new StunByteStringAttribute(type, length);
505 case STUN_VALUE_ERROR_CODE:
506 return new StunErrorCodeAttribute(type, length);
507 case STUN_VALUE_UINT16_LIST:
508 return new StunUInt16ListAttribute(type, length);
509 default:
510 return NULL;
511 }
512}
513
zsteinf42cc9d2017-03-27 16:17:19 -0700514std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
515 uint16_t type) {
516 return rtc::MakeUnique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000517}
518
zsteinf42cc9d2017-03-27 16:17:19 -0700519std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
520 uint16_t type) {
521 return rtc::MakeUnique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000522}
523
zsteinf42cc9d2017-03-27 16:17:19 -0700524std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
525 uint16_t type) {
526 return rtc::MakeUnique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000527}
528
zsteinf42cc9d2017-03-27 16:17:19 -0700529std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
530 uint16_t type) {
531 return rtc::MakeUnique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000532}
533
zsteinf42cc9d2017-03-27 16:17:19 -0700534std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
535 uint16_t type) {
536 return rtc::MakeUnique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000537}
538
zsteinf42cc9d2017-03-27 16:17:19 -0700539std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
540 return rtc::MakeUnique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000541 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
542}
543
zsteinf42cc9d2017-03-27 16:17:19 -0700544std::unique_ptr<StunUInt16ListAttribute>
545StunAttribute::CreateUnknownAttributes() {
546 return rtc::MakeUnique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
547 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000548}
549
Peter Boström0c4e06b2015-10-07 12:23:21 +0200550StunAddressAttribute::StunAddressAttribute(uint16_t type,
551 const rtc::SocketAddress& addr)
552 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000553 SetAddress(addr);
554}
555
Peter Boström0c4e06b2015-10-07 12:23:21 +0200556StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000557 : StunAttribute(type, length) {
558}
559
Steve Antonca7d54e2017-10-25 14:42:51 -0700560StunAttributeValueType StunAddressAttribute::value_type() const {
561 return STUN_VALUE_ADDRESS;
562}
563
jbauchf1f87202016-03-30 06:43:37 -0700564bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200565 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000566 if (!buf->ReadUInt8(&dummy))
567 return false;
568
Peter Boström0c4e06b2015-10-07 12:23:21 +0200569 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000570 if (!buf->ReadUInt8(&stun_family)) {
571 return false;
572 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200573 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574 if (!buf->ReadUInt16(&port))
575 return false;
576 if (stun_family == STUN_ADDRESS_IPV4) {
577 in_addr v4addr;
578 if (length() != SIZE_IP4) {
579 return false;
580 }
581 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
582 return false;
583 }
584 rtc::IPAddress ipaddr(v4addr);
585 SetAddress(rtc::SocketAddress(ipaddr, port));
586 } else if (stun_family == STUN_ADDRESS_IPV6) {
587 in6_addr v6addr;
588 if (length() != SIZE_IP6) {
589 return false;
590 }
591 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
592 return false;
593 }
594 rtc::IPAddress ipaddr(v6addr);
595 SetAddress(rtc::SocketAddress(ipaddr, port));
596 } else {
597 return false;
598 }
599 return true;
600}
601
jbauchf1f87202016-03-30 06:43:37 -0700602bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000603 StunAddressFamily address_family = family();
604 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100605 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000606 return false;
607 }
608 buf->WriteUInt8(0);
609 buf->WriteUInt8(address_family);
610 buf->WriteUInt16(address_.port());
611 switch (address_.family()) {
612 case AF_INET: {
613 in_addr v4addr = address_.ipaddr().ipv4_address();
614 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
615 break;
616 }
617 case AF_INET6: {
618 in6_addr v6addr = address_.ipaddr().ipv6_address();
619 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
620 break;
621 }
622 }
623 return true;
624}
625
Peter Boström0c4e06b2015-10-07 12:23:21 +0200626StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
627 const rtc::SocketAddress& addr)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000628 : StunAddressAttribute(type, addr), owner_(NULL) {
629}
630
Peter Boström0c4e06b2015-10-07 12:23:21 +0200631StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
632 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000633 StunMessage* owner)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200634 : StunAddressAttribute(type, length), owner_(owner) {
635}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000636
Steve Antonca7d54e2017-10-25 14:42:51 -0700637StunAttributeValueType StunXorAddressAttribute::value_type() const {
638 return STUN_VALUE_XOR_ADDRESS;
639}
640
641void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
642 owner_ = owner;
643}
644
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000645rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
646 if (owner_) {
647 rtc::IPAddress ip = ipaddr();
648 switch (ip.family()) {
649 case AF_INET: {
650 in_addr v4addr = ip.ipv4_address();
651 v4addr.s_addr =
652 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
653 return rtc::IPAddress(v4addr);
654 }
655 case AF_INET6: {
656 in6_addr v6addr = ip.ipv6_address();
657 const std::string& transaction_id = owner_->transaction_id();
658 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200659 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000660 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
661 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200662 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000663 // Transaction ID is in network byte order, but magic cookie
664 // is stored in host byte order.
665 ip_as_ints[0] =
666 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
667 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
668 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
669 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
670 return rtc::IPAddress(v6addr);
671 }
672 break;
673 }
674 }
675 }
676 // Invalid ip family or transaction ID, or missing owner.
677 // Return an AF_UNSPEC address.
678 return rtc::IPAddress();
679}
680
jbauchf1f87202016-03-30 06:43:37 -0700681bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000682 if (!StunAddressAttribute::Read(buf))
683 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200684 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000685 rtc::IPAddress xored_ip = GetXoredIP();
686 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
687 return true;
688}
689
jbauchf1f87202016-03-30 06:43:37 -0700690bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691 StunAddressFamily address_family = family();
692 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100693 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000694 return false;
695 }
696 rtc::IPAddress xored_ip = GetXoredIP();
697 if (xored_ip.family() == AF_UNSPEC) {
698 return false;
699 }
700 buf->WriteUInt8(0);
701 buf->WriteUInt8(family());
702 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
703 switch (xored_ip.family()) {
704 case AF_INET: {
705 in_addr v4addr = xored_ip.ipv4_address();
706 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
707 break;
708 }
709 case AF_INET6: {
710 in6_addr v6addr = xored_ip.ipv6_address();
711 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
712 break;
713 }
714 }
715 return true;
716}
717
Peter Boström0c4e06b2015-10-07 12:23:21 +0200718StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000719 : StunAttribute(type, SIZE), bits_(value) {
720}
721
Peter Boström0c4e06b2015-10-07 12:23:21 +0200722StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000723 : StunAttribute(type, SIZE), bits_(0) {
724}
725
Steve Antonca7d54e2017-10-25 14:42:51 -0700726StunAttributeValueType StunUInt32Attribute::value_type() const {
727 return STUN_VALUE_UINT32;
728}
729
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000730bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800731 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000732 return static_cast<bool>((bits_ >> index) & 0x1);
733}
734
735void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800736 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000737 bits_ &= ~(1 << index);
738 bits_ |= value ? (1 << index) : 0;
739}
740
jbauchf1f87202016-03-30 06:43:37 -0700741bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000742 if (length() != SIZE || !buf->ReadUInt32(&bits_))
743 return false;
744 return true;
745}
746
jbauchf1f87202016-03-30 06:43:37 -0700747bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000748 buf->WriteUInt32(bits_);
749 return true;
750}
751
Peter Boström0c4e06b2015-10-07 12:23:21 +0200752StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000753 : StunAttribute(type, SIZE), bits_(value) {
754}
755
Peter Boström0c4e06b2015-10-07 12:23:21 +0200756StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000757 : StunAttribute(type, SIZE), bits_(0) {
758}
759
Steve Antonca7d54e2017-10-25 14:42:51 -0700760StunAttributeValueType StunUInt64Attribute::value_type() const {
761 return STUN_VALUE_UINT64;
762}
763
jbauchf1f87202016-03-30 06:43:37 -0700764bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000765 if (length() != SIZE || !buf->ReadUInt64(&bits_))
766 return false;
767 return true;
768}
769
jbauchf1f87202016-03-30 06:43:37 -0700770bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000771 buf->WriteUInt64(bits_);
772 return true;
773}
774
Peter Boström0c4e06b2015-10-07 12:23:21 +0200775StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000776 : StunAttribute(type, 0), bytes_(NULL) {
777}
778
Peter Boström0c4e06b2015-10-07 12:23:21 +0200779StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000780 const std::string& str)
781 : StunAttribute(type, 0), bytes_(NULL) {
782 CopyBytes(str.c_str(), str.size());
783}
784
Peter Boström0c4e06b2015-10-07 12:23:21 +0200785StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000786 const void* bytes,
787 size_t length)
788 : StunAttribute(type, 0), bytes_(NULL) {
789 CopyBytes(bytes, length);
790}
791
Peter Boström0c4e06b2015-10-07 12:23:21 +0200792StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000793 : StunAttribute(type, length), bytes_(NULL) {
794}
795
796StunByteStringAttribute::~StunByteStringAttribute() {
797 delete [] bytes_;
798}
799
Steve Antonca7d54e2017-10-25 14:42:51 -0700800StunAttributeValueType StunByteStringAttribute::value_type() const {
801 return STUN_VALUE_BYTE_STRING;
802}
803
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000804void StunByteStringAttribute::CopyBytes(const char* bytes) {
805 CopyBytes(bytes, strlen(bytes));
806}
807
808void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
809 char* new_bytes = new char[length];
810 memcpy(new_bytes, bytes, length);
811 SetBytes(new_bytes, length);
812}
813
Peter Boström0c4e06b2015-10-07 12:23:21 +0200814uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800815 RTC_DCHECK(bytes_ != NULL);
816 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200817 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000818}
819
Peter Boström0c4e06b2015-10-07 12:23:21 +0200820void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800821 RTC_DCHECK(bytes_ != NULL);
822 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000823 bytes_[index] = value;
824}
825
jbauchf1f87202016-03-30 06:43:37 -0700826bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000827 bytes_ = new char[length()];
828 if (!buf->ReadBytes(bytes_, length())) {
829 return false;
830 }
831
832 ConsumePadding(buf);
833 return true;
834}
835
jbauchf1f87202016-03-30 06:43:37 -0700836bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000837 buf->WriteBytes(bytes_, length());
838 WritePadding(buf);
839 return true;
840}
841
842void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
843 delete [] bytes_;
844 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200845 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000846}
847
zsteinf42cc9d2017-03-27 16:17:19 -0700848const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
849
Peter Boström0c4e06b2015-10-07 12:23:21 +0200850StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
851 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000852 const std::string& reason)
853 : StunAttribute(type, 0) {
854 SetCode(code);
855 SetReason(reason);
856}
857
Peter Boström0c4e06b2015-10-07 12:23:21 +0200858StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000859 : StunAttribute(type, length), class_(0), number_(0) {
860}
861
862StunErrorCodeAttribute::~StunErrorCodeAttribute() {
863}
864
Steve Antonca7d54e2017-10-25 14:42:51 -0700865StunAttributeValueType StunErrorCodeAttribute::value_type() const {
866 return STUN_VALUE_ERROR_CODE;
867}
868
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000869int StunErrorCodeAttribute::code() const {
870 return class_ * 100 + number_;
871}
872
873void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200874 class_ = static_cast<uint8_t>(code / 100);
875 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000876}
877
878void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200879 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000880 reason_ = reason;
881}
882
jbauchf1f87202016-03-30 06:43:37 -0700883bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200884 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000885 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
886 return false;
887
888 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100889 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000890
891 class_ = ((val >> 8) & 0x7);
892 number_ = (val & 0xff);
893
894 if (!buf->ReadString(&reason_, length() - 4))
895 return false;
896
897 ConsumePadding(buf);
898 return true;
899}
900
jbauchf1f87202016-03-30 06:43:37 -0700901bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000902 buf->WriteUInt32(class_ << 8 | number_);
903 buf->WriteString(reason_);
904 WritePadding(buf);
905 return true;
906}
907
Peter Boström0c4e06b2015-10-07 12:23:21 +0200908StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000909 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200910 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000911}
912
913StunUInt16ListAttribute::~StunUInt16ListAttribute() {
914 delete attr_types_;
915}
916
Steve Antonca7d54e2017-10-25 14:42:51 -0700917StunAttributeValueType StunUInt16ListAttribute::value_type() const {
918 return STUN_VALUE_UINT16_LIST;
919}
920
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000921size_t StunUInt16ListAttribute::Size() const {
922 return attr_types_->size();
923}
924
Peter Boström0c4e06b2015-10-07 12:23:21 +0200925uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000926 return (*attr_types_)[index];
927}
928
Peter Boström0c4e06b2015-10-07 12:23:21 +0200929void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000930 (*attr_types_)[index] = value;
931}
932
Peter Boström0c4e06b2015-10-07 12:23:21 +0200933void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000934 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200935 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000936}
937
jbauchf1f87202016-03-30 06:43:37 -0700938bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000939 if (length() % 2)
940 return false;
941
942 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200943 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000944 if (!buf->ReadUInt16(&attr))
945 return false;
946 attr_types_->push_back(attr);
947 }
948 // Padding of these attributes is done in RFC 5389 style. This is
949 // slightly different from RFC3489, but it shouldn't be important.
950 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
951 // entries in the list (not necessarily the last one - it's unspecified).
952 // RFC5389 pads on the end, and the bytes are always ignored.
953 ConsumePadding(buf);
954 return true;
955}
956
jbauchf1f87202016-03-30 06:43:37 -0700957bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000958 for (size_t i = 0; i < attr_types_->size(); ++i) {
959 buf->WriteUInt16((*attr_types_)[i]);
960 }
961 WritePadding(buf);
962 return true;
963}
964
965int GetStunSuccessResponseType(int req_type) {
966 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
967}
968
969int GetStunErrorResponseType(int req_type) {
970 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
971}
972
973bool IsStunRequestType(int msg_type) {
974 return ((msg_type & kStunTypeMask) == 0x000);
975}
976
977bool IsStunIndicationType(int msg_type) {
978 return ((msg_type & kStunTypeMask) == 0x010);
979}
980
981bool IsStunSuccessResponseType(int msg_type) {
982 return ((msg_type & kStunTypeMask) == 0x100);
983}
984
985bool IsStunErrorResponseType(int msg_type) {
986 return ((msg_type & kStunTypeMask) == 0x110);
987}
988
989bool ComputeStunCredentialHash(const std::string& username,
990 const std::string& realm,
991 const std::string& password,
992 std::string* hash) {
993 // http://tools.ietf.org/html/rfc5389#section-15.4
994 // long-term credentials will be calculated using the key and key is
995 // key = MD5(username ":" realm ":" SASLprep(password))
996 std::string input = username;
997 input += ':';
998 input += realm;
999 input += ':';
1000 input += password;
1001
1002 char digest[rtc::MessageDigest::kMaxSize];
1003 size_t size = rtc::ComputeDigest(
1004 rtc::DIGEST_MD5, input.c_str(), input.size(),
1005 digest, sizeof(digest));
1006 if (size == 0) {
1007 return false;
1008 }
1009
1010 *hash = std::string(digest, size);
1011 return true;
1012}
1013
Jonas Oreland202994c2017-12-18 12:10:43 +01001014std::unique_ptr<StunAttribute> CopyStunAttribute(
1015 const StunAttribute& attribute,
1016 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1017 ByteBufferWriter tmpBuffer;
1018 if (tmp_buffer_ptr == nullptr) {
1019 tmp_buffer_ptr = &tmpBuffer;
1020 }
1021
1022 std::unique_ptr<StunAttribute> copy(
1023 StunAttribute::Create(attribute.value_type(),
1024 attribute.type(),
1025 static_cast<uint16_t>(attribute.length()),
1026 nullptr));
1027
1028 if (!copy) {
1029 return nullptr;
1030 }
1031 tmp_buffer_ptr->Clear();
1032 if (!attribute.Write(tmp_buffer_ptr)) {
1033 return nullptr;
1034 }
1035 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1036 if (!copy->Read(&reader)) {
1037 return nullptr;
1038 }
1039
1040 return copy;
1041}
1042
Steve Antonca7d54e2017-10-25 14:42:51 -07001043StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1044 switch (type) {
1045 case STUN_ATTR_LIFETIME:
1046 return STUN_VALUE_UINT32;
1047 case STUN_ATTR_MAGIC_COOKIE:
1048 return STUN_VALUE_BYTE_STRING;
1049 case STUN_ATTR_BANDWIDTH:
1050 return STUN_VALUE_UINT32;
1051 case STUN_ATTR_DESTINATION_ADDRESS:
1052 return STUN_VALUE_ADDRESS;
1053 case STUN_ATTR_SOURCE_ADDRESS2:
1054 return STUN_VALUE_ADDRESS;
1055 case STUN_ATTR_DATA:
1056 return STUN_VALUE_BYTE_STRING;
1057 case STUN_ATTR_OPTIONS:
1058 return STUN_VALUE_UINT32;
1059 default:
1060 return StunMessage::GetAttributeValueType(type);
1061 }
1062}
1063
1064StunMessage* RelayMessage::CreateNew() const {
1065 return new RelayMessage();
1066}
1067
1068StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1069 switch (type) {
1070 case STUN_ATTR_CHANNEL_NUMBER:
1071 return STUN_VALUE_UINT32;
1072 case STUN_ATTR_TURN_LIFETIME:
1073 return STUN_VALUE_UINT32;
1074 case STUN_ATTR_XOR_PEER_ADDRESS:
1075 return STUN_VALUE_XOR_ADDRESS;
1076 case STUN_ATTR_DATA:
1077 return STUN_VALUE_BYTE_STRING;
1078 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1079 return STUN_VALUE_XOR_ADDRESS;
1080 case STUN_ATTR_EVEN_PORT:
1081 return STUN_VALUE_BYTE_STRING;
1082 case STUN_ATTR_REQUESTED_TRANSPORT:
1083 return STUN_VALUE_UINT32;
1084 case STUN_ATTR_DONT_FRAGMENT:
1085 return STUN_VALUE_BYTE_STRING;
1086 case STUN_ATTR_RESERVATION_TOKEN:
1087 return STUN_VALUE_BYTE_STRING;
1088 default:
1089 return StunMessage::GetAttributeValueType(type);
1090 }
1091}
1092
1093StunMessage* TurnMessage::CreateNew() const {
1094 return new TurnMessage();
1095}
1096
1097StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1098 switch (type) {
1099 case STUN_ATTR_PRIORITY:
1100 case STUN_ATTR_NETWORK_INFO:
1101 case STUN_ATTR_NOMINATION:
1102 return STUN_VALUE_UINT32;
1103 case STUN_ATTR_USE_CANDIDATE:
1104 return STUN_VALUE_BYTE_STRING;
1105 case STUN_ATTR_ICE_CONTROLLED:
1106 return STUN_VALUE_UINT64;
1107 case STUN_ATTR_ICE_CONTROLLING:
1108 return STUN_VALUE_UINT64;
1109 default:
1110 return StunMessage::GetAttributeValueType(type);
1111 }
1112}
1113
1114StunMessage* IceMessage::CreateNew() const {
1115 return new IceMessage();
1116}
1117
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001118} // namespace cricket