blob: e7d12444841e3782361ebb25141fb66dc3069d76 [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "p2p/base/stun.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000012
13#include <string.h>
14
kwiberg3ec46792016-04-27 07:22:53 -070015#include <memory>
16
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/byteorder.h"
18#include "rtc_base/checks.h"
19#include "rtc_base/crc32.h"
20#include "rtc_base/logging.h"
21#include "rtc_base/messagedigest.h"
22#include "rtc_base/ptr_util.h"
23#include "rtc_base/stringencode.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024
jbauchf1f87202016-03-30 06:43:37 -070025using rtc::ByteBufferReader;
26using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000027
28namespace cricket {
29
30const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
31const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
32const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
33const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
34const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
35const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
36const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
37const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
38const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
39const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
40const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
41
42const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
43const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020044const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000045
46// StunMessage
47
48StunMessage::StunMessage()
49 : type_(0),
50 length_(0),
51 transaction_id_(EMPTY_TRANSACTION_ID) {
nisseede5da42017-01-12 05:15:36 -080052 RTC_DCHECK(IsValidTransactionId(transaction_id_));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000053}
54
55bool StunMessage::IsLegacy() const {
56 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
57 return true;
nisseede5da42017-01-12 05:15:36 -080058 RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059 return false;
60}
61
62bool StunMessage::SetTransactionID(const std::string& str) {
63 if (!IsValidTransactionId(str)) {
64 return false;
65 }
66 transaction_id_ = str;
67 return true;
68}
69
Jonas Orelandbdcee282017-10-10 14:01:40 +020070static bool ImplementationDefinedRange(int attr_type)
71{
72 return attr_type >= 0xC000 && attr_type <= 0xFFFF;
73}
74
zsteinf42cc9d2017-03-27 16:17:19 -070075void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Jonas Orelandbdcee282017-10-10 14:01:40 +020076 // Fail any attributes that aren't valid for this type of message,
77 // but allow any type for the range that is "implementation defined"
78 // in the RFC.
79 if (!ImplementationDefinedRange(attr->type())) {
80 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
81 }
nissecc99bc22017-02-02 01:31:30 -080082
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000083 attr->SetOwner(this);
84 size_t attr_length = attr->length();
85 if (attr_length % 4 != 0) {
86 attr_length += (4 - (attr_length % 4));
87 }
Peter Boström0c4e06b2015-10-07 12:23:21 +020088 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -070089
90 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000091}
92
93const StunAddressAttribute* StunMessage::GetAddress(int type) const {
94 switch (type) {
95 case STUN_ATTR_MAPPED_ADDRESS: {
96 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
97 // missing.
98 const StunAttribute* mapped_address =
99 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
100 if (!mapped_address)
101 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
102 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
103 }
104
105 default:
106 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
107 }
108}
109
110const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
111 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
112}
113
114const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
115 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
116}
117
118const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
119 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
120}
121
122const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
123 return static_cast<const StunErrorCodeAttribute*>(
124 GetAttribute(STUN_ATTR_ERROR_CODE));
125}
126
deadbeef996fc6b2017-04-26 09:21:22 -0700127int StunMessage::GetErrorCodeValue() const {
128 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
129 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
130}
131
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000132const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
133 return static_cast<const StunUInt16ListAttribute*>(
134 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
135}
136
137// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
138// procedure outlined in RFC 5389, section 15.4.
139bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
140 const std::string& password) {
141 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700142 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000143 return false;
144 }
145
146 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200147 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000148 if (size != (msg_length + kStunHeaderSize)) {
149 return false;
150 }
151
152 // Finding Message Integrity attribute in stun message.
153 size_t current_pos = kStunHeaderSize;
154 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700155 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200156 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000157 // Getting attribute type and length.
158 attr_type = rtc::GetBE16(&data[current_pos]);
159 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
160
161 // If M-I, sanity check it, and break out.
162 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
163 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700164 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
165 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 return false;
167 }
168 has_message_integrity_attr = true;
169 break;
170 }
171
172 // Otherwise, skip to the next attribute.
173 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
174 if ((attr_length % 4) != 0) {
175 current_pos += (4 - (attr_length % 4));
176 }
177 }
178
179 if (!has_message_integrity_attr) {
180 return false;
181 }
182
183 // Getting length of the message to calculate Message Integrity.
184 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700185 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000186 memcpy(temp_data.get(), data, current_pos);
187 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
188 // Stun message has other attributes after message integrity.
189 // Adjust the length parameter in stun message to calculate HMAC.
190 size_t extra_offset = size -
191 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
192 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
193
194 // Writing new length of the STUN message @ Message Length in temp buffer.
195 // 0 1 2 3
196 // 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
197 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
198 // |0 0| STUN Message Type | Message Length |
199 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200200 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000201 }
202
203 char hmac[kStunMessageIntegritySize];
204 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
205 password.c_str(), password.size(),
206 temp_data.get(), mi_pos,
207 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800208 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000209 if (ret != sizeof(hmac))
210 return false;
211
212 // Comparing the calculated HMAC with the one present in the message.
213 return memcmp(data + current_pos + kStunAttributeHeaderSize,
214 hmac,
215 sizeof(hmac)) == 0;
216}
217
218bool StunMessage::AddMessageIntegrity(const std::string& password) {
219 return AddMessageIntegrity(password.c_str(), password.size());
220}
221
222bool StunMessage::AddMessageIntegrity(const char* key,
223 size_t keylen) {
224 // Add the attribute with a dummy value. Since this is a known attribute, it
225 // can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700226 auto msg_integrity_attr_ptr = rtc::MakeUnique<StunByteStringAttribute>(
227 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
228 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
229 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000230
231 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700232 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000233 if (!Write(&buf))
234 return false;
235
236 int msg_len_for_hmac = static_cast<int>(
237 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
238 char hmac[kStunMessageIntegritySize];
239 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
240 key, keylen,
241 buf.Data(), msg_len_for_hmac,
242 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800243 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000244 if (ret != sizeof(hmac)) {
245 LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
246 << "has dummy value.";
247 return false;
248 }
249
250 // Insert correct HMAC into the attribute.
251 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
252 return true;
253}
254
255// Verifies a message is in fact a STUN message, by performing the checks
256// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
257// in section 15.5.
258bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
259 // Check the message length.
260 size_t fingerprint_attr_size =
261 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
262 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
263 return false;
264
265 // Skip the rest if the magic cookie isn't present.
266 const char* magic_cookie =
267 data + kStunTransactionIdOffset - kStunMagicCookieLength;
268 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
269 return false;
270
271 // Check the fingerprint type and length.
272 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
273 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200274 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000275 StunUInt32Attribute::SIZE)
276 return false;
277
278 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200279 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000280 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
281 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
282 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
283}
284
285bool StunMessage::AddFingerprint() {
286 // Add the attribute with a dummy value. Since this is a known attribute,
287 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700288 auto fingerprint_attr_ptr =
289 rtc::MakeUnique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
290 auto fingerprint_attr = fingerprint_attr_ptr.get();
291 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000292
293 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700294 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000295 if (!Write(&buf))
296 return false;
297
298 int msg_len_for_crc32 = static_cast<int>(
299 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200300 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000301
302 // Insert the correct CRC-32, XORed with a constant, into the attribute.
303 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
304 return true;
305}
306
jbauchf1f87202016-03-30 06:43:37 -0700307bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000308 if (!buf->ReadUInt16(&type_))
309 return false;
310
311 if (type_ & 0x8000) {
312 // RTP and RTCP set the MSB of first byte, since first two bits are version,
313 // and version is always 2 (10). If set, this is not a STUN packet.
314 return false;
315 }
316
317 if (!buf->ReadUInt16(&length_))
318 return false;
319
320 std::string magic_cookie;
321 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
322 return false;
323
324 std::string transaction_id;
325 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
326 return false;
327
Peter Boström0c4e06b2015-10-07 12:23:21 +0200328 uint32_t magic_cookie_int =
329 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000330 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
331 // If magic cookie is invalid it means that the peer implements
332 // RFC3489 instead of RFC5389.
333 transaction_id.insert(0, magic_cookie);
334 }
nisseede5da42017-01-12 05:15:36 -0800335 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000336 transaction_id_ = transaction_id;
337
338 if (length_ != buf->Length())
339 return false;
340
zsteinad94c4c2017-03-06 13:36:05 -0800341 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000342
343 size_t rest = buf->Length() - length_;
344 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200345 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000346 if (!buf->ReadUInt16(&attr_type))
347 return false;
348 if (!buf->ReadUInt16(&attr_length))
349 return false;
350
Honghai Zhang3e024302016-09-22 09:52:16 -0700351 std::unique_ptr<StunAttribute> attr(
352 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000353 if (!attr) {
354 // Skip any unknown or malformed attributes.
355 if ((attr_length % 4) != 0) {
356 attr_length += (4 - (attr_length % 4));
357 }
358 if (!buf->Consume(attr_length))
359 return false;
360 } else {
361 if (!attr->Read(buf))
362 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800363 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000364 }
365 }
366
nisseede5da42017-01-12 05:15:36 -0800367 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000368 return true;
369}
370
jbauchf1f87202016-03-30 06:43:37 -0700371bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000372 buf->WriteUInt16(type_);
373 buf->WriteUInt16(length_);
374 if (!IsLegacy())
375 buf->WriteUInt32(kStunMagicCookie);
376 buf->WriteString(transaction_id_);
377
zsteinad94c4c2017-03-06 13:36:05 -0800378 for (const auto& attr : attrs_) {
379 buf->WriteUInt16(attr->type());
380 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
381 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000382 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800383 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000384 }
385
386 return true;
387}
388
389StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
390 switch (type) {
391 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
392 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
393 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
394 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
395 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
396 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
397 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
398 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
399 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
400 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS;
401 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000402 case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000403 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
404 default: return STUN_VALUE_UNKNOWN;
405 }
406}
407
408StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
409 StunAttributeValueType value_type = GetAttributeValueType(type);
Jonas Orelandbdcee282017-10-10 14:01:40 +0200410 if (value_type != STUN_VALUE_UNKNOWN) {
411 return StunAttribute::Create(value_type, type,
412 static_cast<uint16_t>(length), this);
413 } else if (ImplementationDefinedRange(type)) {
414 // Read unknown attributes as STUN_VALUE_BYTE_STRING
415 return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
416 static_cast<uint16_t>(length), this);
417 } else {
418 return NULL;
419 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000420}
421
422const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800423 for (const auto& attr : attrs_) {
424 if (attr->type() == type) {
425 return attr.get();
426 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000427 }
428 return NULL;
429}
430
431bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
432 return transaction_id.size() == kStunTransactionIdLength ||
433 transaction_id.size() == kStunLegacyTransactionIdLength;
434}
435
436// StunAttribute
437
Peter Boström0c4e06b2015-10-07 12:23:21 +0200438StunAttribute::StunAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000439 : type_(type), length_(length) {
440}
441
jbauchf1f87202016-03-30 06:43:37 -0700442void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000443 int remainder = length_ % 4;
444 if (remainder > 0) {
445 buf->Consume(4 - remainder);
446 }
447}
448
jbauchf1f87202016-03-30 06:43:37 -0700449void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000450 int remainder = length_ % 4;
451 if (remainder > 0) {
452 char zeroes[4] = {0};
453 buf->WriteBytes(zeroes, 4 - remainder);
454 }
455}
456
457StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200458 uint16_t type,
459 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000460 StunMessage* owner) {
461 switch (value_type) {
462 case STUN_VALUE_ADDRESS:
463 return new StunAddressAttribute(type, length);
464 case STUN_VALUE_XOR_ADDRESS:
465 return new StunXorAddressAttribute(type, length, owner);
466 case STUN_VALUE_UINT32:
467 return new StunUInt32Attribute(type);
468 case STUN_VALUE_UINT64:
469 return new StunUInt64Attribute(type);
470 case STUN_VALUE_BYTE_STRING:
471 return new StunByteStringAttribute(type, length);
472 case STUN_VALUE_ERROR_CODE:
473 return new StunErrorCodeAttribute(type, length);
474 case STUN_VALUE_UINT16_LIST:
475 return new StunUInt16ListAttribute(type, length);
476 default:
477 return NULL;
478 }
479}
480
zsteinf42cc9d2017-03-27 16:17:19 -0700481std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
482 uint16_t type) {
483 return rtc::MakeUnique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000484}
485
zsteinf42cc9d2017-03-27 16:17:19 -0700486std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
487 uint16_t type) {
488 return rtc::MakeUnique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000489}
490
zsteinf42cc9d2017-03-27 16:17:19 -0700491std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
492 uint16_t type) {
493 return rtc::MakeUnique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000494}
495
zsteinf42cc9d2017-03-27 16:17:19 -0700496std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
497 uint16_t type) {
498 return rtc::MakeUnique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000499}
500
zsteinf42cc9d2017-03-27 16:17:19 -0700501std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
502 uint16_t type) {
503 return rtc::MakeUnique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000504}
505
zsteinf42cc9d2017-03-27 16:17:19 -0700506std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
507 return rtc::MakeUnique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000508 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
509}
510
zsteinf42cc9d2017-03-27 16:17:19 -0700511std::unique_ptr<StunUInt16ListAttribute>
512StunAttribute::CreateUnknownAttributes() {
513 return rtc::MakeUnique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
514 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000515}
516
Peter Boström0c4e06b2015-10-07 12:23:21 +0200517StunAddressAttribute::StunAddressAttribute(uint16_t type,
518 const rtc::SocketAddress& addr)
519 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000520 SetAddress(addr);
521}
522
Peter Boström0c4e06b2015-10-07 12:23:21 +0200523StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000524 : StunAttribute(type, length) {
525}
526
jbauchf1f87202016-03-30 06:43:37 -0700527bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200528 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000529 if (!buf->ReadUInt8(&dummy))
530 return false;
531
Peter Boström0c4e06b2015-10-07 12:23:21 +0200532 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000533 if (!buf->ReadUInt8(&stun_family)) {
534 return false;
535 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200536 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000537 if (!buf->ReadUInt16(&port))
538 return false;
539 if (stun_family == STUN_ADDRESS_IPV4) {
540 in_addr v4addr;
541 if (length() != SIZE_IP4) {
542 return false;
543 }
544 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
545 return false;
546 }
547 rtc::IPAddress ipaddr(v4addr);
548 SetAddress(rtc::SocketAddress(ipaddr, port));
549 } else if (stun_family == STUN_ADDRESS_IPV6) {
550 in6_addr v6addr;
551 if (length() != SIZE_IP6) {
552 return false;
553 }
554 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
555 return false;
556 }
557 rtc::IPAddress ipaddr(v6addr);
558 SetAddress(rtc::SocketAddress(ipaddr, port));
559 } else {
560 return false;
561 }
562 return true;
563}
564
jbauchf1f87202016-03-30 06:43:37 -0700565bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000566 StunAddressFamily address_family = family();
567 if (address_family == STUN_ADDRESS_UNDEF) {
568 LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
569 return false;
570 }
571 buf->WriteUInt8(0);
572 buf->WriteUInt8(address_family);
573 buf->WriteUInt16(address_.port());
574 switch (address_.family()) {
575 case AF_INET: {
576 in_addr v4addr = address_.ipaddr().ipv4_address();
577 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
578 break;
579 }
580 case AF_INET6: {
581 in6_addr v6addr = address_.ipaddr().ipv6_address();
582 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
583 break;
584 }
585 }
586 return true;
587}
588
Peter Boström0c4e06b2015-10-07 12:23:21 +0200589StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
590 const rtc::SocketAddress& addr)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000591 : StunAddressAttribute(type, addr), owner_(NULL) {
592}
593
Peter Boström0c4e06b2015-10-07 12:23:21 +0200594StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
595 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000596 StunMessage* owner)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200597 : StunAddressAttribute(type, length), owner_(owner) {
598}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000599
600rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
601 if (owner_) {
602 rtc::IPAddress ip = ipaddr();
603 switch (ip.family()) {
604 case AF_INET: {
605 in_addr v4addr = ip.ipv4_address();
606 v4addr.s_addr =
607 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
608 return rtc::IPAddress(v4addr);
609 }
610 case AF_INET6: {
611 in6_addr v6addr = ip.ipv6_address();
612 const std::string& transaction_id = owner_->transaction_id();
613 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200614 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000615 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
616 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200617 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000618 // Transaction ID is in network byte order, but magic cookie
619 // is stored in host byte order.
620 ip_as_ints[0] =
621 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
622 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
623 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
624 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
625 return rtc::IPAddress(v6addr);
626 }
627 break;
628 }
629 }
630 }
631 // Invalid ip family or transaction ID, or missing owner.
632 // Return an AF_UNSPEC address.
633 return rtc::IPAddress();
634}
635
jbauchf1f87202016-03-30 06:43:37 -0700636bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000637 if (!StunAddressAttribute::Read(buf))
638 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200639 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000640 rtc::IPAddress xored_ip = GetXoredIP();
641 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
642 return true;
643}
644
jbauchf1f87202016-03-30 06:43:37 -0700645bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000646 StunAddressFamily address_family = family();
647 if (address_family == STUN_ADDRESS_UNDEF) {
648 LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
649 return false;
650 }
651 rtc::IPAddress xored_ip = GetXoredIP();
652 if (xored_ip.family() == AF_UNSPEC) {
653 return false;
654 }
655 buf->WriteUInt8(0);
656 buf->WriteUInt8(family());
657 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
658 switch (xored_ip.family()) {
659 case AF_INET: {
660 in_addr v4addr = xored_ip.ipv4_address();
661 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
662 break;
663 }
664 case AF_INET6: {
665 in6_addr v6addr = xored_ip.ipv6_address();
666 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
667 break;
668 }
669 }
670 return true;
671}
672
Peter Boström0c4e06b2015-10-07 12:23:21 +0200673StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000674 : StunAttribute(type, SIZE), bits_(value) {
675}
676
Peter Boström0c4e06b2015-10-07 12:23:21 +0200677StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000678 : StunAttribute(type, SIZE), bits_(0) {
679}
680
681bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800682 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000683 return static_cast<bool>((bits_ >> index) & 0x1);
684}
685
686void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800687 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000688 bits_ &= ~(1 << index);
689 bits_ |= value ? (1 << index) : 0;
690}
691
jbauchf1f87202016-03-30 06:43:37 -0700692bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000693 if (length() != SIZE || !buf->ReadUInt32(&bits_))
694 return false;
695 return true;
696}
697
jbauchf1f87202016-03-30 06:43:37 -0700698bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000699 buf->WriteUInt32(bits_);
700 return true;
701}
702
Peter Boström0c4e06b2015-10-07 12:23:21 +0200703StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000704 : StunAttribute(type, SIZE), bits_(value) {
705}
706
Peter Boström0c4e06b2015-10-07 12:23:21 +0200707StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000708 : StunAttribute(type, SIZE), bits_(0) {
709}
710
jbauchf1f87202016-03-30 06:43:37 -0700711bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000712 if (length() != SIZE || !buf->ReadUInt64(&bits_))
713 return false;
714 return true;
715}
716
jbauchf1f87202016-03-30 06:43:37 -0700717bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000718 buf->WriteUInt64(bits_);
719 return true;
720}
721
Peter Boström0c4e06b2015-10-07 12:23:21 +0200722StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000723 : StunAttribute(type, 0), bytes_(NULL) {
724}
725
Peter Boström0c4e06b2015-10-07 12:23:21 +0200726StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000727 const std::string& str)
728 : StunAttribute(type, 0), bytes_(NULL) {
729 CopyBytes(str.c_str(), str.size());
730}
731
Peter Boström0c4e06b2015-10-07 12:23:21 +0200732StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000733 const void* bytes,
734 size_t length)
735 : StunAttribute(type, 0), bytes_(NULL) {
736 CopyBytes(bytes, length);
737}
738
Peter Boström0c4e06b2015-10-07 12:23:21 +0200739StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000740 : StunAttribute(type, length), bytes_(NULL) {
741}
742
743StunByteStringAttribute::~StunByteStringAttribute() {
744 delete [] bytes_;
745}
746
747void StunByteStringAttribute::CopyBytes(const char* bytes) {
748 CopyBytes(bytes, strlen(bytes));
749}
750
751void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
752 char* new_bytes = new char[length];
753 memcpy(new_bytes, bytes, length);
754 SetBytes(new_bytes, length);
755}
756
Peter Boström0c4e06b2015-10-07 12:23:21 +0200757uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800758 RTC_DCHECK(bytes_ != NULL);
759 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200760 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000761}
762
Peter Boström0c4e06b2015-10-07 12:23:21 +0200763void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800764 RTC_DCHECK(bytes_ != NULL);
765 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000766 bytes_[index] = value;
767}
768
jbauchf1f87202016-03-30 06:43:37 -0700769bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000770 bytes_ = new char[length()];
771 if (!buf->ReadBytes(bytes_, length())) {
772 return false;
773 }
774
775 ConsumePadding(buf);
776 return true;
777}
778
jbauchf1f87202016-03-30 06:43:37 -0700779bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000780 buf->WriteBytes(bytes_, length());
781 WritePadding(buf);
782 return true;
783}
784
785void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
786 delete [] bytes_;
787 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200788 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000789}
790
zsteinf42cc9d2017-03-27 16:17:19 -0700791const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
792
Peter Boström0c4e06b2015-10-07 12:23:21 +0200793StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
794 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000795 const std::string& reason)
796 : StunAttribute(type, 0) {
797 SetCode(code);
798 SetReason(reason);
799}
800
Peter Boström0c4e06b2015-10-07 12:23:21 +0200801StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000802 : StunAttribute(type, length), class_(0), number_(0) {
803}
804
805StunErrorCodeAttribute::~StunErrorCodeAttribute() {
806}
807
808int StunErrorCodeAttribute::code() const {
809 return class_ * 100 + number_;
810}
811
812void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200813 class_ = static_cast<uint8_t>(code / 100);
814 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000815}
816
817void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200818 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000819 reason_ = reason;
820}
821
jbauchf1f87202016-03-30 06:43:37 -0700822bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200823 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000824 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
825 return false;
826
827 if ((val >> 11) != 0)
828 LOG(LS_ERROR) << "error-code bits not zero";
829
830 class_ = ((val >> 8) & 0x7);
831 number_ = (val & 0xff);
832
833 if (!buf->ReadString(&reason_, length() - 4))
834 return false;
835
836 ConsumePadding(buf);
837 return true;
838}
839
jbauchf1f87202016-03-30 06:43:37 -0700840bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000841 buf->WriteUInt32(class_ << 8 | number_);
842 buf->WriteString(reason_);
843 WritePadding(buf);
844 return true;
845}
846
Peter Boström0c4e06b2015-10-07 12:23:21 +0200847StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000848 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200849 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000850}
851
852StunUInt16ListAttribute::~StunUInt16ListAttribute() {
853 delete attr_types_;
854}
855
856size_t StunUInt16ListAttribute::Size() const {
857 return attr_types_->size();
858}
859
Peter Boström0c4e06b2015-10-07 12:23:21 +0200860uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000861 return (*attr_types_)[index];
862}
863
Peter Boström0c4e06b2015-10-07 12:23:21 +0200864void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000865 (*attr_types_)[index] = value;
866}
867
Peter Boström0c4e06b2015-10-07 12:23:21 +0200868void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000869 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200870 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000871}
872
jbauchf1f87202016-03-30 06:43:37 -0700873bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000874 if (length() % 2)
875 return false;
876
877 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200878 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000879 if (!buf->ReadUInt16(&attr))
880 return false;
881 attr_types_->push_back(attr);
882 }
883 // Padding of these attributes is done in RFC 5389 style. This is
884 // slightly different from RFC3489, but it shouldn't be important.
885 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
886 // entries in the list (not necessarily the last one - it's unspecified).
887 // RFC5389 pads on the end, and the bytes are always ignored.
888 ConsumePadding(buf);
889 return true;
890}
891
jbauchf1f87202016-03-30 06:43:37 -0700892bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000893 for (size_t i = 0; i < attr_types_->size(); ++i) {
894 buf->WriteUInt16((*attr_types_)[i]);
895 }
896 WritePadding(buf);
897 return true;
898}
899
900int GetStunSuccessResponseType(int req_type) {
901 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
902}
903
904int GetStunErrorResponseType(int req_type) {
905 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
906}
907
908bool IsStunRequestType(int msg_type) {
909 return ((msg_type & kStunTypeMask) == 0x000);
910}
911
912bool IsStunIndicationType(int msg_type) {
913 return ((msg_type & kStunTypeMask) == 0x010);
914}
915
916bool IsStunSuccessResponseType(int msg_type) {
917 return ((msg_type & kStunTypeMask) == 0x100);
918}
919
920bool IsStunErrorResponseType(int msg_type) {
921 return ((msg_type & kStunTypeMask) == 0x110);
922}
923
924bool ComputeStunCredentialHash(const std::string& username,
925 const std::string& realm,
926 const std::string& password,
927 std::string* hash) {
928 // http://tools.ietf.org/html/rfc5389#section-15.4
929 // long-term credentials will be calculated using the key and key is
930 // key = MD5(username ":" realm ":" SASLprep(password))
931 std::string input = username;
932 input += ':';
933 input += realm;
934 input += ':';
935 input += password;
936
937 char digest[rtc::MessageDigest::kMaxSize];
938 size_t size = rtc::ComputeDigest(
939 rtc::DIGEST_MD5, input.c_str(), input.size(),
940 digest, sizeof(digest));
941 if (size == 0) {
942 return false;
943 }
944
945 *hash = std::string(digest, size);
946 return true;
947}
948
949} // namespace cricket