blob: ac3fd5f9368bda2e7b2b042be87ee4db5e31b09f [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:111/*
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
11#include "webrtc/p2p/base/stun.h"
12
13#include <string.h>
14
kwiberg3ec46792016-04-27 14:22:5315#include <memory>
16
henrike@webrtc.org269fb4b2014-10-28 22:20:1117#include "webrtc/base/byteorder.h"
18#include "webrtc/base/common.h"
19#include "webrtc/base/crc32.h"
20#include "webrtc/base/logging.h"
21#include "webrtc/base/messagedigest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:1122#include "webrtc/base/stringencode.h"
23
jbauchf1f87202016-03-30 13:43:3724using rtc::ByteBufferReader;
25using rtc::ByteBufferWriter;
henrike@webrtc.org269fb4b2014-10-28 22:20:1126
27namespace cricket {
28
29const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
30const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
31const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
32const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
33const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
34const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
35const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
36const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
37const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
38const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
39const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
40
41const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
42const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 10:23:2143const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
henrike@webrtc.org269fb4b2014-10-28 22:20:1144
45// StunMessage
46
47StunMessage::StunMessage()
48 : type_(0),
49 length_(0),
50 transaction_id_(EMPTY_TRANSACTION_ID) {
51 ASSERT(IsValidTransactionId(transaction_id_));
52 attrs_ = new std::vector<StunAttribute*>();
53}
54
55StunMessage::~StunMessage() {
56 for (size_t i = 0; i < attrs_->size(); i++)
57 delete (*attrs_)[i];
58 delete attrs_;
59}
60
61bool StunMessage::IsLegacy() const {
62 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
63 return true;
64 ASSERT(transaction_id_.size() == kStunTransactionIdLength);
65 return false;
66}
67
68bool StunMessage::SetTransactionID(const std::string& str) {
69 if (!IsValidTransactionId(str)) {
70 return false;
71 }
72 transaction_id_ = str;
73 return true;
74}
75
76bool StunMessage::AddAttribute(StunAttribute* attr) {
77 // Fail any attributes that aren't valid for this type of message.
78 if (attr->value_type() != GetAttributeValueType(attr->type())) {
79 return false;
80 }
81 attrs_->push_back(attr);
82 attr->SetOwner(this);
83 size_t attr_length = attr->length();
84 if (attr_length % 4 != 0) {
85 attr_length += (4 - (attr_length % 4));
86 }
Peter Boström0c4e06b2015-10-07 10:23:2187 length_ += static_cast<uint16_t>(attr_length + 4);
henrike@webrtc.org269fb4b2014-10-28 22:20:1188 return true;
89}
90
91const StunAddressAttribute* StunMessage::GetAddress(int type) const {
92 switch (type) {
93 case STUN_ATTR_MAPPED_ADDRESS: {
94 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
95 // missing.
96 const StunAttribute* mapped_address =
97 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
98 if (!mapped_address)
99 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
100 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
101 }
102
103 default:
104 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
105 }
106}
107
108const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
109 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
110}
111
112const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
113 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
114}
115
116const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
117 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
118}
119
120const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
121 return static_cast<const StunErrorCodeAttribute*>(
122 GetAttribute(STUN_ATTR_ERROR_CODE));
123}
124
125const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
126 return static_cast<const StunUInt16ListAttribute*>(
127 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
128}
129
130// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
131// procedure outlined in RFC 5389, section 15.4.
132bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
133 const std::string& password) {
134 // Verifying the size of the message.
135 if ((size % 4) != 0) {
136 return false;
137 }
138
139 // Getting the message length from the STUN header.
Peter Boström0c4e06b2015-10-07 10:23:21140 uint16_t msg_length = rtc::GetBE16(&data[2]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11141 if (size != (msg_length + kStunHeaderSize)) {
142 return false;
143 }
144
145 // Finding Message Integrity attribute in stun message.
146 size_t current_pos = kStunHeaderSize;
147 bool has_message_integrity_attr = false;
148 while (current_pos < size) {
Peter Boström0c4e06b2015-10-07 10:23:21149 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11150 // Getting attribute type and length.
151 attr_type = rtc::GetBE16(&data[current_pos]);
152 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
153
154 // If M-I, sanity check it, and break out.
155 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
156 if (attr_length != kStunMessageIntegritySize ||
157 current_pos + attr_length > size) {
158 return false;
159 }
160 has_message_integrity_attr = true;
161 break;
162 }
163
164 // Otherwise, skip to the next attribute.
165 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
166 if ((attr_length % 4) != 0) {
167 current_pos += (4 - (attr_length % 4));
168 }
169 }
170
171 if (!has_message_integrity_attr) {
172 return false;
173 }
174
175 // Getting length of the message to calculate Message Integrity.
176 size_t mi_pos = current_pos;
kwiberg3ec46792016-04-27 14:22:53177 std::unique_ptr<char[]> temp_data(new char[current_pos]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11178 memcpy(temp_data.get(), data, current_pos);
179 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
180 // Stun message has other attributes after message integrity.
181 // Adjust the length parameter in stun message to calculate HMAC.
182 size_t extra_offset = size -
183 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
184 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
185
186 // Writing new length of the STUN message @ Message Length in temp buffer.
187 // 0 1 2 3
188 // 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
189 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190 // |0 0| STUN Message Type | Message Length |
191 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 10:23:21192 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11193 }
194
195 char hmac[kStunMessageIntegritySize];
196 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
197 password.c_str(), password.size(),
198 temp_data.get(), mi_pos,
199 hmac, sizeof(hmac));
200 ASSERT(ret == sizeof(hmac));
201 if (ret != sizeof(hmac))
202 return false;
203
204 // Comparing the calculated HMAC with the one present in the message.
205 return memcmp(data + current_pos + kStunAttributeHeaderSize,
206 hmac,
207 sizeof(hmac)) == 0;
208}
209
210bool StunMessage::AddMessageIntegrity(const std::string& password) {
211 return AddMessageIntegrity(password.c_str(), password.size());
212}
213
214bool StunMessage::AddMessageIntegrity(const char* key,
215 size_t keylen) {
216 // Add the attribute with a dummy value. Since this is a known attribute, it
217 // can't fail.
218 StunByteStringAttribute* msg_integrity_attr =
219 new StunByteStringAttribute(STUN_ATTR_MESSAGE_INTEGRITY,
220 std::string(kStunMessageIntegritySize, '0'));
221 VERIFY(AddAttribute(msg_integrity_attr));
222
223 // Calculate the HMAC for the message.
jbauchf1f87202016-03-30 13:43:37224 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11225 if (!Write(&buf))
226 return false;
227
228 int msg_len_for_hmac = static_cast<int>(
229 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
230 char hmac[kStunMessageIntegritySize];
231 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
232 key, keylen,
233 buf.Data(), msg_len_for_hmac,
234 hmac, sizeof(hmac));
235 ASSERT(ret == sizeof(hmac));
236 if (ret != sizeof(hmac)) {
237 LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
238 << "has dummy value.";
239 return false;
240 }
241
242 // Insert correct HMAC into the attribute.
243 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
244 return true;
245}
246
247// Verifies a message is in fact a STUN message, by performing the checks
248// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
249// in section 15.5.
250bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
251 // Check the message length.
252 size_t fingerprint_attr_size =
253 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
254 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
255 return false;
256
257 // Skip the rest if the magic cookie isn't present.
258 const char* magic_cookie =
259 data + kStunTransactionIdOffset - kStunMagicCookieLength;
260 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
261 return false;
262
263 // Check the fingerprint type and length.
264 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
265 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 10:23:21266 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11267 StunUInt32Attribute::SIZE)
268 return false;
269
270 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 10:23:21271 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11272 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
273 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
274 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
275}
276
277bool StunMessage::AddFingerprint() {
278 // Add the attribute with a dummy value. Since this is a known attribute,
279 // it can't fail.
280 StunUInt32Attribute* fingerprint_attr =
281 new StunUInt32Attribute(STUN_ATTR_FINGERPRINT, 0);
282 VERIFY(AddAttribute(fingerprint_attr));
283
284 // Calculate the CRC-32 for the message and insert it.
jbauchf1f87202016-03-30 13:43:37285 ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11286 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 10:23:21291 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11292
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 13:43:37298bool StunMessage::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11299 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 10:23:21319 uint32_t magic_cookie_int =
320 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11321 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 }
326 ASSERT(IsValidTransactionId(transaction_id));
327 transaction_id_ = transaction_id;
328
329 if (length_ != buf->Length())
330 return false;
331
332 attrs_->resize(0);
333
334 size_t rest = buf->Length() - length_;
335 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 10:23:21336 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11337 if (!buf->ReadUInt16(&attr_type))
338 return false;
339 if (!buf->ReadUInt16(&attr_length))
340 return false;
341
342 StunAttribute* attr = CreateAttribute(attr_type, attr_length);
343 if (!attr) {
344 // Skip any unknown or malformed attributes.
345 if ((attr_length % 4) != 0) {
346 attr_length += (4 - (attr_length % 4));
347 }
348 if (!buf->Consume(attr_length))
349 return false;
350 } else {
351 if (!attr->Read(buf))
352 return false;
353 attrs_->push_back(attr);
354 }
355 }
356
357 ASSERT(buf->Length() == rest);
358 return true;
359}
360
jbauchf1f87202016-03-30 13:43:37361bool StunMessage::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11362 buf->WriteUInt16(type_);
363 buf->WriteUInt16(length_);
364 if (!IsLegacy())
365 buf->WriteUInt32(kStunMagicCookie);
366 buf->WriteString(transaction_id_);
367
368 for (size_t i = 0; i < attrs_->size(); ++i) {
369 buf->WriteUInt16((*attrs_)[i]->type());
Peter Boström0c4e06b2015-10-07 10:23:21370 buf->WriteUInt16(static_cast<uint16_t>((*attrs_)[i]->length()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11371 if (!(*attrs_)[i]->Write(buf))
372 return false;
373 }
374
375 return true;
376}
377
378StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
379 switch (type) {
380 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
381 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
382 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
383 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
384 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
385 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
386 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
387 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
388 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
389 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS;
390 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
pthatcher@webrtc.org0ba15332015-01-10 00:47:02391 case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING;
henrike@webrtc.org269fb4b2014-10-28 22:20:11392 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
393 default: return STUN_VALUE_UNKNOWN;
394 }
395}
396
397StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
398 StunAttributeValueType value_type = GetAttributeValueType(type);
Peter Boström0c4e06b2015-10-07 10:23:21399 return StunAttribute::Create(value_type, type, static_cast<uint16_t>(length),
400 this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11401}
402
403const StunAttribute* StunMessage::GetAttribute(int type) const {
404 for (size_t i = 0; i < attrs_->size(); ++i) {
405 if ((*attrs_)[i]->type() == type)
406 return (*attrs_)[i];
407 }
408 return NULL;
409}
410
411bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
412 return transaction_id.size() == kStunTransactionIdLength ||
413 transaction_id.size() == kStunLegacyTransactionIdLength;
414}
415
416// StunAttribute
417
Peter Boström0c4e06b2015-10-07 10:23:21418StunAttribute::StunAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11419 : type_(type), length_(length) {
420}
421
jbauchf1f87202016-03-30 13:43:37422void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11423 int remainder = length_ % 4;
424 if (remainder > 0) {
425 buf->Consume(4 - remainder);
426 }
427}
428
jbauchf1f87202016-03-30 13:43:37429void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11430 int remainder = length_ % 4;
431 if (remainder > 0) {
432 char zeroes[4] = {0};
433 buf->WriteBytes(zeroes, 4 - remainder);
434 }
435}
436
437StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 10:23:21438 uint16_t type,
439 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11440 StunMessage* owner) {
441 switch (value_type) {
442 case STUN_VALUE_ADDRESS:
443 return new StunAddressAttribute(type, length);
444 case STUN_VALUE_XOR_ADDRESS:
445 return new StunXorAddressAttribute(type, length, owner);
446 case STUN_VALUE_UINT32:
447 return new StunUInt32Attribute(type);
448 case STUN_VALUE_UINT64:
449 return new StunUInt64Attribute(type);
450 case STUN_VALUE_BYTE_STRING:
451 return new StunByteStringAttribute(type, length);
452 case STUN_VALUE_ERROR_CODE:
453 return new StunErrorCodeAttribute(type, length);
454 case STUN_VALUE_UINT16_LIST:
455 return new StunUInt16ListAttribute(type, length);
456 default:
457 return NULL;
458 }
459}
460
Peter Boström0c4e06b2015-10-07 10:23:21461StunAddressAttribute* StunAttribute::CreateAddress(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11462 return new StunAddressAttribute(type, 0);
463}
464
Peter Boström0c4e06b2015-10-07 10:23:21465StunXorAddressAttribute* StunAttribute::CreateXorAddress(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11466 return new StunXorAddressAttribute(type, 0, NULL);
467}
468
Peter Boström0c4e06b2015-10-07 10:23:21469StunUInt64Attribute* StunAttribute::CreateUInt64(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11470 return new StunUInt64Attribute(type);
471}
472
Peter Boström0c4e06b2015-10-07 10:23:21473StunUInt32Attribute* StunAttribute::CreateUInt32(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11474 return new StunUInt32Attribute(type);
475}
476
Peter Boström0c4e06b2015-10-07 10:23:21477StunByteStringAttribute* StunAttribute::CreateByteString(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11478 return new StunByteStringAttribute(type, 0);
479}
480
481StunErrorCodeAttribute* StunAttribute::CreateErrorCode() {
482 return new StunErrorCodeAttribute(
483 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
484}
485
486StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() {
487 return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
488}
489
Peter Boström0c4e06b2015-10-07 10:23:21490StunAddressAttribute::StunAddressAttribute(uint16_t type,
491 const rtc::SocketAddress& addr)
492 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11493 SetAddress(addr);
494}
495
Peter Boström0c4e06b2015-10-07 10:23:21496StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11497 : StunAttribute(type, length) {
498}
499
jbauchf1f87202016-03-30 13:43:37500bool StunAddressAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 10:23:21501 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11502 if (!buf->ReadUInt8(&dummy))
503 return false;
504
Peter Boström0c4e06b2015-10-07 10:23:21505 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11506 if (!buf->ReadUInt8(&stun_family)) {
507 return false;
508 }
Peter Boström0c4e06b2015-10-07 10:23:21509 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11510 if (!buf->ReadUInt16(&port))
511 return false;
512 if (stun_family == STUN_ADDRESS_IPV4) {
513 in_addr v4addr;
514 if (length() != SIZE_IP4) {
515 return false;
516 }
517 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
518 return false;
519 }
520 rtc::IPAddress ipaddr(v4addr);
521 SetAddress(rtc::SocketAddress(ipaddr, port));
522 } else if (stun_family == STUN_ADDRESS_IPV6) {
523 in6_addr v6addr;
524 if (length() != SIZE_IP6) {
525 return false;
526 }
527 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
528 return false;
529 }
530 rtc::IPAddress ipaddr(v6addr);
531 SetAddress(rtc::SocketAddress(ipaddr, port));
532 } else {
533 return false;
534 }
535 return true;
536}
537
jbauchf1f87202016-03-30 13:43:37538bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11539 StunAddressFamily address_family = family();
540 if (address_family == STUN_ADDRESS_UNDEF) {
541 LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
542 return false;
543 }
544 buf->WriteUInt8(0);
545 buf->WriteUInt8(address_family);
546 buf->WriteUInt16(address_.port());
547 switch (address_.family()) {
548 case AF_INET: {
549 in_addr v4addr = address_.ipaddr().ipv4_address();
550 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
551 break;
552 }
553 case AF_INET6: {
554 in6_addr v6addr = address_.ipaddr().ipv6_address();
555 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
556 break;
557 }
558 }
559 return true;
560}
561
Peter Boström0c4e06b2015-10-07 10:23:21562StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
563 const rtc::SocketAddress& addr)
henrike@webrtc.org269fb4b2014-10-28 22:20:11564 : StunAddressAttribute(type, addr), owner_(NULL) {
565}
566
Peter Boström0c4e06b2015-10-07 10:23:21567StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
568 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11569 StunMessage* owner)
Peter Boström0c4e06b2015-10-07 10:23:21570 : StunAddressAttribute(type, length), owner_(owner) {
571}
henrike@webrtc.org269fb4b2014-10-28 22:20:11572
573rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
574 if (owner_) {
575 rtc::IPAddress ip = ipaddr();
576 switch (ip.family()) {
577 case AF_INET: {
578 in_addr v4addr = ip.ipv4_address();
579 v4addr.s_addr =
580 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
581 return rtc::IPAddress(v4addr);
582 }
583 case AF_INET6: {
584 in6_addr v6addr = ip.ipv6_address();
585 const std::string& transaction_id = owner_->transaction_id();
586 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 10:23:21587 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11588 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
589 transaction_id.length());
Peter Boström0c4e06b2015-10-07 10:23:21590 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11591 // Transaction ID is in network byte order, but magic cookie
592 // is stored in host byte order.
593 ip_as_ints[0] =
594 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
595 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
596 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
597 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
598 return rtc::IPAddress(v6addr);
599 }
600 break;
601 }
602 }
603 }
604 // Invalid ip family or transaction ID, or missing owner.
605 // Return an AF_UNSPEC address.
606 return rtc::IPAddress();
607}
608
jbauchf1f87202016-03-30 13:43:37609bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11610 if (!StunAddressAttribute::Read(buf))
611 return false;
Peter Boström0c4e06b2015-10-07 10:23:21612 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11613 rtc::IPAddress xored_ip = GetXoredIP();
614 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
615 return true;
616}
617
jbauchf1f87202016-03-30 13:43:37618bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11619 StunAddressFamily address_family = family();
620 if (address_family == STUN_ADDRESS_UNDEF) {
621 LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
622 return false;
623 }
624 rtc::IPAddress xored_ip = GetXoredIP();
625 if (xored_ip.family() == AF_UNSPEC) {
626 return false;
627 }
628 buf->WriteUInt8(0);
629 buf->WriteUInt8(family());
630 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
631 switch (xored_ip.family()) {
632 case AF_INET: {
633 in_addr v4addr = xored_ip.ipv4_address();
634 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
635 break;
636 }
637 case AF_INET6: {
638 in6_addr v6addr = xored_ip.ipv6_address();
639 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
640 break;
641 }
642 }
643 return true;
644}
645
Peter Boström0c4e06b2015-10-07 10:23:21646StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11647 : StunAttribute(type, SIZE), bits_(value) {
648}
649
Peter Boström0c4e06b2015-10-07 10:23:21650StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11651 : StunAttribute(type, SIZE), bits_(0) {
652}
653
654bool StunUInt32Attribute::GetBit(size_t index) const {
655 ASSERT(index < 32);
656 return static_cast<bool>((bits_ >> index) & 0x1);
657}
658
659void StunUInt32Attribute::SetBit(size_t index, bool value) {
660 ASSERT(index < 32);
661 bits_ &= ~(1 << index);
662 bits_ |= value ? (1 << index) : 0;
663}
664
jbauchf1f87202016-03-30 13:43:37665bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11666 if (length() != SIZE || !buf->ReadUInt32(&bits_))
667 return false;
668 return true;
669}
670
jbauchf1f87202016-03-30 13:43:37671bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11672 buf->WriteUInt32(bits_);
673 return true;
674}
675
Peter Boström0c4e06b2015-10-07 10:23:21676StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11677 : StunAttribute(type, SIZE), bits_(value) {
678}
679
Peter Boström0c4e06b2015-10-07 10:23:21680StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11681 : StunAttribute(type, SIZE), bits_(0) {
682}
683
jbauchf1f87202016-03-30 13:43:37684bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11685 if (length() != SIZE || !buf->ReadUInt64(&bits_))
686 return false;
687 return true;
688}
689
jbauchf1f87202016-03-30 13:43:37690bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11691 buf->WriteUInt64(bits_);
692 return true;
693}
694
Peter Boström0c4e06b2015-10-07 10:23:21695StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11696 : StunAttribute(type, 0), bytes_(NULL) {
697}
698
Peter Boström0c4e06b2015-10-07 10:23:21699StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11700 const std::string& str)
701 : StunAttribute(type, 0), bytes_(NULL) {
702 CopyBytes(str.c_str(), str.size());
703}
704
Peter Boström0c4e06b2015-10-07 10:23:21705StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11706 const void* bytes,
707 size_t length)
708 : StunAttribute(type, 0), bytes_(NULL) {
709 CopyBytes(bytes, length);
710}
711
Peter Boström0c4e06b2015-10-07 10:23:21712StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11713 : StunAttribute(type, length), bytes_(NULL) {
714}
715
716StunByteStringAttribute::~StunByteStringAttribute() {
717 delete [] bytes_;
718}
719
720void StunByteStringAttribute::CopyBytes(const char* bytes) {
721 CopyBytes(bytes, strlen(bytes));
722}
723
724void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
725 char* new_bytes = new char[length];
726 memcpy(new_bytes, bytes, length);
727 SetBytes(new_bytes, length);
728}
729
Peter Boström0c4e06b2015-10-07 10:23:21730uint8_t StunByteStringAttribute::GetByte(size_t index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11731 ASSERT(bytes_ != NULL);
732 ASSERT(index < length());
Peter Boström0c4e06b2015-10-07 10:23:21733 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11734}
735
Peter Boström0c4e06b2015-10-07 10:23:21736void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11737 ASSERT(bytes_ != NULL);
738 ASSERT(index < length());
739 bytes_[index] = value;
740}
741
jbauchf1f87202016-03-30 13:43:37742bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11743 bytes_ = new char[length()];
744 if (!buf->ReadBytes(bytes_, length())) {
745 return false;
746 }
747
748 ConsumePadding(buf);
749 return true;
750}
751
jbauchf1f87202016-03-30 13:43:37752bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11753 buf->WriteBytes(bytes_, length());
754 WritePadding(buf);
755 return true;
756}
757
758void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
759 delete [] bytes_;
760 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 10:23:21761 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11762}
763
Peter Boström0c4e06b2015-10-07 10:23:21764StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
765 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11766 const std::string& reason)
767 : StunAttribute(type, 0) {
768 SetCode(code);
769 SetReason(reason);
770}
771
Peter Boström0c4e06b2015-10-07 10:23:21772StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11773 : StunAttribute(type, length), class_(0), number_(0) {
774}
775
776StunErrorCodeAttribute::~StunErrorCodeAttribute() {
777}
778
779int StunErrorCodeAttribute::code() const {
780 return class_ * 100 + number_;
781}
782
783void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 10:23:21784 class_ = static_cast<uint8_t>(code / 100);
785 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11786}
787
788void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 10:23:21789 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11790 reason_ = reason;
791}
792
jbauchf1f87202016-03-30 13:43:37793bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
Peter Boström0c4e06b2015-10-07 10:23:21794 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11795 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
796 return false;
797
798 if ((val >> 11) != 0)
799 LOG(LS_ERROR) << "error-code bits not zero";
800
801 class_ = ((val >> 8) & 0x7);
802 number_ = (val & 0xff);
803
804 if (!buf->ReadString(&reason_, length() - 4))
805 return false;
806
807 ConsumePadding(buf);
808 return true;
809}
810
jbauchf1f87202016-03-30 13:43:37811bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11812 buf->WriteUInt32(class_ << 8 | number_);
813 buf->WriteString(reason_);
814 WritePadding(buf);
815 return true;
816}
817
Peter Boström0c4e06b2015-10-07 10:23:21818StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11819 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 10:23:21820 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11821}
822
823StunUInt16ListAttribute::~StunUInt16ListAttribute() {
824 delete attr_types_;
825}
826
827size_t StunUInt16ListAttribute::Size() const {
828 return attr_types_->size();
829}
830
Peter Boström0c4e06b2015-10-07 10:23:21831uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11832 return (*attr_types_)[index];
833}
834
Peter Boström0c4e06b2015-10-07 10:23:21835void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11836 (*attr_types_)[index] = value;
837}
838
Peter Boström0c4e06b2015-10-07 10:23:21839void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11840 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 10:23:21841 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11842}
843
jbauchf1f87202016-03-30 13:43:37844bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11845 if (length() % 2)
846 return false;
847
848 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 10:23:21849 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11850 if (!buf->ReadUInt16(&attr))
851 return false;
852 attr_types_->push_back(attr);
853 }
854 // Padding of these attributes is done in RFC 5389 style. This is
855 // slightly different from RFC3489, but it shouldn't be important.
856 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
857 // entries in the list (not necessarily the last one - it's unspecified).
858 // RFC5389 pads on the end, and the bytes are always ignored.
859 ConsumePadding(buf);
860 return true;
861}
862
jbauchf1f87202016-03-30 13:43:37863bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11864 for (size_t i = 0; i < attr_types_->size(); ++i) {
865 buf->WriteUInt16((*attr_types_)[i]);
866 }
867 WritePadding(buf);
868 return true;
869}
870
871int GetStunSuccessResponseType(int req_type) {
872 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
873}
874
875int GetStunErrorResponseType(int req_type) {
876 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
877}
878
879bool IsStunRequestType(int msg_type) {
880 return ((msg_type & kStunTypeMask) == 0x000);
881}
882
883bool IsStunIndicationType(int msg_type) {
884 return ((msg_type & kStunTypeMask) == 0x010);
885}
886
887bool IsStunSuccessResponseType(int msg_type) {
888 return ((msg_type & kStunTypeMask) == 0x100);
889}
890
891bool IsStunErrorResponseType(int msg_type) {
892 return ((msg_type & kStunTypeMask) == 0x110);
893}
894
895bool ComputeStunCredentialHash(const std::string& username,
896 const std::string& realm,
897 const std::string& password,
898 std::string* hash) {
899 // http://tools.ietf.org/html/rfc5389#section-15.4
900 // long-term credentials will be calculated using the key and key is
901 // key = MD5(username ":" realm ":" SASLprep(password))
902 std::string input = username;
903 input += ':';
904 input += realm;
905 input += ':';
906 input += password;
907
908 char digest[rtc::MessageDigest::kMaxSize];
909 size_t size = rtc::ComputeDigest(
910 rtc::DIGEST_MD5, input.c_str(), input.size(),
911 digest, sizeof(digest));
912 if (size == 0) {
913 return false;
914 }
915
916 *hash = std::string(digest, size);
917 return true;
918}
919
920} // namespace cricket