blob: 9ac2554cf9c79ba669088f0d93b831823b0cab49 [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
zsteinf42cc9d2017-03-27 16:17:19 -070070void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
Guido Urdaneta604427b2017-10-09 09:53:49 +000071 // Fail any attributes that aren't valid for this type of message.
72 RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
nissecc99bc22017-02-02 01:31:30 -080073
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000074 attr->SetOwner(this);
75 size_t attr_length = attr->length();
76 if (attr_length % 4 != 0) {
77 attr_length += (4 - (attr_length % 4));
78 }
Peter Boström0c4e06b2015-10-07 12:23:21 +020079 length_ += static_cast<uint16_t>(attr_length + 4);
zsteinf42cc9d2017-03-27 16:17:19 -070080
81 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000082}
83
84const StunAddressAttribute* StunMessage::GetAddress(int type) const {
85 switch (type) {
86 case STUN_ATTR_MAPPED_ADDRESS: {
87 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
88 // missing.
89 const StunAttribute* mapped_address =
90 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
91 if (!mapped_address)
92 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
93 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
94 }
95
96 default:
97 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
98 }
99}
100
101const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
102 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
103}
104
105const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
106 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
107}
108
109const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
110 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
111}
112
113const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
114 return static_cast<const StunErrorCodeAttribute*>(
115 GetAttribute(STUN_ATTR_ERROR_CODE));
116}
117
deadbeef996fc6b2017-04-26 09:21:22 -0700118int StunMessage::GetErrorCodeValue() const {
119 const StunErrorCodeAttribute* error_attribute = GetErrorCode();
120 return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
121}
122
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000123const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
124 return static_cast<const StunUInt16ListAttribute*>(
125 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
126}
127
128// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
129// procedure outlined in RFC 5389, section 15.4.
130bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
131 const std::string& password) {
132 // Verifying the size of the message.
katrielce4bda242016-06-09 08:45:45 -0700133 if ((size % 4) != 0 || size < kStunHeaderSize) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000134 return false;
135 }
136
137 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200138 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000139 if (size != (msg_length + kStunHeaderSize)) {
140 return false;
141 }
142
143 // Finding Message Integrity attribute in stun message.
144 size_t current_pos = kStunHeaderSize;
145 bool has_message_integrity_attr = false;
katrielc1a206102016-06-20 05:13:16 -0700146 while (current_pos + 4 <= size) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200147 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000148 // Getting attribute type and length.
149 attr_type = rtc::GetBE16(&data[current_pos]);
150 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
151
152 // If M-I, sanity check it, and break out.
153 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
154 if (attr_length != kStunMessageIntegritySize ||
katrielc1a206102016-06-20 05:13:16 -0700155 current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
156 size) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000157 return false;
158 }
159 has_message_integrity_attr = true;
160 break;
161 }
162
163 // Otherwise, skip to the next attribute.
164 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
165 if ((attr_length % 4) != 0) {
166 current_pos += (4 - (attr_length % 4));
167 }
168 }
169
170 if (!has_message_integrity_attr) {
171 return false;
172 }
173
174 // Getting length of the message to calculate Message Integrity.
175 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 07:22:53 -0700176 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000177 memcpy(temp_data.get(), data, current_pos);
178 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
179 // Stun message has other attributes after message integrity.
180 // Adjust the length parameter in stun message to calculate HMAC.
181 size_t extra_offset = size -
182 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
183 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
184
185 // Writing new length of the STUN message @ Message Length in temp buffer.
186 // 0 1 2 3
187 // 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
188 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
189 // |0 0| STUN Message Type | Message Length |
190 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200191 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000192 }
193
194 char hmac[kStunMessageIntegritySize];
195 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
196 password.c_str(), password.size(),
197 temp_data.get(), mi_pos,
198 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800199 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000200 if (ret != sizeof(hmac))
201 return false;
202
203 // Comparing the calculated HMAC with the one present in the message.
204 return memcmp(data + current_pos + kStunAttributeHeaderSize,
205 hmac,
206 sizeof(hmac)) == 0;
207}
208
209bool StunMessage::AddMessageIntegrity(const std::string& password) {
210 return AddMessageIntegrity(password.c_str(), password.size());
211}
212
213bool StunMessage::AddMessageIntegrity(const char* key,
214 size_t keylen) {
215 // Add the attribute with a dummy value. Since this is a known attribute, it
216 // can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700217 auto msg_integrity_attr_ptr = rtc::MakeUnique<StunByteStringAttribute>(
218 STUN_ATTR_MESSAGE_INTEGRITY, std::string(kStunMessageIntegritySize, '0'));
219 auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
220 AddAttribute(std::move(msg_integrity_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000221
222 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 06:43:37 -0700223 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000224 if (!Write(&buf))
225 return false;
226
227 int msg_len_for_hmac = static_cast<int>(
228 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
229 char hmac[kStunMessageIntegritySize];
230 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
231 key, keylen,
232 buf.Data(), msg_len_for_hmac,
233 hmac, sizeof(hmac));
nisseede5da42017-01-12 05:15:36 -0800234 RTC_DCHECK(ret == sizeof(hmac));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000235 if (ret != sizeof(hmac)) {
236 LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
237 << "has dummy value.";
238 return false;
239 }
240
241 // Insert correct HMAC into the attribute.
242 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
243 return true;
244}
245
246// Verifies a message is in fact a STUN message, by performing the checks
247// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
248// in section 15.5.
249bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
250 // Check the message length.
251 size_t fingerprint_attr_size =
252 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
253 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
254 return false;
255
256 // Skip the rest if the magic cookie isn't present.
257 const char* magic_cookie =
258 data + kStunTransactionIdOffset - kStunMagicCookieLength;
259 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
260 return false;
261
262 // Check the fingerprint type and length.
263 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
264 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200265 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000266 StunUInt32Attribute::SIZE)
267 return false;
268
269 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200270 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000271 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
272 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
273 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
274}
275
276bool StunMessage::AddFingerprint() {
277 // Add the attribute with a dummy value. Since this is a known attribute,
278 // it can't fail.
zsteinf42cc9d2017-03-27 16:17:19 -0700279 auto fingerprint_attr_ptr =
280 rtc::MakeUnique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
281 auto fingerprint_attr = fingerprint_attr_ptr.get();
282 AddAttribute(std::move(fingerprint_attr_ptr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000283
284 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 06:43:37 -0700285 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000286 if (!Write(&buf))
287 return false;
288
289 int msg_len_for_crc32 = static_cast<int>(
290 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200291 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000292
293 // Insert the correct CRC-32, XORed with a constant, into the attribute.
294 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
295 return true;
296}
297
jbauchf1f87202016-03-30 06:43:37 -0700298bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000299 if (!buf->ReadUInt16(&type_))
300 return false;
301
302 if (type_ & 0x8000) {
303 // RTP and RTCP set the MSB of first byte, since first two bits are version,
304 // and version is always 2 (10). If set, this is not a STUN packet.
305 return false;
306 }
307
308 if (!buf->ReadUInt16(&length_))
309 return false;
310
311 std::string magic_cookie;
312 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
313 return false;
314
315 std::string transaction_id;
316 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
317 return false;
318
Peter Boström0c4e06b2015-10-07 12:23:21 +0200319 uint32_t magic_cookie_int =
320 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000321 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
322 // If magic cookie is invalid it means that the peer implements
323 // RFC3489 instead of RFC5389.
324 transaction_id.insert(0, magic_cookie);
325 }
nisseede5da42017-01-12 05:15:36 -0800326 RTC_DCHECK(IsValidTransactionId(transaction_id));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000327 transaction_id_ = transaction_id;
328
329 if (length_ != buf->Length())
330 return false;
331
zsteinad94c4c2017-03-06 13:36:05 -0800332 attrs_.resize(0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000333
334 size_t rest = buf->Length() - length_;
335 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200336 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000337 if (!buf->ReadUInt16(&attr_type))
338 return false;
339 if (!buf->ReadUInt16(&attr_length))
340 return false;
341
Honghai Zhang3e024302016-09-22 09:52:16 -0700342 std::unique_ptr<StunAttribute> attr(
343 CreateAttribute(attr_type, attr_length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000344 if (!attr) {
345 // Skip any unknown or malformed attributes.
346 if ((attr_length % 4) != 0) {
347 attr_length += (4 - (attr_length % 4));
348 }
349 if (!buf->Consume(attr_length))
350 return false;
351 } else {
352 if (!attr->Read(buf))
353 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800354 attrs_.push_back(std::move(attr));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000355 }
356 }
357
nisseede5da42017-01-12 05:15:36 -0800358 RTC_DCHECK(buf->Length() == rest);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000359 return true;
360}
361
jbauchf1f87202016-03-30 06:43:37 -0700362bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000363 buf->WriteUInt16(type_);
364 buf->WriteUInt16(length_);
365 if (!IsLegacy())
366 buf->WriteUInt32(kStunMagicCookie);
367 buf->WriteString(transaction_id_);
368
zsteinad94c4c2017-03-06 13:36:05 -0800369 for (const auto& attr : attrs_) {
370 buf->WriteUInt16(attr->type());
371 buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
372 if (!attr->Write(buf)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000373 return false;
zsteinad94c4c2017-03-06 13:36:05 -0800374 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000375 }
376
377 return true;
378}
379
380StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
381 switch (type) {
382 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
383 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
384 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
385 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
386 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
387 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
388 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
389 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
390 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
391 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS;
392 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000393 case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000394 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
395 default: return STUN_VALUE_UNKNOWN;
396 }
397}
398
399StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
400 StunAttributeValueType value_type = GetAttributeValueType(type);
Guido Urdaneta604427b2017-10-09 09:53:49 +0000401 return StunAttribute::Create(value_type, type, static_cast<uint16_t>(length),
402 this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000403}
404
405const StunAttribute* StunMessage::GetAttribute(int type) const {
zsteinad94c4c2017-03-06 13:36:05 -0800406 for (const auto& attr : attrs_) {
407 if (attr->type() == type) {
408 return attr.get();
409 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000410 }
411 return NULL;
412}
413
414bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
415 return transaction_id.size() == kStunTransactionIdLength ||
416 transaction_id.size() == kStunLegacyTransactionIdLength;
417}
418
419// StunAttribute
420
Peter Boström0c4e06b2015-10-07 12:23:21 +0200421StunAttribute::StunAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000422 : type_(type), length_(length) {
423}
424
jbauchf1f87202016-03-30 06:43:37 -0700425void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000426 int remainder = length_ % 4;
427 if (remainder > 0) {
428 buf->Consume(4 - remainder);
429 }
430}
431
jbauchf1f87202016-03-30 06:43:37 -0700432void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000433 int remainder = length_ % 4;
434 if (remainder > 0) {
435 char zeroes[4] = {0};
436 buf->WriteBytes(zeroes, 4 - remainder);
437 }
438}
439
440StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200441 uint16_t type,
442 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000443 StunMessage* owner) {
444 switch (value_type) {
445 case STUN_VALUE_ADDRESS:
446 return new StunAddressAttribute(type, length);
447 case STUN_VALUE_XOR_ADDRESS:
448 return new StunXorAddressAttribute(type, length, owner);
449 case STUN_VALUE_UINT32:
450 return new StunUInt32Attribute(type);
451 case STUN_VALUE_UINT64:
452 return new StunUInt64Attribute(type);
453 case STUN_VALUE_BYTE_STRING:
454 return new StunByteStringAttribute(type, length);
455 case STUN_VALUE_ERROR_CODE:
456 return new StunErrorCodeAttribute(type, length);
457 case STUN_VALUE_UINT16_LIST:
458 return new StunUInt16ListAttribute(type, length);
459 default:
460 return NULL;
461 }
462}
463
zsteinf42cc9d2017-03-27 16:17:19 -0700464std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
465 uint16_t type) {
466 return rtc::MakeUnique<StunAddressAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000467}
468
zsteinf42cc9d2017-03-27 16:17:19 -0700469std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
470 uint16_t type) {
471 return rtc::MakeUnique<StunXorAddressAttribute>(type, 0, nullptr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000472}
473
zsteinf42cc9d2017-03-27 16:17:19 -0700474std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
475 uint16_t type) {
476 return rtc::MakeUnique<StunUInt64Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000477}
478
zsteinf42cc9d2017-03-27 16:17:19 -0700479std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
480 uint16_t type) {
481 return rtc::MakeUnique<StunUInt32Attribute>(type);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000482}
483
zsteinf42cc9d2017-03-27 16:17:19 -0700484std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
485 uint16_t type) {
486 return rtc::MakeUnique<StunByteStringAttribute>(type, 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000487}
488
zsteinf42cc9d2017-03-27 16:17:19 -0700489std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
490 return rtc::MakeUnique<StunErrorCodeAttribute>(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000491 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
492}
493
zsteinf42cc9d2017-03-27 16:17:19 -0700494std::unique_ptr<StunUInt16ListAttribute>
495StunAttribute::CreateUnknownAttributes() {
496 return rtc::MakeUnique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
497 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000498}
499
Peter Boström0c4e06b2015-10-07 12:23:21 +0200500StunAddressAttribute::StunAddressAttribute(uint16_t type,
501 const rtc::SocketAddress& addr)
502 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000503 SetAddress(addr);
504}
505
Peter Boström0c4e06b2015-10-07 12:23:21 +0200506StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000507 : StunAttribute(type, length) {
508}
509
jbauchf1f87202016-03-30 06:43:37 -0700510bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200511 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000512 if (!buf->ReadUInt8(&dummy))
513 return false;
514
Peter Boström0c4e06b2015-10-07 12:23:21 +0200515 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000516 if (!buf->ReadUInt8(&stun_family)) {
517 return false;
518 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200519 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000520 if (!buf->ReadUInt16(&port))
521 return false;
522 if (stun_family == STUN_ADDRESS_IPV4) {
523 in_addr v4addr;
524 if (length() != SIZE_IP4) {
525 return false;
526 }
527 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
528 return false;
529 }
530 rtc::IPAddress ipaddr(v4addr);
531 SetAddress(rtc::SocketAddress(ipaddr, port));
532 } else if (stun_family == STUN_ADDRESS_IPV6) {
533 in6_addr v6addr;
534 if (length() != SIZE_IP6) {
535 return false;
536 }
537 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
538 return false;
539 }
540 rtc::IPAddress ipaddr(v6addr);
541 SetAddress(rtc::SocketAddress(ipaddr, port));
542 } else {
543 return false;
544 }
545 return true;
546}
547
jbauchf1f87202016-03-30 06:43:37 -0700548bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000549 StunAddressFamily address_family = family();
550 if (address_family == STUN_ADDRESS_UNDEF) {
551 LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
552 return false;
553 }
554 buf->WriteUInt8(0);
555 buf->WriteUInt8(address_family);
556 buf->WriteUInt16(address_.port());
557 switch (address_.family()) {
558 case AF_INET: {
559 in_addr v4addr = address_.ipaddr().ipv4_address();
560 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
561 break;
562 }
563 case AF_INET6: {
564 in6_addr v6addr = address_.ipaddr().ipv6_address();
565 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
566 break;
567 }
568 }
569 return true;
570}
571
Peter Boström0c4e06b2015-10-07 12:23:21 +0200572StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
573 const rtc::SocketAddress& addr)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574 : StunAddressAttribute(type, addr), owner_(NULL) {
575}
576
Peter Boström0c4e06b2015-10-07 12:23:21 +0200577StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
578 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000579 StunMessage* owner)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200580 : StunAddressAttribute(type, length), owner_(owner) {
581}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000582
583rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
584 if (owner_) {
585 rtc::IPAddress ip = ipaddr();
586 switch (ip.family()) {
587 case AF_INET: {
588 in_addr v4addr = ip.ipv4_address();
589 v4addr.s_addr =
590 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
591 return rtc::IPAddress(v4addr);
592 }
593 case AF_INET6: {
594 in6_addr v6addr = ip.ipv6_address();
595 const std::string& transaction_id = owner_->transaction_id();
596 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200597 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000598 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
599 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200600 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000601 // Transaction ID is in network byte order, but magic cookie
602 // is stored in host byte order.
603 ip_as_ints[0] =
604 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
605 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
606 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
607 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
608 return rtc::IPAddress(v6addr);
609 }
610 break;
611 }
612 }
613 }
614 // Invalid ip family or transaction ID, or missing owner.
615 // Return an AF_UNSPEC address.
616 return rtc::IPAddress();
617}
618
jbauchf1f87202016-03-30 06:43:37 -0700619bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000620 if (!StunAddressAttribute::Read(buf))
621 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200622 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000623 rtc::IPAddress xored_ip = GetXoredIP();
624 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
625 return true;
626}
627
jbauchf1f87202016-03-30 06:43:37 -0700628bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000629 StunAddressFamily address_family = family();
630 if (address_family == STUN_ADDRESS_UNDEF) {
631 LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
632 return false;
633 }
634 rtc::IPAddress xored_ip = GetXoredIP();
635 if (xored_ip.family() == AF_UNSPEC) {
636 return false;
637 }
638 buf->WriteUInt8(0);
639 buf->WriteUInt8(family());
640 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
641 switch (xored_ip.family()) {
642 case AF_INET: {
643 in_addr v4addr = xored_ip.ipv4_address();
644 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
645 break;
646 }
647 case AF_INET6: {
648 in6_addr v6addr = xored_ip.ipv6_address();
649 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
650 break;
651 }
652 }
653 return true;
654}
655
Peter Boström0c4e06b2015-10-07 12:23:21 +0200656StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000657 : StunAttribute(type, SIZE), bits_(value) {
658}
659
Peter Boström0c4e06b2015-10-07 12:23:21 +0200660StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000661 : StunAttribute(type, SIZE), bits_(0) {
662}
663
664bool StunUInt32Attribute::GetBit(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800665 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000666 return static_cast<bool>((bits_ >> index) & 0x1);
667}
668
669void StunUInt32Attribute::SetBit(size_t index, bool value) {
nisseede5da42017-01-12 05:15:36 -0800670 RTC_DCHECK(index < 32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000671 bits_ &= ~(1 << index);
672 bits_ |= value ? (1 << index) : 0;
673}
674
jbauchf1f87202016-03-30 06:43:37 -0700675bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000676 if (length() != SIZE || !buf->ReadUInt32(&bits_))
677 return false;
678 return true;
679}
680
jbauchf1f87202016-03-30 06:43:37 -0700681bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000682 buf->WriteUInt32(bits_);
683 return true;
684}
685
Peter Boström0c4e06b2015-10-07 12:23:21 +0200686StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000687 : StunAttribute(type, SIZE), bits_(value) {
688}
689
Peter Boström0c4e06b2015-10-07 12:23:21 +0200690StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691 : StunAttribute(type, SIZE), bits_(0) {
692}
693
jbauchf1f87202016-03-30 06:43:37 -0700694bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000695 if (length() != SIZE || !buf->ReadUInt64(&bits_))
696 return false;
697 return true;
698}
699
jbauchf1f87202016-03-30 06:43:37 -0700700bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000701 buf->WriteUInt64(bits_);
702 return true;
703}
704
Peter Boström0c4e06b2015-10-07 12:23:21 +0200705StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000706 : StunAttribute(type, 0), bytes_(NULL) {
707}
708
Peter Boström0c4e06b2015-10-07 12:23:21 +0200709StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000710 const std::string& str)
711 : StunAttribute(type, 0), bytes_(NULL) {
712 CopyBytes(str.c_str(), str.size());
713}
714
Peter Boström0c4e06b2015-10-07 12:23:21 +0200715StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000716 const void* bytes,
717 size_t length)
718 : StunAttribute(type, 0), bytes_(NULL) {
719 CopyBytes(bytes, length);
720}
721
Peter Boström0c4e06b2015-10-07 12:23:21 +0200722StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000723 : StunAttribute(type, length), bytes_(NULL) {
724}
725
726StunByteStringAttribute::~StunByteStringAttribute() {
727 delete [] bytes_;
728}
729
730void StunByteStringAttribute::CopyBytes(const char* bytes) {
731 CopyBytes(bytes, strlen(bytes));
732}
733
734void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
735 char* new_bytes = new char[length];
736 memcpy(new_bytes, bytes, length);
737 SetBytes(new_bytes, length);
738}
739
Peter Boström0c4e06b2015-10-07 12:23:21 +0200740uint8_t StunByteStringAttribute::GetByte(size_t index) const {
nisseede5da42017-01-12 05:15:36 -0800741 RTC_DCHECK(bytes_ != NULL);
742 RTC_DCHECK(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200743 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000744}
745
Peter Boström0c4e06b2015-10-07 12:23:21 +0200746void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
nisseede5da42017-01-12 05:15:36 -0800747 RTC_DCHECK(bytes_ != NULL);
748 RTC_DCHECK(index < length());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000749 bytes_[index] = value;
750}
751
jbauchf1f87202016-03-30 06:43:37 -0700752bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000753 bytes_ = new char[length()];
754 if (!buf->ReadBytes(bytes_, length())) {
755 return false;
756 }
757
758 ConsumePadding(buf);
759 return true;
760}
761
jbauchf1f87202016-03-30 06:43:37 -0700762bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000763 buf->WriteBytes(bytes_, length());
764 WritePadding(buf);
765 return true;
766}
767
768void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
769 delete [] bytes_;
770 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200771 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000772}
773
zsteinf42cc9d2017-03-27 16:17:19 -0700774const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
775
Peter Boström0c4e06b2015-10-07 12:23:21 +0200776StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
777 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000778 const std::string& reason)
779 : StunAttribute(type, 0) {
780 SetCode(code);
781 SetReason(reason);
782}
783
Peter Boström0c4e06b2015-10-07 12:23:21 +0200784StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000785 : StunAttribute(type, length), class_(0), number_(0) {
786}
787
788StunErrorCodeAttribute::~StunErrorCodeAttribute() {
789}
790
791int StunErrorCodeAttribute::code() const {
792 return class_ * 100 + number_;
793}
794
795void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200796 class_ = static_cast<uint8_t>(code / 100);
797 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000798}
799
800void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200801 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000802 reason_ = reason;
803}
804
jbauchf1f87202016-03-30 06:43:37 -0700805bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200806 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000807 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
808 return false;
809
810 if ((val >> 11) != 0)
811 LOG(LS_ERROR) << "error-code bits not zero";
812
813 class_ = ((val >> 8) & 0x7);
814 number_ = (val & 0xff);
815
816 if (!buf->ReadString(&reason_, length() - 4))
817 return false;
818
819 ConsumePadding(buf);
820 return true;
821}
822
jbauchf1f87202016-03-30 06:43:37 -0700823bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000824 buf->WriteUInt32(class_ << 8 | number_);
825 buf->WriteString(reason_);
826 WritePadding(buf);
827 return true;
828}
829
Peter Boström0c4e06b2015-10-07 12:23:21 +0200830StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000831 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200832 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000833}
834
835StunUInt16ListAttribute::~StunUInt16ListAttribute() {
836 delete attr_types_;
837}
838
839size_t StunUInt16ListAttribute::Size() const {
840 return attr_types_->size();
841}
842
Peter Boström0c4e06b2015-10-07 12:23:21 +0200843uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000844 return (*attr_types_)[index];
845}
846
Peter Boström0c4e06b2015-10-07 12:23:21 +0200847void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000848 (*attr_types_)[index] = value;
849}
850
Peter Boström0c4e06b2015-10-07 12:23:21 +0200851void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000852 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200853 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000854}
855
jbauchf1f87202016-03-30 06:43:37 -0700856bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000857 if (length() % 2)
858 return false;
859
860 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200861 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000862 if (!buf->ReadUInt16(&attr))
863 return false;
864 attr_types_->push_back(attr);
865 }
866 // Padding of these attributes is done in RFC 5389 style. This is
867 // slightly different from RFC3489, but it shouldn't be important.
868 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
869 // entries in the list (not necessarily the last one - it's unspecified).
870 // RFC5389 pads on the end, and the bytes are always ignored.
871 ConsumePadding(buf);
872 return true;
873}
874
jbauchf1f87202016-03-30 06:43:37 -0700875bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000876 for (size_t i = 0; i < attr_types_->size(); ++i) {
877 buf->WriteUInt16((*attr_types_)[i]);
878 }
879 WritePadding(buf);
880 return true;
881}
882
883int GetStunSuccessResponseType(int req_type) {
884 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
885}
886
887int GetStunErrorResponseType(int req_type) {
888 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
889}
890
891bool IsStunRequestType(int msg_type) {
892 return ((msg_type & kStunTypeMask) == 0x000);
893}
894
895bool IsStunIndicationType(int msg_type) {
896 return ((msg_type & kStunTypeMask) == 0x010);
897}
898
899bool IsStunSuccessResponseType(int msg_type) {
900 return ((msg_type & kStunTypeMask) == 0x100);
901}
902
903bool IsStunErrorResponseType(int msg_type) {
904 return ((msg_type & kStunTypeMask) == 0x110);
905}
906
907bool ComputeStunCredentialHash(const std::string& username,
908 const std::string& realm,
909 const std::string& password,
910 std::string* hash) {
911 // http://tools.ietf.org/html/rfc5389#section-15.4
912 // long-term credentials will be calculated using the key and key is
913 // key = MD5(username ":" realm ":" SASLprep(password))
914 std::string input = username;
915 input += ':';
916 input += realm;
917 input += ':';
918 input += password;
919
920 char digest[rtc::MessageDigest::kMaxSize];
921 size_t size = rtc::ComputeDigest(
922 rtc::DIGEST_MD5, input.c_str(), input.size(),
923 digest, sizeof(digest));
924 if (size == 0) {
925 return false;
926 }
927
928 *hash = std::string(digest, size);
929 return true;
930}
931
932} // namespace cricket