blob: 38990f9b904a757788bad0e066fd4d281a2319c2 [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "p2p/base/stun.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000012
13#include <string.h>
14
Yves Gerey665174f2018-06-19 15:03:05 +020015#include <algorithm>
kwiberg3ec46792016-04-27 07:22:53 -070016#include <memory>
Steve Anton6c38cc72017-11-29 10:25:58 -080017#include <utility>
kwiberg3ec46792016-04-27 07:22:53 -070018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/byteorder.h"
20#include "rtc_base/checks.h"
21#include "rtc_base/crc32.h"
22#include "rtc_base/logging.h"
23#include "rtc_base/messagedigest.h"
24#include "rtc_base/ptr_util.h"
25#include "rtc_base/stringencode.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000026
jbauchf1f87202016-03-30 06:43:37 -070027using rtc::ByteBufferReader;
28using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000029
30namespace cricket {
31
32const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
33const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
34const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
35const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
36const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
37const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
38const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
39const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
40const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
41const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
42const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
43
Yves Gerey665174f2018-06-19 15:03:05 +020044const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000045const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020046const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000047
48// StunMessage
49
50StunMessage::StunMessage()
51 : type_(0),
52 length_(0),
Jonas Oreland7ca63112018-02-27 08:45:13 +010053 transaction_id_(EMPTY_TRANSACTION_ID),
54 stun_magic_cookie_(kStunMagicCookie) {
nisseede5da42017-01-12 05:15:36 -080055 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000056}
57
Steve Antonca7d54e2017-10-25 14:42:51 -070058StunMessage::~StunMessage() = default;
59
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000060bool StunMessage::IsLegacy() const {
61 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
62 return true;
nisseede5da42017-01-12 05:15:36 -080063 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000064 return false;
65}
66
67bool StunMessage::SetTransactionID(const std::string& str) {
68 if (!IsValidTransactionId(str)) {
69 return false;
70 }
71 transaction_id_ = str;
72 return true;
73}
74
Jonas Oreland16ccef72018-03-27 09:02:43 +020075static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +020076 return (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) {
Yves Gerey665174f2018-06-19 15:03:05 +0200101 if ((*it)->type() == type) {
102 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100103 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.
Yves Gerey665174f2018-06-19 15:03:05 +0200164bool StunMessage::ValidateMessageIntegrity(const char* data,
165 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 const std::string& password) {
167 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700168 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000169 return false;
170 }
171
172 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200173 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000174 if (size != (msg_length + kStunHeaderSize)) {
175 return false;
176 }
177
178 // Finding Message Integrity attribute in stun message.
179 size_t current_pos = kStunHeaderSize;
180 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700181 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200182 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000183 // Getting attribute type and length.
184 attr_type = rtc::GetBE16(&data[current_pos]);
185 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
186
187 // If M-I, sanity check it, and break out.
188 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
189 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700190 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
191 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000192 return false;
193 }
194 has_message_integrity_attr = true;
195 break;
196 }
197
198 // Otherwise, skip to the next attribute.
199 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
200 if ((attr_length % 4) != 0) {
201 current_pos += (4 - (attr_length % 4));
202 }
203 }
204
205 if (!has_message_integrity_attr) {
206 return false;
207 }
208
209 // Getting length of the message to calculate Message Integrity.
210 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700211 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000212 memcpy(temp_data.get(), data, current_pos);
213 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
214 // Stun message has other attributes after message integrity.
215 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200216 size_t extra_offset =
217 size - (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000218 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
219
220 // Writing new length of the STUN message @ Message Length in temp buffer.
221 // 0 1 2 3
222 // 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
223 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
224 // |0 0| STUN Message Type | Message Length |
225 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200226 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000227 }
228
229 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200230 size_t ret =
231 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
232 temp_data.get(), mi_pos, 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.
Yves Gerey665174f2018-06-19 15:03:05 +0200238 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000239 sizeof(hmac)) == 0;
240}
241
242bool StunMessage::AddMessageIntegrity(const std::string& password) {
243 return AddMessageIntegrity(password.c_str(), password.size());
244}
245
Yves Gerey665174f2018-06-19 15:03:05 +0200246bool StunMessage::AddMessageIntegrity(const char* key, size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000247 // 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];
Yves Gerey665174f2018-06-19 15:03:05 +0200262 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
263 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800264 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000265 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100266 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200267 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000268 return false;
269 }
270
271 // Insert correct HMAC into the attribute.
272 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
273 return true;
274}
275
276// Verifies a message is in fact a STUN message, by performing the checks
277// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
278// in section 15.5.
279bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
280 // Check the message length.
281 size_t fingerprint_attr_size =
282 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
283 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
284 return false;
285
286 // Skip the rest if the magic cookie isn't present.
287 const char* magic_cookie =
288 data + kStunTransactionIdOffset - kStunMagicCookieLength;
289 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
290 return false;
291
292 // Check the fingerprint type and length.
293 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
294 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200295 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000296 StunUInt32Attribute::SIZE)
297 return false;
298
299 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200300 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000301 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
302 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200303 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000304}
305
306bool StunMessage::AddFingerprint() {
307 // Add the attribute with a dummy value. Since this is a known attribute,
308 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700309 auto fingerprint_attr_ptr =
310 rtc::MakeUnique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700311 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700312 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000313
314 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700315 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000316 if (!Write(&buf))
317 return false;
318
319 int msg_len_for_crc32 = static_cast<int>(
320 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200321 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000322
323 // Insert the correct CRC-32, XORed with a constant, into the attribute.
324 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
325 return true;
326}
327
jbauchf1f87202016-03-30 06:43:37 -0700328bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000329 if (!buf->ReadUInt16(&type_))
330 return false;
331
332 if (type_ & 0x8000) {
333 // RTP and RTCP set the MSB of first byte, since first two bits are version,
334 // and version is always 2 (10). If set, this is not a STUN packet.
335 return false;
336 }
337
338 if (!buf->ReadUInt16(&length_))
339 return false;
340
341 std::string magic_cookie;
342 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
343 return false;
344
345 std::string transaction_id;
346 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
347 return false;
348
Peter Boström0c4e06b2015-10-07 12:23:21 +0200349 uint32_t magic_cookie_int =
350 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
352 // If magic cookie is invalid it means that the peer implements
353 // RFC3489 instead of RFC5389.
354 transaction_id.insert(0, magic_cookie);
355 }
nisseede5da42017-01-12 05:15:36 -0800356 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000357 transaction_id_ = transaction_id;
358
359 if (length_ != buf->Length())
360 return false;
361
zsteinad94c4c2017-03-06 13:36:05 -0800362 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000363
364 size_t rest = buf->Length() - length_;
365 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200366 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000367 if (!buf->ReadUInt16(&attr_type))
368 return false;
369 if (!buf->ReadUInt16(&attr_length))
370 return false;
371
Honghai Zhang3e024302016-09-22 09:52:16 -0700372 std::unique_ptr<StunAttribute> attr(
373 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000374 if (!attr) {
375 // Skip any unknown or malformed attributes.
376 if ((attr_length % 4) != 0) {
377 attr_length += (4 - (attr_length % 4));
378 }
379 if (!buf->Consume(attr_length))
380 return false;
381 } else {
382 if (!attr->Read(buf))
383 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800384 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000385 }
386 }
387
nisseede5da42017-01-12 05:15:36 -0800388 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000389 return true;
390}
391
jbauchf1f87202016-03-30 06:43:37 -0700392bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000393 buf->WriteUInt16(type_);
394 buf->WriteUInt16(length_);
395 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100396 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000397 buf->WriteString(transaction_id_);
398
zsteinad94c4c2017-03-06 13:36:05 -0800399 for (const auto& attr : attrs_) {
400 buf->WriteUInt16(attr->type());
401 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
402 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000403 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800404 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000405 }
406
407 return true;
408}
409
Steve Antonca7d54e2017-10-25 14:42:51 -0700410StunMessage* StunMessage::CreateNew() const {
411 return new StunMessage();
412}
413
Jonas Oreland7ca63112018-02-27 08:45:13 +0100414void StunMessage::SetStunMagicCookie(uint32_t val) {
415 stun_magic_cookie_ = val;
416}
417
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000418StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
419 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200420 case STUN_ATTR_MAPPED_ADDRESS:
421 return STUN_VALUE_ADDRESS;
422 case STUN_ATTR_USERNAME:
423 return STUN_VALUE_BYTE_STRING;
424 case STUN_ATTR_MESSAGE_INTEGRITY:
425 return STUN_VALUE_BYTE_STRING;
426 case STUN_ATTR_ERROR_CODE:
427 return STUN_VALUE_ERROR_CODE;
428 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
429 return STUN_VALUE_UINT16_LIST;
430 case STUN_ATTR_REALM:
431 return STUN_VALUE_BYTE_STRING;
432 case STUN_ATTR_NONCE:
433 return STUN_VALUE_BYTE_STRING;
434 case STUN_ATTR_XOR_MAPPED_ADDRESS:
435 return STUN_VALUE_XOR_ADDRESS;
436 case STUN_ATTR_SOFTWARE:
437 return STUN_VALUE_BYTE_STRING;
438 case STUN_ATTR_ALTERNATE_SERVER:
439 return STUN_VALUE_ADDRESS;
440 case STUN_ATTR_FINGERPRINT:
441 return STUN_VALUE_UINT32;
442 case STUN_ATTR_ORIGIN:
443 return STUN_VALUE_BYTE_STRING;
444 case STUN_ATTR_RETRANSMIT_COUNT:
445 return STUN_VALUE_UINT32;
446 default:
447 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000448 }
449}
450
451StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
452 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200453 if (value_type != STUN_VALUE_UNKNOWN) {
454 return StunAttribute::Create(value_type, type,
455 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200456 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200457 // Read unknown attributes as STUN_VALUE_BYTE_STRING
458 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
459 static_cast<uint16_t>(length), this);
460 } else {
461 return NULL;
462 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000463}
464
465const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800466 for (const auto& attr : attrs_) {
467 if (attr->type() == type) {
468 return attr.get();
469 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000470 }
471 return NULL;
472}
473
474bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
475 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200476 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000477}
478
479// StunAttribute
480
Peter Boström0c4e06b2015-10-07 12:23:21 +0200481StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200482 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000483
jbauchf1f87202016-03-30 06:43:37 -0700484void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000485 int remainder = length_ % 4;
486 if (remainder > 0) {
487 buf->Consume(4 - remainder);
488 }
489}
490
jbauchf1f87202016-03-30 06:43:37 -0700491void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000492 int remainder = length_ % 4;
493 if (remainder > 0) {
494 char zeroes[4] = {0};
495 buf->WriteBytes(zeroes, 4 - remainder);
496 }
497}
498
499StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200500 uint16_t type,
501 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000502 StunMessage* owner) {
503 switch (value_type) {
504 case STUN_VALUE_ADDRESS:
505 return new StunAddressAttribute(type, length);
506 case STUN_VALUE_XOR_ADDRESS:
507 return new StunXorAddressAttribute(type, length, owner);
508 case STUN_VALUE_UINT32:
509 return new StunUInt32Attribute(type);
510 case STUN_VALUE_UINT64:
511 return new StunUInt64Attribute(type);
512 case STUN_VALUE_BYTE_STRING:
513 return new StunByteStringAttribute(type, length);
514 case STUN_VALUE_ERROR_CODE:
515 return new StunErrorCodeAttribute(type, length);
516 case STUN_VALUE_UINT16_LIST:
517 return new StunUInt16ListAttribute(type, length);
518 default:
519 return NULL;
520 }
521}
522
zsteinf42cc9d2017-03-27 16:17:19 -0700523std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
524 uint16_t type) {
525 return rtc::MakeUnique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000526}
527
zsteinf42cc9d2017-03-27 16:17:19 -0700528std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
529 uint16_t type) {
530 return rtc::MakeUnique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000531}
532
zsteinf42cc9d2017-03-27 16:17:19 -0700533std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
534 uint16_t type) {
535 return rtc::MakeUnique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000536}
537
zsteinf42cc9d2017-03-27 16:17:19 -0700538std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
539 uint16_t type) {
540 return rtc::MakeUnique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000541}
542
zsteinf42cc9d2017-03-27 16:17:19 -0700543std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
544 uint16_t type) {
545 return rtc::MakeUnique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000546}
547
zsteinf42cc9d2017-03-27 16:17:19 -0700548std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
549 return rtc::MakeUnique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000550 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
551}
552
zsteinf42cc9d2017-03-27 16:17:19 -0700553std::unique_ptr<StunUInt16ListAttribute>
554StunAttribute::CreateUnknownAttributes() {
555 return rtc::MakeUnique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
556 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000557}
558
Peter Boström0c4e06b2015-10-07 12:23:21 +0200559StunAddressAttribute::StunAddressAttribute(uint16_t type,
560 const rtc::SocketAddress& addr)
561 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000562 SetAddress(addr);
563}
564
Peter Boström0c4e06b2015-10-07 12:23:21 +0200565StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200566 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000567
Steve Antonca7d54e2017-10-25 14:42:51 -0700568StunAttributeValueType StunAddressAttribute::value_type() const {
569 return STUN_VALUE_ADDRESS;
570}
571
jbauchf1f87202016-03-30 06:43:37 -0700572bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200573 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574 if (!buf->ReadUInt8(&dummy))
575 return false;
576
Peter Boström0c4e06b2015-10-07 12:23:21 +0200577 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000578 if (!buf->ReadUInt8(&stun_family)) {
579 return false;
580 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200581 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000582 if (!buf->ReadUInt16(&port))
583 return false;
584 if (stun_family == STUN_ADDRESS_IPV4) {
585 in_addr v4addr;
586 if (length() != SIZE_IP4) {
587 return false;
588 }
589 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
590 return false;
591 }
592 rtc::IPAddress ipaddr(v4addr);
593 SetAddress(rtc::SocketAddress(ipaddr, port));
594 } else if (stun_family == STUN_ADDRESS_IPV6) {
595 in6_addr v6addr;
596 if (length() != SIZE_IP6) {
597 return false;
598 }
599 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
600 return false;
601 }
602 rtc::IPAddress ipaddr(v6addr);
603 SetAddress(rtc::SocketAddress(ipaddr, port));
604 } else {
605 return false;
606 }
607 return true;
608}
609
jbauchf1f87202016-03-30 06:43:37 -0700610bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000611 StunAddressFamily address_family = family();
612 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100613 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000614 return false;
615 }
616 buf->WriteUInt8(0);
617 buf->WriteUInt8(address_family);
618 buf->WriteUInt16(address_.port());
619 switch (address_.family()) {
620 case AF_INET: {
621 in_addr v4addr = address_.ipaddr().ipv4_address();
622 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
623 break;
624 }
625 case AF_INET6: {
626 in6_addr v6addr = address_.ipaddr().ipv6_address();
627 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
628 break;
629 }
630 }
631 return true;
632}
633
Peter Boström0c4e06b2015-10-07 12:23:21 +0200634StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
635 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200636 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000637
Peter Boström0c4e06b2015-10-07 12:23:21 +0200638StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
639 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000640 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200641 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000642
Steve Antonca7d54e2017-10-25 14:42:51 -0700643StunAttributeValueType StunXorAddressAttribute::value_type() const {
644 return STUN_VALUE_XOR_ADDRESS;
645}
646
647void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
648 owner_ = owner;
649}
650
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000651rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
652 if (owner_) {
653 rtc::IPAddress ip = ipaddr();
654 switch (ip.family()) {
655 case AF_INET: {
656 in_addr v4addr = ip.ipv4_address();
657 v4addr.s_addr =
658 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
659 return rtc::IPAddress(v4addr);
660 }
661 case AF_INET6: {
662 in6_addr v6addr = ip.ipv6_address();
663 const std::string& transaction_id = owner_->transaction_id();
664 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200665 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000666 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
667 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200668 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000669 // Transaction ID is in network byte order, but magic cookie
670 // is stored in host byte order.
671 ip_as_ints[0] =
672 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
673 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
674 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
675 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
676 return rtc::IPAddress(v6addr);
677 }
678 break;
679 }
680 }
681 }
682 // Invalid ip family or transaction ID, or missing owner.
683 // Return an AF_UNSPEC address.
684 return rtc::IPAddress();
685}
686
jbauchf1f87202016-03-30 06:43:37 -0700687bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000688 if (!StunAddressAttribute::Read(buf))
689 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200690 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691 rtc::IPAddress xored_ip = GetXoredIP();
692 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
693 return true;
694}
695
jbauchf1f87202016-03-30 06:43:37 -0700696bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000697 StunAddressFamily address_family = family();
698 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100699 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000700 return false;
701 }
702 rtc::IPAddress xored_ip = GetXoredIP();
703 if (xored_ip.family() == AF_UNSPEC) {
704 return false;
705 }
706 buf->WriteUInt8(0);
707 buf->WriteUInt8(family());
708 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
709 switch (xored_ip.family()) {
710 case AF_INET: {
711 in_addr v4addr = xored_ip.ipv4_address();
712 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
713 break;
714 }
715 case AF_INET6: {
716 in6_addr v6addr = xored_ip.ipv6_address();
717 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
718 break;
719 }
720 }
721 return true;
722}
723
Peter Boström0c4e06b2015-10-07 12:23:21 +0200724StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200725 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000726
Peter Boström0c4e06b2015-10-07 12:23:21 +0200727StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200728 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000729
Steve Antonca7d54e2017-10-25 14:42:51 -0700730StunAttributeValueType StunUInt32Attribute::value_type() const {
731 return STUN_VALUE_UINT32;
732}
733
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000734bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800735 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000736 return static_cast<bool>((bits_ >> index) & 0x1);
737}
738
739void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800740 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000741 bits_ &= ~(1 << index);
742 bits_ |= value ? (1 << index) : 0;
743}
744
jbauchf1f87202016-03-30 06:43:37 -0700745bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000746 if (length() != SIZE || !buf->ReadUInt32(&bits_))
747 return false;
748 return true;
749}
750
jbauchf1f87202016-03-30 06:43:37 -0700751bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000752 buf->WriteUInt32(bits_);
753 return true;
754}
755
Peter Boström0c4e06b2015-10-07 12:23:21 +0200756StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200757 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000758
Peter Boström0c4e06b2015-10-07 12:23:21 +0200759StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200760 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000761
Steve Antonca7d54e2017-10-25 14:42:51 -0700762StunAttributeValueType StunUInt64Attribute::value_type() const {
763 return STUN_VALUE_UINT64;
764}
765
jbauchf1f87202016-03-30 06:43:37 -0700766bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000767 if (length() != SIZE || !buf->ReadUInt64(&bits_))
768 return false;
769 return true;
770}
771
jbauchf1f87202016-03-30 06:43:37 -0700772bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000773 buf->WriteUInt64(bits_);
774 return true;
775}
776
Peter Boström0c4e06b2015-10-07 12:23:21 +0200777StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200778 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000779
Peter Boström0c4e06b2015-10-07 12:23:21 +0200780StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000781 const std::string& str)
782 : StunAttribute(type, 0), bytes_(NULL) {
783 CopyBytes(str.c_str(), str.size());
784}
785
Peter Boström0c4e06b2015-10-07 12:23:21 +0200786StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000787 const void* bytes,
788 size_t length)
789 : StunAttribute(type, 0), bytes_(NULL) {
790 CopyBytes(bytes, length);
791}
792
Peter Boström0c4e06b2015-10-07 12:23:21 +0200793StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200794 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000795
796StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +0200797 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000798}
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) {
Yves Gerey665174f2018-06-19 15:03:05 +0200843 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000844 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)
Yves Gerey665174f2018-06-19 15:03:05 +0200859 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000860
Yves Gerey665174f2018-06-19 15:03:05 +0200861StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000862
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];
Yves Gerey665174f2018-06-19 15:03:05 +02001001 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1002 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001003 if (size == 0) {
1004 return false;
1005 }
1006
1007 *hash = std::string(digest, size);
1008 return true;
1009}
1010
Jonas Oreland202994c2017-12-18 12:10:43 +01001011std::unique_ptr<StunAttribute> CopyStunAttribute(
1012 const StunAttribute& attribute,
1013 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1014 ByteBufferWriter tmpBuffer;
1015 if (tmp_buffer_ptr == nullptr) {
1016 tmp_buffer_ptr = &tmpBuffer;
1017 }
1018
Yves Gerey665174f2018-06-19 15:03:05 +02001019 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1020 attribute.value_type(), attribute.type(),
1021 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001022
1023 if (!copy) {
1024 return nullptr;
1025 }
1026 tmp_buffer_ptr->Clear();
1027 if (!attribute.Write(tmp_buffer_ptr)) {
1028 return nullptr;
1029 }
1030 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1031 if (!copy->Read(&reader)) {
1032 return nullptr;
1033 }
1034
1035 return copy;
1036}
1037
Steve Antonca7d54e2017-10-25 14:42:51 -07001038StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1039 switch (type) {
1040 case STUN_ATTR_LIFETIME:
1041 return STUN_VALUE_UINT32;
1042 case STUN_ATTR_MAGIC_COOKIE:
1043 return STUN_VALUE_BYTE_STRING;
1044 case STUN_ATTR_BANDWIDTH:
1045 return STUN_VALUE_UINT32;
1046 case STUN_ATTR_DESTINATION_ADDRESS:
1047 return STUN_VALUE_ADDRESS;
1048 case STUN_ATTR_SOURCE_ADDRESS2:
1049 return STUN_VALUE_ADDRESS;
1050 case STUN_ATTR_DATA:
1051 return STUN_VALUE_BYTE_STRING;
1052 case STUN_ATTR_OPTIONS:
1053 return STUN_VALUE_UINT32;
1054 default:
1055 return StunMessage::GetAttributeValueType(type);
1056 }
1057}
1058
1059StunMessage* RelayMessage::CreateNew() const {
1060 return new RelayMessage();
1061}
1062
1063StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1064 switch (type) {
1065 case STUN_ATTR_CHANNEL_NUMBER:
1066 return STUN_VALUE_UINT32;
1067 case STUN_ATTR_TURN_LIFETIME:
1068 return STUN_VALUE_UINT32;
1069 case STUN_ATTR_XOR_PEER_ADDRESS:
1070 return STUN_VALUE_XOR_ADDRESS;
1071 case STUN_ATTR_DATA:
1072 return STUN_VALUE_BYTE_STRING;
1073 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1074 return STUN_VALUE_XOR_ADDRESS;
1075 case STUN_ATTR_EVEN_PORT:
1076 return STUN_VALUE_BYTE_STRING;
1077 case STUN_ATTR_REQUESTED_TRANSPORT:
1078 return STUN_VALUE_UINT32;
1079 case STUN_ATTR_DONT_FRAGMENT:
1080 return STUN_VALUE_BYTE_STRING;
1081 case STUN_ATTR_RESERVATION_TOKEN:
1082 return STUN_VALUE_BYTE_STRING;
1083 default:
1084 return StunMessage::GetAttributeValueType(type);
1085 }
1086}
1087
1088StunMessage* TurnMessage::CreateNew() const {
1089 return new TurnMessage();
1090}
1091
1092StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1093 switch (type) {
1094 case STUN_ATTR_PRIORITY:
1095 case STUN_ATTR_NETWORK_INFO:
1096 case STUN_ATTR_NOMINATION:
1097 return STUN_VALUE_UINT32;
1098 case STUN_ATTR_USE_CANDIDATE:
1099 return STUN_VALUE_BYTE_STRING;
1100 case STUN_ATTR_ICE_CONTROLLED:
1101 return STUN_VALUE_UINT64;
1102 case STUN_ATTR_ICE_CONTROLLING:
1103 return STUN_VALUE_UINT64;
1104 default:
1105 return StunMessage::GetAttributeValueType(type);
1106 }
1107}
1108
1109StunMessage* IceMessage::CreateNew() const {
1110 return new IceMessage();
1111}
1112
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001113} // namespace cricket