blob: 88097565780c47bc540e2243b4d41c1ee0ad1120 [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
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/checks.h"
21#include "rtc_base/crc32.h"
22#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "rtc_base/message_digest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024
jbauchf1f87202016-03-30 06:43:37 -070025using rtc::ByteBufferReader;
26using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000027
Zach Stein92c42892018-11-28 11:38:52 -080028namespace {
29
30uint32_t ReduceTransactionId(const std::string& transaction_id) {
31 RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
32 transaction_id.length() ==
33 cricket::kStunLegacyTransactionIdLength);
Zach Steinff71a492018-12-07 11:25:12 -080034 ByteBufferReader reader(transaction_id.c_str(), transaction_id.length(),
35 rtc::ByteBuffer::ORDER_NETWORK);
Zach Stein92c42892018-11-28 11:38:52 -080036 uint32_t result = 0;
Zach Steinff71a492018-12-07 11:25:12 -080037 uint32_t next;
38 while (reader.ReadUInt32(&next)) {
39 result ^= next;
Zach Stein92c42892018-11-28 11:38:52 -080040 }
41 return result;
42}
43
44} // namespace
45
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000046namespace cricket {
47
48const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
49const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
50const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
51const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
52const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
53const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
54const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
55const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
56const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
57const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
58const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
59
Yves Gerey665174f2018-06-19 15:03:05 +020060const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000061const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020062const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
Eldar Relloda13ea22019-06-01 12:23:43 +030063const int SERVER_NOT_REACHABLE_ERROR = 701;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000064
65// StunMessage
66
67StunMessage::StunMessage()
68 : type_(0),
69 length_(0),
Jonas Oreland7ca63112018-02-27 08:45:13 +010070 transaction_id_(EMPTY_TRANSACTION_ID),
71 stun_magic_cookie_(kStunMagicCookie) {
nisseede5da42017-01-12 05:15:36 -080072 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000073}
74
Steve Antonca7d54e2017-10-25 14:42:51 -070075StunMessage::~StunMessage() = default;
76
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000077bool StunMessage::IsLegacy() const {
78 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
79 return true;
nisseede5da42017-01-12 05:15:36 -080080 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000081 return false;
82}
83
84bool StunMessage::SetTransactionID(const std::string& str) {
85 if (!IsValidTransactionId(str)) {
86 return false;
87 }
88 transaction_id_ = str;
Zach Stein92c42892018-11-28 11:38:52 -080089 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000090 return true;
91}
92
Jonas Oreland16ccef72018-03-27 09:02:43 +020093static bool DesignatedExpertRange(int attr_type) {
Yves Gerey665174f2018-06-19 15:03:05 +020094 return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
95 (attr_type >= 0xC000 && attr_type <= 0xFFFF);
Jonas Orelandbdcee282017-10-10 14:01:40 +020096}
97
zsteinf42cc9d2017-03-27 16:17:19 -070098void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020099 // Fail any attributes that aren't valid for this type of message,
Jonas Oreland16ccef72018-03-27 09:02:43 +0200100 // but allow any type for the range that in the RFC is reserved for
101 // the "designated experts".
102 if (!DesignatedExpertRange(attr->type())) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200103 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
104 }
nissecc99bc22017-02-02 01:31:30 -0800105
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000106 attr->SetOwner(this);
107 size_t attr_length = attr->length();
108 if (attr_length % 4 != 0) {
109 attr_length += (4 - (attr_length % 4));
110 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200111 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -0700112
113 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000114}
115
Jonas Oreland202994c2017-12-18 12:10:43 +0100116std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
117 std::unique_ptr<StunAttribute> attribute;
118 for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
Yves Gerey665174f2018-06-19 15:03:05 +0200119 if ((*it)->type() == type) {
120 attribute = std::move(*it);
Jonas Oreland202994c2017-12-18 12:10:43 +0100121 attrs_.erase(std::next(it).base());
122 break;
123 }
124 }
125 if (attribute) {
126 attribute->SetOwner(nullptr);
127 size_t attr_length = attribute->length();
128 if (attr_length % 4 != 0) {
129 attr_length += (4 - (attr_length % 4));
130 }
131 length_ -= static_cast<uint16_t>(attr_length + 4);
132 }
133 return attribute;
134}
135
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000136const StunAddressAttribute* StunMessage::GetAddress(int type) const {
137 switch (type) {
138 case STUN_ATTR_MAPPED_ADDRESS: {
139 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
140 // missing.
141 const StunAttribute* mapped_address =
142 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
143 if (!mapped_address)
144 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
145 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
146 }
147
148 default:
149 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
150 }
151}
152
153const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
154 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
155}
156
157const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
158 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
159}
160
161const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
162 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
163}
164
165const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
166 return static_cast<const StunErrorCodeAttribute*>(
167 GetAttribute(STUN_ATTR_ERROR_CODE));
168}
169
deadbeef996fc6b2017-04-26 09:21:22 -0700170int StunMessage::GetErrorCodeValue() const {
171 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
172 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
173}
174
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000175const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
176 return static_cast<const StunUInt16ListAttribute*>(
177 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
178}
179
180// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
181// procedure outlined in RFC 5389, section 15.4.
Yves Gerey665174f2018-06-19 15:03:05 +0200182bool StunMessage::ValidateMessageIntegrity(const char* data,
183 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000184 const std::string& password) {
185 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700186 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000187 return false;
188 }
189
190 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200191 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000192 if (size != (msg_length + kStunHeaderSize)) {
193 return false;
194 }
195
196 // Finding Message Integrity attribute in stun message.
197 size_t current_pos = kStunHeaderSize;
198 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700199 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200200 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000201 // Getting attribute type and length.
202 attr_type = rtc::GetBE16(&data[current_pos]);
203 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
204
205 // If M-I, sanity check it, and break out.
206 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
207 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700208 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
209 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000210 return false;
211 }
212 has_message_integrity_attr = true;
213 break;
214 }
215
216 // Otherwise, skip to the next attribute.
217 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
218 if ((attr_length % 4) != 0) {
219 current_pos += (4 - (attr_length % 4));
220 }
221 }
222
223 if (!has_message_integrity_attr) {
224 return false;
225 }
226
227 // Getting length of the message to calculate Message Integrity.
228 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700229 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000230 memcpy(temp_data.get(), data, current_pos);
231 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
232 // Stun message has other attributes after message integrity.
233 // Adjust the length parameter in stun message to calculate HMAC.
Yves Gerey665174f2018-06-19 15:03:05 +0200234 size_t extra_offset =
235 size - (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000236 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
237
238 // Writing new length of the STUN message @ Message Length in temp buffer.
239 // 0 1 2 3
240 // 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
241 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
242 // |0 0| STUN Message Type | Message Length |
243 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200244 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000245 }
246
247 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200248 size_t ret =
249 rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
250 temp_data.get(), mi_pos, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800251 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000252 if (ret != sizeof(hmac))
253 return false;
254
255 // Comparing the calculated HMAC with the one present in the message.
Yves Gerey665174f2018-06-19 15:03:05 +0200256 return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000257 sizeof(hmac)) == 0;
258}
259
260bool StunMessage::AddMessageIntegrity(const std::string& password) {
261 return AddMessageIntegrity(password.c_str(), password.size());
262}
263
Yves Gerey665174f2018-06-19 15:03:05 +0200264bool StunMessage::AddMessageIntegrity(const char* key, size_t keylen) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000265 // Add the attribute with a dummy value. Since this is a known attribute, it
266 // can't fail.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200267 auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
zsteinf42cc9d2017-03-27 16:17:19 -0700268 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
269 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
270 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000271
272 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700273 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000274 if (!Write(&buf))
275 return false;
276
277 int msg_len_for_hmac = static_cast<int>(
278 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
279 char hmac[kStunMessageIntegritySize];
Yves Gerey665174f2018-06-19 15:03:05 +0200280 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, key, keylen, buf.Data(),
281 msg_len_for_hmac, hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800282 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000283 if (ret != sizeof(hmac)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100284 RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
Jonas Olssond7d762d2018-03-28 09:47:51 +0200285 "has dummy value.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000286 return false;
287 }
288
289 // Insert correct HMAC into the attribute.
290 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
291 return true;
292}
293
294// Verifies a message is in fact a STUN message, by performing the checks
295// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
296// in section 15.5.
297bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
298 // Check the message length.
299 size_t fingerprint_attr_size =
300 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
301 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
302 return false;
303
304 // Skip the rest if the magic cookie isn't present.
305 const char* magic_cookie =
306 data + kStunTransactionIdOffset - kStunMagicCookieLength;
307 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
308 return false;
309
310 // Check the fingerprint type and length.
311 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
312 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200313 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000314 StunUInt32Attribute::SIZE)
315 return false;
316
317 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200318 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000319 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
320 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
Yves Gerey665174f2018-06-19 15:03:05 +0200321 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000322}
323
324bool StunMessage::AddFingerprint() {
325 // Add the attribute with a dummy value. Since this is a known attribute,
326 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700327 auto fingerprint_attr_ptr =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200328 std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
Steve Antonca7d54e2017-10-25 14:42:51 -0700329 auto* fingerprint_attr = fingerprint_attr_ptr.get();
zsteinf42cc9d2017-03-27 16:17:19 -0700330 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000331
332 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700333 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000334 if (!Write(&buf))
335 return false;
336
337 int msg_len_for_crc32 = static_cast<int>(
338 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200339 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000340
341 // Insert the correct CRC-32, XORed with a constant, into the attribute.
342 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
343 return true;
344}
345
jbauchf1f87202016-03-30 06:43:37 -0700346bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000347 if (!buf->ReadUInt16(&type_))
348 return false;
349
350 if (type_ & 0x8000) {
351 // RTP and RTCP set the MSB of first byte, since first two bits are version,
352 // and version is always 2 (10). If set, this is not a STUN packet.
353 return false;
354 }
355
356 if (!buf->ReadUInt16(&length_))
357 return false;
358
359 std::string magic_cookie;
360 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
361 return false;
362
363 std::string transaction_id;
364 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
365 return false;
366
Andrew Royes154d8392019-03-14 10:38:31 -0700367 uint32_t magic_cookie_int;
368 static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
369 "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
370 std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
372 // If magic cookie is invalid it means that the peer implements
373 // RFC3489 instead of RFC5389.
374 transaction_id.insert(0, magic_cookie);
375 }
nisseede5da42017-01-12 05:15:36 -0800376 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000377 transaction_id_ = transaction_id;
Zach Stein92c42892018-11-28 11:38:52 -0800378 reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000379
380 if (length_ != buf->Length())
381 return false;
382
zsteinad94c4c2017-03-06 13:36:05 -0800383 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000384
385 size_t rest = buf->Length() - length_;
386 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200387 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000388 if (!buf->ReadUInt16(&attr_type))
389 return false;
390 if (!buf->ReadUInt16(&attr_length))
391 return false;
392
Honghai Zhang3e024302016-09-22 09:52:16 -0700393 std::unique_ptr<StunAttribute> attr(
394 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000395 if (!attr) {
396 // Skip any unknown or malformed attributes.
397 if ((attr_length % 4) != 0) {
398 attr_length += (4 - (attr_length % 4));
399 }
400 if (!buf->Consume(attr_length))
401 return false;
402 } else {
403 if (!attr->Read(buf))
404 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800405 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000406 }
407 }
408
nisseede5da42017-01-12 05:15:36 -0800409 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000410 return true;
411}
412
jbauchf1f87202016-03-30 06:43:37 -0700413bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000414 buf->WriteUInt16(type_);
415 buf->WriteUInt16(length_);
416 if (!IsLegacy())
Jonas Oreland7ca63112018-02-27 08:45:13 +0100417 buf->WriteUInt32(stun_magic_cookie_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000418 buf->WriteString(transaction_id_);
419
zsteinad94c4c2017-03-06 13:36:05 -0800420 for (const auto& attr : attrs_) {
421 buf->WriteUInt16(attr->type());
422 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
423 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000424 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800425 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000426 }
427
428 return true;
429}
430
Steve Antonca7d54e2017-10-25 14:42:51 -0700431StunMessage* StunMessage::CreateNew() const {
432 return new StunMessage();
433}
434
Jonas Oreland7ca63112018-02-27 08:45:13 +0100435void StunMessage::SetStunMagicCookie(uint32_t val) {
436 stun_magic_cookie_ = val;
437}
438
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000439StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
440 switch (type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200441 case STUN_ATTR_MAPPED_ADDRESS:
442 return STUN_VALUE_ADDRESS;
443 case STUN_ATTR_USERNAME:
444 return STUN_VALUE_BYTE_STRING;
445 case STUN_ATTR_MESSAGE_INTEGRITY:
446 return STUN_VALUE_BYTE_STRING;
447 case STUN_ATTR_ERROR_CODE:
448 return STUN_VALUE_ERROR_CODE;
449 case STUN_ATTR_UNKNOWN_ATTRIBUTES:
450 return STUN_VALUE_UINT16_LIST;
451 case STUN_ATTR_REALM:
452 return STUN_VALUE_BYTE_STRING;
453 case STUN_ATTR_NONCE:
454 return STUN_VALUE_BYTE_STRING;
455 case STUN_ATTR_XOR_MAPPED_ADDRESS:
456 return STUN_VALUE_XOR_ADDRESS;
457 case STUN_ATTR_SOFTWARE:
458 return STUN_VALUE_BYTE_STRING;
459 case STUN_ATTR_ALTERNATE_SERVER:
460 return STUN_VALUE_ADDRESS;
461 case STUN_ATTR_FINGERPRINT:
462 return STUN_VALUE_UINT32;
463 case STUN_ATTR_ORIGIN:
464 return STUN_VALUE_BYTE_STRING;
465 case STUN_ATTR_RETRANSMIT_COUNT:
466 return STUN_VALUE_UINT32;
Qingsi Wang0894f0f2019-06-18 14:11:36 -0700467 case STUN_ATTR_LAST_ICE_CHECK_RECEIVED:
468 return STUN_VALUE_BYTE_STRING;
Yves Gerey665174f2018-06-19 15:03:05 +0200469 default:
470 return STUN_VALUE_UNKNOWN;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000471 }
472}
473
474StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
475 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200476 if (value_type != STUN_VALUE_UNKNOWN) {
477 return StunAttribute::Create(value_type, type,
478 static_cast<uint16_t>(length), this);
Jonas Oreland16ccef72018-03-27 09:02:43 +0200479 } else if (DesignatedExpertRange(type)) {
Jonas Orelandbdcee282017-10-10 14:01:40 +0200480 // Read unknown attributes as STUN_VALUE_BYTE_STRING
481 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
482 static_cast<uint16_t>(length), this);
483 } else {
484 return NULL;
485 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000486}
487
488const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800489 for (const auto& attr : attrs_) {
490 if (attr->type() == type) {
491 return attr.get();
492 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000493 }
494 return NULL;
495}
496
497bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
498 return transaction_id.size() == kStunTransactionIdLength ||
Yves Gerey665174f2018-06-19 15:03:05 +0200499 transaction_id.size() == kStunLegacyTransactionIdLength;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000500}
501
502// StunAttribute
503
Peter Boström0c4e06b2015-10-07 12:23:21 +0200504StunAttribute::StunAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200505 : type_(type), length_(length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000506
jbauchf1f87202016-03-30 06:43:37 -0700507void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000508 int remainder = length_ % 4;
509 if (remainder > 0) {
510 buf->Consume(4 - remainder);
511 }
512}
513
jbauchf1f87202016-03-30 06:43:37 -0700514void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000515 int remainder = length_ % 4;
516 if (remainder > 0) {
517 char zeroes[4] = {0};
518 buf->WriteBytes(zeroes, 4 - remainder);
519 }
520}
521
522StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200523 uint16_t type,
524 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000525 StunMessage* owner) {
526 switch (value_type) {
527 case STUN_VALUE_ADDRESS:
528 return new StunAddressAttribute(type, length);
529 case STUN_VALUE_XOR_ADDRESS:
530 return new StunXorAddressAttribute(type, length, owner);
531 case STUN_VALUE_UINT32:
532 return new StunUInt32Attribute(type);
533 case STUN_VALUE_UINT64:
534 return new StunUInt64Attribute(type);
535 case STUN_VALUE_BYTE_STRING:
536 return new StunByteStringAttribute(type, length);
537 case STUN_VALUE_ERROR_CODE:
538 return new StunErrorCodeAttribute(type, length);
539 case STUN_VALUE_UINT16_LIST:
540 return new StunUInt16ListAttribute(type, length);
541 default:
542 return NULL;
543 }
544}
545
zsteinf42cc9d2017-03-27 16:17:19 -0700546std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
547 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200548 return std::make_unique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000549}
550
zsteinf42cc9d2017-03-27 16:17:19 -0700551std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
552 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200553 return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000554}
555
zsteinf42cc9d2017-03-27 16:17:19 -0700556std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
557 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200558 return std::make_unique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000559}
560
zsteinf42cc9d2017-03-27 16:17:19 -0700561std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
562 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200563 return std::make_unique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000564}
565
zsteinf42cc9d2017-03-27 16:17:19 -0700566std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
567 uint16_t type) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200568 return std::make_unique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000569}
570
zsteinf42cc9d2017-03-27 16:17:19 -0700571std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200572 return std::make_unique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000573 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
574}
575
zsteinf42cc9d2017-03-27 16:17:19 -0700576std::unique_ptr<StunUInt16ListAttribute>
577StunAttribute::CreateUnknownAttributes() {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200578 return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
579 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000580}
581
Peter Boström0c4e06b2015-10-07 12:23:21 +0200582StunAddressAttribute::StunAddressAttribute(uint16_t type,
583 const rtc::SocketAddress& addr)
584 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000585 SetAddress(addr);
586}
587
Peter Boström0c4e06b2015-10-07 12:23:21 +0200588StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200589 : StunAttribute(type, length) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000590
Steve Antonca7d54e2017-10-25 14:42:51 -0700591StunAttributeValueType StunAddressAttribute::value_type() const {
592 return STUN_VALUE_ADDRESS;
593}
594
jbauchf1f87202016-03-30 06:43:37 -0700595bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200596 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000597 if (!buf->ReadUInt8(&dummy))
598 return false;
599
Peter Boström0c4e06b2015-10-07 12:23:21 +0200600 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000601 if (!buf->ReadUInt8(&stun_family)) {
602 return false;
603 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200604 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000605 if (!buf->ReadUInt16(&port))
606 return false;
607 if (stun_family == STUN_ADDRESS_IPV4) {
608 in_addr v4addr;
609 if (length() != SIZE_IP4) {
610 return false;
611 }
612 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
613 return false;
614 }
615 rtc::IPAddress ipaddr(v4addr);
616 SetAddress(rtc::SocketAddress(ipaddr, port));
617 } else if (stun_family == STUN_ADDRESS_IPV6) {
618 in6_addr v6addr;
619 if (length() != SIZE_IP6) {
620 return false;
621 }
622 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
623 return false;
624 }
625 rtc::IPAddress ipaddr(v6addr);
626 SetAddress(rtc::SocketAddress(ipaddr, port));
627 } else {
628 return false;
629 }
630 return true;
631}
632
jbauchf1f87202016-03-30 06:43:37 -0700633bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000634 StunAddressFamily address_family = family();
635 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100636 RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000637 return false;
638 }
639 buf->WriteUInt8(0);
640 buf->WriteUInt8(address_family);
641 buf->WriteUInt16(address_.port());
642 switch (address_.family()) {
643 case AF_INET: {
644 in_addr v4addr = address_.ipaddr().ipv4_address();
645 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
646 break;
647 }
648 case AF_INET6: {
649 in6_addr v6addr = address_.ipaddr().ipv6_address();
650 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
651 break;
652 }
653 }
654 return true;
655}
656
Peter Boström0c4e06b2015-10-07 12:23:21 +0200657StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
658 const rtc::SocketAddress& addr)
Yves Gerey665174f2018-06-19 15:03:05 +0200659 : StunAddressAttribute(type, addr), owner_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000660
Peter Boström0c4e06b2015-10-07 12:23:21 +0200661StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
662 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000663 StunMessage* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200664 : StunAddressAttribute(type, length), owner_(owner) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000665
Steve Antonca7d54e2017-10-25 14:42:51 -0700666StunAttributeValueType StunXorAddressAttribute::value_type() const {
667 return STUN_VALUE_XOR_ADDRESS;
668}
669
670void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
671 owner_ = owner;
672}
673
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000674rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
675 if (owner_) {
676 rtc::IPAddress ip = ipaddr();
677 switch (ip.family()) {
678 case AF_INET: {
679 in_addr v4addr = ip.ipv4_address();
680 v4addr.s_addr =
681 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
682 return rtc::IPAddress(v4addr);
683 }
684 case AF_INET6: {
685 in6_addr v6addr = ip.ipv6_address();
686 const std::string& transaction_id = owner_->transaction_id();
687 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200688 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000689 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
690 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200691 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000692 // Transaction ID is in network byte order, but magic cookie
693 // is stored in host byte order.
694 ip_as_ints[0] =
695 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
696 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
697 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
698 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
699 return rtc::IPAddress(v6addr);
700 }
701 break;
702 }
703 }
704 }
705 // Invalid ip family or transaction ID, or missing owner.
706 // Return an AF_UNSPEC address.
707 return rtc::IPAddress();
708}
709
jbauchf1f87202016-03-30 06:43:37 -0700710bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000711 if (!StunAddressAttribute::Read(buf))
712 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200713 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000714 rtc::IPAddress xored_ip = GetXoredIP();
715 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
716 return true;
717}
718
jbauchf1f87202016-03-30 06:43:37 -0700719bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000720 StunAddressFamily address_family = family();
721 if (address_family == STUN_ADDRESS_UNDEF) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100722 RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000723 return false;
724 }
725 rtc::IPAddress xored_ip = GetXoredIP();
726 if (xored_ip.family() == AF_UNSPEC) {
727 return false;
728 }
729 buf->WriteUInt8(0);
730 buf->WriteUInt8(family());
731 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
732 switch (xored_ip.family()) {
733 case AF_INET: {
734 in_addr v4addr = xored_ip.ipv4_address();
735 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
736 break;
737 }
738 case AF_INET6: {
739 in6_addr v6addr = xored_ip.ipv6_address();
740 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
741 break;
742 }
743 }
744 return true;
745}
746
Peter Boström0c4e06b2015-10-07 12:23:21 +0200747StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200748 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000749
Peter Boström0c4e06b2015-10-07 12:23:21 +0200750StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200751 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000752
Steve Antonca7d54e2017-10-25 14:42:51 -0700753StunAttributeValueType StunUInt32Attribute::value_type() const {
754 return STUN_VALUE_UINT32;
755}
756
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000757bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800758 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000759 return static_cast<bool>((bits_ >> index) & 0x1);
760}
761
762void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800763 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000764 bits_ &= ~(1 << index);
765 bits_ |= value ? (1 << index) : 0;
766}
767
jbauchf1f87202016-03-30 06:43:37 -0700768bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000769 if (length() != SIZE || !buf->ReadUInt32(&bits_))
770 return false;
771 return true;
772}
773
jbauchf1f87202016-03-30 06:43:37 -0700774bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000775 buf->WriteUInt32(bits_);
776 return true;
777}
778
Peter Boström0c4e06b2015-10-07 12:23:21 +0200779StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
Yves Gerey665174f2018-06-19 15:03:05 +0200780 : StunAttribute(type, SIZE), bits_(value) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000781
Peter Boström0c4e06b2015-10-07 12:23:21 +0200782StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200783 : StunAttribute(type, SIZE), bits_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000784
Steve Antonca7d54e2017-10-25 14:42:51 -0700785StunAttributeValueType StunUInt64Attribute::value_type() const {
786 return STUN_VALUE_UINT64;
787}
788
jbauchf1f87202016-03-30 06:43:37 -0700789bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000790 if (length() != SIZE || !buf->ReadUInt64(&bits_))
791 return false;
792 return true;
793}
794
jbauchf1f87202016-03-30 06:43:37 -0700795bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000796 buf->WriteUInt64(bits_);
797 return true;
798}
799
Peter Boström0c4e06b2015-10-07 12:23:21 +0200800StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
Yves Gerey665174f2018-06-19 15:03:05 +0200801 : StunAttribute(type, 0), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000802
Peter Boström0c4e06b2015-10-07 12:23:21 +0200803StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000804 const std::string& str)
805 : StunAttribute(type, 0), bytes_(NULL) {
806 CopyBytes(str.c_str(), str.size());
807}
808
Peter Boström0c4e06b2015-10-07 12:23:21 +0200809StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000810 const void* bytes,
811 size_t length)
812 : StunAttribute(type, 0), bytes_(NULL) {
813 CopyBytes(bytes, length);
814}
815
Peter Boström0c4e06b2015-10-07 12:23:21 +0200816StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200817 : StunAttribute(type, length), bytes_(NULL) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000818
819StunByteStringAttribute::~StunByteStringAttribute() {
Yves Gerey665174f2018-06-19 15:03:05 +0200820 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000821}
822
Steve Antonca7d54e2017-10-25 14:42:51 -0700823StunAttributeValueType StunByteStringAttribute::value_type() const {
824 return STUN_VALUE_BYTE_STRING;
825}
826
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000827void StunByteStringAttribute::CopyBytes(const char* bytes) {
828 CopyBytes(bytes, strlen(bytes));
829}
830
831void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
832 char* new_bytes = new char[length];
833 memcpy(new_bytes, bytes, length);
834 SetBytes(new_bytes, length);
835}
836
Peter Boström0c4e06b2015-10-07 12:23:21 +0200837uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800838 RTC_DCHECK(bytes_ != NULL);
839 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200840 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000841}
842
Peter Boström0c4e06b2015-10-07 12:23:21 +0200843void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800844 RTC_DCHECK(bytes_ != NULL);
845 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000846 bytes_[index] = value;
847}
848
jbauchf1f87202016-03-30 06:43:37 -0700849bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000850 bytes_ = new char[length()];
851 if (!buf->ReadBytes(bytes_, length())) {
852 return false;
853 }
854
855 ConsumePadding(buf);
856 return true;
857}
858
jbauchf1f87202016-03-30 06:43:37 -0700859bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000860 buf->WriteBytes(bytes_, length());
861 WritePadding(buf);
862 return true;
863}
864
865void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
Yves Gerey665174f2018-06-19 15:03:05 +0200866 delete[] bytes_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000867 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200868 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000869}
870
zsteinf42cc9d2017-03-27 16:17:19 -0700871const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
872
Peter Boström0c4e06b2015-10-07 12:23:21 +0200873StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
874 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000875 const std::string& reason)
876 : StunAttribute(type, 0) {
877 SetCode(code);
878 SetReason(reason);
879}
880
Peter Boström0c4e06b2015-10-07 12:23:21 +0200881StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
Yves Gerey665174f2018-06-19 15:03:05 +0200882 : StunAttribute(type, length), class_(0), number_(0) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000883
Yves Gerey665174f2018-06-19 15:03:05 +0200884StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000885
Steve Antonca7d54e2017-10-25 14:42:51 -0700886StunAttributeValueType StunErrorCodeAttribute::value_type() const {
887 return STUN_VALUE_ERROR_CODE;
888}
889
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000890int StunErrorCodeAttribute::code() const {
891 return class_ * 100 + number_;
892}
893
894void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200895 class_ = static_cast<uint8_t>(code / 100);
896 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000897}
898
899void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200900 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000901 reason_ = reason;
902}
903
jbauchf1f87202016-03-30 06:43:37 -0700904bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200905 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000906 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
907 return false;
908
909 if ((val >> 11) != 0)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100910 RTC_LOG(LS_ERROR) << "error-code bits not zero";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000911
912 class_ = ((val >> 8) & 0x7);
913 number_ = (val & 0xff);
914
915 if (!buf->ReadString(&reason_, length() - 4))
916 return false;
917
918 ConsumePadding(buf);
919 return true;
920}
921
jbauchf1f87202016-03-30 06:43:37 -0700922bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000923 buf->WriteUInt32(class_ << 8 | number_);
924 buf->WriteString(reason_);
925 WritePadding(buf);
926 return true;
927}
928
Peter Boström0c4e06b2015-10-07 12:23:21 +0200929StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000930 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200931 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000932}
933
934StunUInt16ListAttribute::~StunUInt16ListAttribute() {
935 delete attr_types_;
936}
937
Steve Antonca7d54e2017-10-25 14:42:51 -0700938StunAttributeValueType StunUInt16ListAttribute::value_type() const {
939 return STUN_VALUE_UINT16_LIST;
940}
941
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000942size_t StunUInt16ListAttribute::Size() const {
943 return attr_types_->size();
944}
945
Peter Boström0c4e06b2015-10-07 12:23:21 +0200946uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000947 return (*attr_types_)[index];
948}
949
Peter Boström0c4e06b2015-10-07 12:23:21 +0200950void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000951 (*attr_types_)[index] = value;
952}
953
Peter Boström0c4e06b2015-10-07 12:23:21 +0200954void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000955 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200956 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000957}
958
jbauchf1f87202016-03-30 06:43:37 -0700959bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000960 if (length() % 2)
961 return false;
962
963 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200964 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000965 if (!buf->ReadUInt16(&attr))
966 return false;
967 attr_types_->push_back(attr);
968 }
969 // Padding of these attributes is done in RFC 5389 style. This is
970 // slightly different from RFC3489, but it shouldn't be important.
971 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
972 // entries in the list (not necessarily the last one - it's unspecified).
973 // RFC5389 pads on the end, and the bytes are always ignored.
974 ConsumePadding(buf);
975 return true;
976}
977
jbauchf1f87202016-03-30 06:43:37 -0700978bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000979 for (size_t i = 0; i < attr_types_->size(); ++i) {
980 buf->WriteUInt16((*attr_types_)[i]);
981 }
982 WritePadding(buf);
983 return true;
984}
985
986int GetStunSuccessResponseType(int req_type) {
987 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
988}
989
990int GetStunErrorResponseType(int req_type) {
991 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
992}
993
994bool IsStunRequestType(int msg_type) {
995 return ((msg_type & kStunTypeMask) == 0x000);
996}
997
998bool IsStunIndicationType(int msg_type) {
999 return ((msg_type & kStunTypeMask) == 0x010);
1000}
1001
1002bool IsStunSuccessResponseType(int msg_type) {
1003 return ((msg_type & kStunTypeMask) == 0x100);
1004}
1005
1006bool IsStunErrorResponseType(int msg_type) {
1007 return ((msg_type & kStunTypeMask) == 0x110);
1008}
1009
1010bool ComputeStunCredentialHash(const std::string& username,
1011 const std::string& realm,
1012 const std::string& password,
1013 std::string* hash) {
1014 // http://tools.ietf.org/html/rfc5389#section-15.4
1015 // long-term credentials will be calculated using the key and key is
1016 // key = MD5(username ":" realm ":" SASLprep(password))
1017 std::string input = username;
1018 input += ':';
1019 input += realm;
1020 input += ':';
1021 input += password;
1022
1023 char digest[rtc::MessageDigest::kMaxSize];
Yves Gerey665174f2018-06-19 15:03:05 +02001024 size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
1025 digest, sizeof(digest));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001026 if (size == 0) {
1027 return false;
1028 }
1029
1030 *hash = std::string(digest, size);
1031 return true;
1032}
1033
Jonas Oreland202994c2017-12-18 12:10:43 +01001034std::unique_ptr<StunAttribute> CopyStunAttribute(
1035 const StunAttribute& attribute,
1036 rtc::ByteBufferWriter* tmp_buffer_ptr) {
1037 ByteBufferWriter tmpBuffer;
1038 if (tmp_buffer_ptr == nullptr) {
1039 tmp_buffer_ptr = &tmpBuffer;
1040 }
1041
Yves Gerey665174f2018-06-19 15:03:05 +02001042 std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
1043 attribute.value_type(), attribute.type(),
1044 static_cast<uint16_t>(attribute.length()), nullptr));
Jonas Oreland202994c2017-12-18 12:10:43 +01001045
1046 if (!copy) {
1047 return nullptr;
1048 }
1049 tmp_buffer_ptr->Clear();
1050 if (!attribute.Write(tmp_buffer_ptr)) {
1051 return nullptr;
1052 }
1053 rtc::ByteBufferReader reader(*tmp_buffer_ptr);
1054 if (!copy->Read(&reader)) {
1055 return nullptr;
1056 }
1057
1058 return copy;
1059}
1060
Steve Antonca7d54e2017-10-25 14:42:51 -07001061StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
1062 switch (type) {
1063 case STUN_ATTR_LIFETIME:
1064 return STUN_VALUE_UINT32;
1065 case STUN_ATTR_MAGIC_COOKIE:
1066 return STUN_VALUE_BYTE_STRING;
1067 case STUN_ATTR_BANDWIDTH:
1068 return STUN_VALUE_UINT32;
1069 case STUN_ATTR_DESTINATION_ADDRESS:
1070 return STUN_VALUE_ADDRESS;
1071 case STUN_ATTR_SOURCE_ADDRESS2:
1072 return STUN_VALUE_ADDRESS;
1073 case STUN_ATTR_DATA:
1074 return STUN_VALUE_BYTE_STRING;
1075 case STUN_ATTR_OPTIONS:
1076 return STUN_VALUE_UINT32;
1077 default:
1078 return StunMessage::GetAttributeValueType(type);
1079 }
1080}
1081
1082StunMessage* RelayMessage::CreateNew() const {
1083 return new RelayMessage();
1084}
1085
1086StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
1087 switch (type) {
1088 case STUN_ATTR_CHANNEL_NUMBER:
1089 return STUN_VALUE_UINT32;
1090 case STUN_ATTR_TURN_LIFETIME:
1091 return STUN_VALUE_UINT32;
1092 case STUN_ATTR_XOR_PEER_ADDRESS:
1093 return STUN_VALUE_XOR_ADDRESS;
1094 case STUN_ATTR_DATA:
1095 return STUN_VALUE_BYTE_STRING;
1096 case STUN_ATTR_XOR_RELAYED_ADDRESS:
1097 return STUN_VALUE_XOR_ADDRESS;
1098 case STUN_ATTR_EVEN_PORT:
1099 return STUN_VALUE_BYTE_STRING;
1100 case STUN_ATTR_REQUESTED_TRANSPORT:
1101 return STUN_VALUE_UINT32;
1102 case STUN_ATTR_DONT_FRAGMENT:
1103 return STUN_VALUE_BYTE_STRING;
1104 case STUN_ATTR_RESERVATION_TOKEN:
1105 return STUN_VALUE_BYTE_STRING;
1106 default:
1107 return StunMessage::GetAttributeValueType(type);
1108 }
1109}
1110
1111StunMessage* TurnMessage::CreateNew() const {
1112 return new TurnMessage();
1113}
1114
1115StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
1116 switch (type) {
1117 case STUN_ATTR_PRIORITY:
1118 case STUN_ATTR_NETWORK_INFO:
1119 case STUN_ATTR_NOMINATION:
1120 return STUN_VALUE_UINT32;
1121 case STUN_ATTR_USE_CANDIDATE:
1122 return STUN_VALUE_BYTE_STRING;
1123 case STUN_ATTR_ICE_CONTROLLED:
1124 return STUN_VALUE_UINT64;
1125 case STUN_ATTR_ICE_CONTROLLING:
1126 return STUN_VALUE_UINT64;
1127 default:
1128 return StunMessage::GetAttributeValueType(type);
1129 }
1130}
1131
1132StunMessage* IceMessage::CreateNew() const {
1133 return new IceMessage();
1134}
1135
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001136} // namespace cricket