blob: 9c229957555ef93e49541a53db15f04a4e7b1cbd [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
11#include "webrtc/p2p/base/stun.h"
12
13#include <string.h>
14
15#include "webrtc/base/byteorder.h"
16#include "webrtc/base/common.h"
17#include "webrtc/base/crc32.h"
18#include "webrtc/base/logging.h"
19#include "webrtc/base/messagedigest.h"
20#include "webrtc/base/scoped_ptr.h"
21#include "webrtc/base/stringencode.h"
22
23using rtc::ByteBuffer;
24
25namespace cricket {
26
27const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
28const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
29const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
30const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
31const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
32const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
33const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
34const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
35const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
36const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
37const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
38
39const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
40const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
Peter Boström0c4e06b2015-10-07 12:23:21 +020041const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000042
43// StunMessage
44
45StunMessage::StunMessage()
46 : type_(0),
47 length_(0),
48 transaction_id_(EMPTY_TRANSACTION_ID) {
49 ASSERT(IsValidTransactionId(transaction_id_));
50 attrs_ = new std::vector<StunAttribute*>();
51}
52
53StunMessage::~StunMessage() {
54 for (size_t i = 0; i < attrs_->size(); i++)
55 delete (*attrs_)[i];
56 delete attrs_;
57}
58
59bool StunMessage::IsLegacy() const {
60 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
61 return true;
62 ASSERT(transaction_id_.size() == kStunTransactionIdLength);
63 return false;
64}
65
66bool StunMessage::SetTransactionID(const std::string& str) {
67 if (!IsValidTransactionId(str)) {
68 return false;
69 }
70 transaction_id_ = str;
71 return true;
72}
73
74bool StunMessage::AddAttribute(StunAttribute* attr) {
75 // Fail any attributes that aren't valid for this type of message.
76 if (attr->value_type() != GetAttributeValueType(attr->type())) {
77 return false;
78 }
79 attrs_->push_back(attr);
80 attr->SetOwner(this);
81 size_t attr_length = attr->length();
82 if (attr_length % 4 != 0) {
83 attr_length += (4 - (attr_length % 4));
84 }
Peter Boström0c4e06b2015-10-07 12:23:21 +020085 length_ += static_cast<uint16_t>(attr_length + 4);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000086 return true;
87}
88
89const StunAddressAttribute* StunMessage::GetAddress(int type) const {
90 switch (type) {
91 case STUN_ATTR_MAPPED_ADDRESS: {
92 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
93 // missing.
94 const StunAttribute* mapped_address =
95 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
96 if (!mapped_address)
97 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
98 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
99 }
100
101 default:
102 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
103 }
104}
105
106const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
107 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
108}
109
110const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
111 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
112}
113
114const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
115 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
116}
117
118const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
119 return static_cast<const StunErrorCodeAttribute*>(
120 GetAttribute(STUN_ATTR_ERROR_CODE));
121}
122
123const 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.
133 if ((size % 4) != 0) {
134 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;
146 while (current_pos < 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 ||
155 current_pos + attr_length > size) {
156 return false;
157 }
158 has_message_integrity_attr = true;
159 break;
160 }
161
162 // Otherwise, skip to the next attribute.
163 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
164 if ((attr_length % 4) != 0) {
165 current_pos += (4 - (attr_length % 4));
166 }
167 }
168
169 if (!has_message_integrity_attr) {
170 return false;
171 }
172
173 // Getting length of the message to calculate Message Integrity.
174 size_t mi_pos = current_pos;
175 rtc::scoped_ptr<char[]> temp_data(new char[current_pos]);
176 memcpy(temp_data.get(), data, current_pos);
177 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
178 // Stun message has other attributes after message integrity.
179 // Adjust the length parameter in stun message to calculate HMAC.
180 size_t extra_offset = size -
181 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
182 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
183
184 // Writing new length of the STUN message @ Message Length in temp buffer.
185 // 0 1 2 3
186 // 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
187 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
188 // |0 0| STUN Message Type | Message Length |
189 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Peter Boström0c4e06b2015-10-07 12:23:21 +0200190 rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000191 }
192
193 char hmac[kStunMessageIntegritySize];
194 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
195 password.c_str(), password.size(),
196 temp_data.get(), mi_pos,
197 hmac, sizeof(hmac));
198 ASSERT(ret == sizeof(hmac));
199 if (ret != sizeof(hmac))
200 return false;
201
202 // Comparing the calculated HMAC with the one present in the message.
203 return memcmp(data + current_pos + kStunAttributeHeaderSize,
204 hmac,
205 sizeof(hmac)) == 0;
206}
207
208bool StunMessage::AddMessageIntegrity(const std::string& password) {
209 return AddMessageIntegrity(password.c_str(), password.size());
210}
211
212bool StunMessage::AddMessageIntegrity(const char* key,
213 size_t keylen) {
214 // Add the attribute with a dummy value. Since this is a known attribute, it
215 // can't fail.
216 StunByteStringAttribute* msg_integrity_attr =
217 new StunByteStringAttribute(STUN_ATTR_MESSAGE_INTEGRITY,
218 std::string(kStunMessageIntegritySize, '0'));
219 VERIFY(AddAttribute(msg_integrity_attr));
220
221 // Calculate the HMAC for the message.
222 rtc::ByteBuffer buf;
223 if (!Write(&buf))
224 return false;
225
226 int msg_len_for_hmac = static_cast<int>(
227 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
228 char hmac[kStunMessageIntegritySize];
229 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
230 key, keylen,
231 buf.Data(), msg_len_for_hmac,
232 hmac, sizeof(hmac));
233 ASSERT(ret == sizeof(hmac));
234 if (ret != sizeof(hmac)) {
235 LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
236 << "has dummy value.";
237 return false;
238 }
239
240 // Insert correct HMAC into the attribute.
241 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
242 return true;
243}
244
245// Verifies a message is in fact a STUN message, by performing the checks
246// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
247// in section 15.5.
248bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
249 // Check the message length.
250 size_t fingerprint_attr_size =
251 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
252 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
253 return false;
254
255 // Skip the rest if the magic cookie isn't present.
256 const char* magic_cookie =
257 data + kStunTransactionIdOffset - kStunMagicCookieLength;
258 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
259 return false;
260
261 // Check the fingerprint type and length.
262 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
263 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
Peter Boström0c4e06b2015-10-07 12:23:21 +0200264 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000265 StunUInt32Attribute::SIZE)
266 return false;
267
268 // Check the fingerprint value.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200269 uint32_t fingerprint =
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000270 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
271 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
272 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
273}
274
275bool StunMessage::AddFingerprint() {
276 // Add the attribute with a dummy value. Since this is a known attribute,
277 // it can't fail.
278 StunUInt32Attribute* fingerprint_attr =
279 new StunUInt32Attribute(STUN_ATTR_FINGERPRINT, 0);
280 VERIFY(AddAttribute(fingerprint_attr));
281
282 // Calculate the CRC-32 for the message and insert it.
283 rtc::ByteBuffer buf;
284 if (!Write(&buf))
285 return false;
286
287 int msg_len_for_crc32 = static_cast<int>(
288 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200289 uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000290
291 // Insert the correct CRC-32, XORed with a constant, into the attribute.
292 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
293 return true;
294}
295
296bool StunMessage::Read(ByteBuffer* buf) {
297 if (!buf->ReadUInt16(&type_))
298 return false;
299
300 if (type_ & 0x8000) {
301 // RTP and RTCP set the MSB of first byte, since first two bits are version,
302 // and version is always 2 (10). If set, this is not a STUN packet.
303 return false;
304 }
305
306 if (!buf->ReadUInt16(&length_))
307 return false;
308
309 std::string magic_cookie;
310 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
311 return false;
312
313 std::string transaction_id;
314 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
315 return false;
316
Peter Boström0c4e06b2015-10-07 12:23:21 +0200317 uint32_t magic_cookie_int =
318 *reinterpret_cast<const uint32_t*>(magic_cookie.data());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000319 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
320 // If magic cookie is invalid it means that the peer implements
321 // RFC3489 instead of RFC5389.
322 transaction_id.insert(0, magic_cookie);
323 }
324 ASSERT(IsValidTransactionId(transaction_id));
325 transaction_id_ = transaction_id;
326
327 if (length_ != buf->Length())
328 return false;
329
330 attrs_->resize(0);
331
332 size_t rest = buf->Length() - length_;
333 while (buf->Length() > rest) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200334 uint16_t attr_type, attr_length;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000335 if (!buf->ReadUInt16(&attr_type))
336 return false;
337 if (!buf->ReadUInt16(&attr_length))
338 return false;
339
340 StunAttribute* attr = CreateAttribute(attr_type, attr_length);
341 if (!attr) {
342 // Skip any unknown or malformed attributes.
343 if ((attr_length % 4) != 0) {
344 attr_length += (4 - (attr_length % 4));
345 }
346 if (!buf->Consume(attr_length))
347 return false;
348 } else {
349 if (!attr->Read(buf))
350 return false;
351 attrs_->push_back(attr);
352 }
353 }
354
355 ASSERT(buf->Length() == rest);
356 return true;
357}
358
359bool StunMessage::Write(ByteBuffer* buf) const {
360 buf->WriteUInt16(type_);
361 buf->WriteUInt16(length_);
362 if (!IsLegacy())
363 buf->WriteUInt32(kStunMagicCookie);
364 buf->WriteString(transaction_id_);
365
366 for (size_t i = 0; i < attrs_->size(); ++i) {
367 buf->WriteUInt16((*attrs_)[i]->type());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200368 buf->WriteUInt16(static_cast<uint16_t>((*attrs_)[i]->length()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000369 if (!(*attrs_)[i]->Write(buf))
370 return false;
371 }
372
373 return true;
374}
375
376StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
377 switch (type) {
378 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
379 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
380 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
381 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
382 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
383 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
384 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
385 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
386 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
387 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS;
388 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000389 case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000390 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
391 default: return STUN_VALUE_UNKNOWN;
392 }
393}
394
395StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
396 StunAttributeValueType value_type = GetAttributeValueType(type);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200397 return StunAttribute::Create(value_type, type, static_cast<uint16_t>(length),
398 this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000399}
400
401const StunAttribute* StunMessage::GetAttribute(int type) const {
402 for (size_t i = 0; i < attrs_->size(); ++i) {
403 if ((*attrs_)[i]->type() == type)
404 return (*attrs_)[i];
405 }
406 return NULL;
407}
408
409bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
410 return transaction_id.size() == kStunTransactionIdLength ||
411 transaction_id.size() == kStunLegacyTransactionIdLength;
412}
413
414// StunAttribute
415
Peter Boström0c4e06b2015-10-07 12:23:21 +0200416StunAttribute::StunAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000417 : type_(type), length_(length) {
418}
419
420void StunAttribute::ConsumePadding(rtc::ByteBuffer* buf) const {
421 int remainder = length_ % 4;
422 if (remainder > 0) {
423 buf->Consume(4 - remainder);
424 }
425}
426
427void StunAttribute::WritePadding(rtc::ByteBuffer* buf) const {
428 int remainder = length_ % 4;
429 if (remainder > 0) {
430 char zeroes[4] = {0};
431 buf->WriteBytes(zeroes, 4 - remainder);
432 }
433}
434
435StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200436 uint16_t type,
437 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000438 StunMessage* owner) {
439 switch (value_type) {
440 case STUN_VALUE_ADDRESS:
441 return new StunAddressAttribute(type, length);
442 case STUN_VALUE_XOR_ADDRESS:
443 return new StunXorAddressAttribute(type, length, owner);
444 case STUN_VALUE_UINT32:
445 return new StunUInt32Attribute(type);
446 case STUN_VALUE_UINT64:
447 return new StunUInt64Attribute(type);
448 case STUN_VALUE_BYTE_STRING:
449 return new StunByteStringAttribute(type, length);
450 case STUN_VALUE_ERROR_CODE:
451 return new StunErrorCodeAttribute(type, length);
452 case STUN_VALUE_UINT16_LIST:
453 return new StunUInt16ListAttribute(type, length);
454 default:
455 return NULL;
456 }
457}
458
Peter Boström0c4e06b2015-10-07 12:23:21 +0200459StunAddressAttribute* StunAttribute::CreateAddress(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000460 return new StunAddressAttribute(type, 0);
461}
462
Peter Boström0c4e06b2015-10-07 12:23:21 +0200463StunXorAddressAttribute* StunAttribute::CreateXorAddress(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000464 return new StunXorAddressAttribute(type, 0, NULL);
465}
466
Peter Boström0c4e06b2015-10-07 12:23:21 +0200467StunUInt64Attribute* StunAttribute::CreateUInt64(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000468 return new StunUInt64Attribute(type);
469}
470
Peter Boström0c4e06b2015-10-07 12:23:21 +0200471StunUInt32Attribute* StunAttribute::CreateUInt32(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000472 return new StunUInt32Attribute(type);
473}
474
Peter Boström0c4e06b2015-10-07 12:23:21 +0200475StunByteStringAttribute* StunAttribute::CreateByteString(uint16_t type) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000476 return new StunByteStringAttribute(type, 0);
477}
478
479StunErrorCodeAttribute* StunAttribute::CreateErrorCode() {
480 return new StunErrorCodeAttribute(
481 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
482}
483
484StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() {
485 return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
486}
487
Peter Boström0c4e06b2015-10-07 12:23:21 +0200488StunAddressAttribute::StunAddressAttribute(uint16_t type,
489 const rtc::SocketAddress& addr)
490 : StunAttribute(type, 0) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000491 SetAddress(addr);
492}
493
Peter Boström0c4e06b2015-10-07 12:23:21 +0200494StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000495 : StunAttribute(type, length) {
496}
497
498bool StunAddressAttribute::Read(ByteBuffer* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200499 uint8_t dummy;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000500 if (!buf->ReadUInt8(&dummy))
501 return false;
502
Peter Boström0c4e06b2015-10-07 12:23:21 +0200503 uint8_t stun_family;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000504 if (!buf->ReadUInt8(&stun_family)) {
505 return false;
506 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200507 uint16_t port;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000508 if (!buf->ReadUInt16(&port))
509 return false;
510 if (stun_family == STUN_ADDRESS_IPV4) {
511 in_addr v4addr;
512 if (length() != SIZE_IP4) {
513 return false;
514 }
515 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
516 return false;
517 }
518 rtc::IPAddress ipaddr(v4addr);
519 SetAddress(rtc::SocketAddress(ipaddr, port));
520 } else if (stun_family == STUN_ADDRESS_IPV6) {
521 in6_addr v6addr;
522 if (length() != SIZE_IP6) {
523 return false;
524 }
525 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
526 return false;
527 }
528 rtc::IPAddress ipaddr(v6addr);
529 SetAddress(rtc::SocketAddress(ipaddr, port));
530 } else {
531 return false;
532 }
533 return true;
534}
535
536bool StunAddressAttribute::Write(ByteBuffer* buf) const {
537 StunAddressFamily address_family = family();
538 if (address_family == STUN_ADDRESS_UNDEF) {
539 LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
540 return false;
541 }
542 buf->WriteUInt8(0);
543 buf->WriteUInt8(address_family);
544 buf->WriteUInt16(address_.port());
545 switch (address_.family()) {
546 case AF_INET: {
547 in_addr v4addr = address_.ipaddr().ipv4_address();
548 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
549 break;
550 }
551 case AF_INET6: {
552 in6_addr v6addr = address_.ipaddr().ipv6_address();
553 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
554 break;
555 }
556 }
557 return true;
558}
559
Peter Boström0c4e06b2015-10-07 12:23:21 +0200560StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
561 const rtc::SocketAddress& addr)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000562 : StunAddressAttribute(type, addr), owner_(NULL) {
563}
564
Peter Boström0c4e06b2015-10-07 12:23:21 +0200565StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
566 uint16_t length,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000567 StunMessage* owner)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200568 : StunAddressAttribute(type, length), owner_(owner) {
569}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000570
571rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
572 if (owner_) {
573 rtc::IPAddress ip = ipaddr();
574 switch (ip.family()) {
575 case AF_INET: {
576 in_addr v4addr = ip.ipv4_address();
577 v4addr.s_addr =
578 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
579 return rtc::IPAddress(v4addr);
580 }
581 case AF_INET6: {
582 in6_addr v6addr = ip.ipv6_address();
583 const std::string& transaction_id = owner_->transaction_id();
584 if (transaction_id.length() == kStunTransactionIdLength) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200585 uint32_t transactionid_as_ints[3];
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000586 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
587 transaction_id.length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200588 uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000589 // Transaction ID is in network byte order, but magic cookie
590 // is stored in host byte order.
591 ip_as_ints[0] =
592 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
593 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
594 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
595 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
596 return rtc::IPAddress(v6addr);
597 }
598 break;
599 }
600 }
601 }
602 // Invalid ip family or transaction ID, or missing owner.
603 // Return an AF_UNSPEC address.
604 return rtc::IPAddress();
605}
606
607bool StunXorAddressAttribute::Read(ByteBuffer* buf) {
608 if (!StunAddressAttribute::Read(buf))
609 return false;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200610 uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000611 rtc::IPAddress xored_ip = GetXoredIP();
612 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
613 return true;
614}
615
616bool StunXorAddressAttribute::Write(ByteBuffer* buf) const {
617 StunAddressFamily address_family = family();
618 if (address_family == STUN_ADDRESS_UNDEF) {
619 LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
620 return false;
621 }
622 rtc::IPAddress xored_ip = GetXoredIP();
623 if (xored_ip.family() == AF_UNSPEC) {
624 return false;
625 }
626 buf->WriteUInt8(0);
627 buf->WriteUInt8(family());
628 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
629 switch (xored_ip.family()) {
630 case AF_INET: {
631 in_addr v4addr = xored_ip.ipv4_address();
632 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
633 break;
634 }
635 case AF_INET6: {
636 in6_addr v6addr = xored_ip.ipv6_address();
637 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
638 break;
639 }
640 }
641 return true;
642}
643
Peter Boström0c4e06b2015-10-07 12:23:21 +0200644StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000645 : StunAttribute(type, SIZE), bits_(value) {
646}
647
Peter Boström0c4e06b2015-10-07 12:23:21 +0200648StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000649 : StunAttribute(type, SIZE), bits_(0) {
650}
651
652bool StunUInt32Attribute::GetBit(size_t index) const {
653 ASSERT(index < 32);
654 return static_cast<bool>((bits_ >> index) & 0x1);
655}
656
657void StunUInt32Attribute::SetBit(size_t index, bool value) {
658 ASSERT(index < 32);
659 bits_ &= ~(1 << index);
660 bits_ |= value ? (1 << index) : 0;
661}
662
663bool StunUInt32Attribute::Read(ByteBuffer* buf) {
664 if (length() != SIZE || !buf->ReadUInt32(&bits_))
665 return false;
666 return true;
667}
668
669bool StunUInt32Attribute::Write(ByteBuffer* buf) const {
670 buf->WriteUInt32(bits_);
671 return true;
672}
673
Peter Boström0c4e06b2015-10-07 12:23:21 +0200674StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000675 : StunAttribute(type, SIZE), bits_(value) {
676}
677
Peter Boström0c4e06b2015-10-07 12:23:21 +0200678StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000679 : StunAttribute(type, SIZE), bits_(0) {
680}
681
682bool StunUInt64Attribute::Read(ByteBuffer* buf) {
683 if (length() != SIZE || !buf->ReadUInt64(&bits_))
684 return false;
685 return true;
686}
687
688bool StunUInt64Attribute::Write(ByteBuffer* buf) const {
689 buf->WriteUInt64(bits_);
690 return true;
691}
692
Peter Boström0c4e06b2015-10-07 12:23:21 +0200693StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000694 : StunAttribute(type, 0), bytes_(NULL) {
695}
696
Peter Boström0c4e06b2015-10-07 12:23:21 +0200697StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000698 const std::string& str)
699 : StunAttribute(type, 0), bytes_(NULL) {
700 CopyBytes(str.c_str(), str.size());
701}
702
Peter Boström0c4e06b2015-10-07 12:23:21 +0200703StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000704 const void* bytes,
705 size_t length)
706 : StunAttribute(type, 0), bytes_(NULL) {
707 CopyBytes(bytes, length);
708}
709
Peter Boström0c4e06b2015-10-07 12:23:21 +0200710StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000711 : StunAttribute(type, length), bytes_(NULL) {
712}
713
714StunByteStringAttribute::~StunByteStringAttribute() {
715 delete [] bytes_;
716}
717
718void StunByteStringAttribute::CopyBytes(const char* bytes) {
719 CopyBytes(bytes, strlen(bytes));
720}
721
722void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
723 char* new_bytes = new char[length];
724 memcpy(new_bytes, bytes, length);
725 SetBytes(new_bytes, length);
726}
727
Peter Boström0c4e06b2015-10-07 12:23:21 +0200728uint8_t StunByteStringAttribute::GetByte(size_t index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000729 ASSERT(bytes_ != NULL);
730 ASSERT(index < length());
Peter Boström0c4e06b2015-10-07 12:23:21 +0200731 return static_cast<uint8_t>(bytes_[index]);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000732}
733
Peter Boström0c4e06b2015-10-07 12:23:21 +0200734void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000735 ASSERT(bytes_ != NULL);
736 ASSERT(index < length());
737 bytes_[index] = value;
738}
739
740bool StunByteStringAttribute::Read(ByteBuffer* buf) {
741 bytes_ = new char[length()];
742 if (!buf->ReadBytes(bytes_, length())) {
743 return false;
744 }
745
746 ConsumePadding(buf);
747 return true;
748}
749
750bool StunByteStringAttribute::Write(ByteBuffer* buf) const {
751 buf->WriteBytes(bytes_, length());
752 WritePadding(buf);
753 return true;
754}
755
756void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
757 delete [] bytes_;
758 bytes_ = bytes;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200759 SetLength(static_cast<uint16_t>(length));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000760}
761
Peter Boström0c4e06b2015-10-07 12:23:21 +0200762StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
763 int code,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000764 const std::string& reason)
765 : StunAttribute(type, 0) {
766 SetCode(code);
767 SetReason(reason);
768}
769
Peter Boström0c4e06b2015-10-07 12:23:21 +0200770StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000771 : StunAttribute(type, length), class_(0), number_(0) {
772}
773
774StunErrorCodeAttribute::~StunErrorCodeAttribute() {
775}
776
777int StunErrorCodeAttribute::code() const {
778 return class_ * 100 + number_;
779}
780
781void StunErrorCodeAttribute::SetCode(int code) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200782 class_ = static_cast<uint8_t>(code / 100);
783 number_ = static_cast<uint8_t>(code % 100);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000784}
785
786void StunErrorCodeAttribute::SetReason(const std::string& reason) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200787 SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000788 reason_ = reason;
789}
790
791bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200792 uint32_t val;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000793 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
794 return false;
795
796 if ((val >> 11) != 0)
797 LOG(LS_ERROR) << "error-code bits not zero";
798
799 class_ = ((val >> 8) & 0x7);
800 number_ = (val & 0xff);
801
802 if (!buf->ReadString(&reason_, length() - 4))
803 return false;
804
805 ConsumePadding(buf);
806 return true;
807}
808
809bool StunErrorCodeAttribute::Write(ByteBuffer* buf) const {
810 buf->WriteUInt32(class_ << 8 | number_);
811 buf->WriteString(reason_);
812 WritePadding(buf);
813 return true;
814}
815
Peter Boström0c4e06b2015-10-07 12:23:21 +0200816StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000817 : StunAttribute(type, length) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200818 attr_types_ = new std::vector<uint16_t>();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000819}
820
821StunUInt16ListAttribute::~StunUInt16ListAttribute() {
822 delete attr_types_;
823}
824
825size_t StunUInt16ListAttribute::Size() const {
826 return attr_types_->size();
827}
828
Peter Boström0c4e06b2015-10-07 12:23:21 +0200829uint16_t StunUInt16ListAttribute::GetType(int index) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000830 return (*attr_types_)[index];
831}
832
Peter Boström0c4e06b2015-10-07 12:23:21 +0200833void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000834 (*attr_types_)[index] = value;
835}
836
Peter Boström0c4e06b2015-10-07 12:23:21 +0200837void StunUInt16ListAttribute::AddType(uint16_t value) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000838 attr_types_->push_back(value);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200839 SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000840}
841
842bool StunUInt16ListAttribute::Read(ByteBuffer* buf) {
843 if (length() % 2)
844 return false;
845
846 for (size_t i = 0; i < length() / 2; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200847 uint16_t attr;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000848 if (!buf->ReadUInt16(&attr))
849 return false;
850 attr_types_->push_back(attr);
851 }
852 // Padding of these attributes is done in RFC 5389 style. This is
853 // slightly different from RFC3489, but it shouldn't be important.
854 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
855 // entries in the list (not necessarily the last one - it's unspecified).
856 // RFC5389 pads on the end, and the bytes are always ignored.
857 ConsumePadding(buf);
858 return true;
859}
860
861bool StunUInt16ListAttribute::Write(ByteBuffer* buf) const {
862 for (size_t i = 0; i < attr_types_->size(); ++i) {
863 buf->WriteUInt16((*attr_types_)[i]);
864 }
865 WritePadding(buf);
866 return true;
867}
868
869int GetStunSuccessResponseType(int req_type) {
870 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
871}
872
873int GetStunErrorResponseType(int req_type) {
874 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
875}
876
877bool IsStunRequestType(int msg_type) {
878 return ((msg_type & kStunTypeMask) == 0x000);
879}
880
881bool IsStunIndicationType(int msg_type) {
882 return ((msg_type & kStunTypeMask) == 0x010);
883}
884
885bool IsStunSuccessResponseType(int msg_type) {
886 return ((msg_type & kStunTypeMask) == 0x100);
887}
888
889bool IsStunErrorResponseType(int msg_type) {
890 return ((msg_type & kStunTypeMask) == 0x110);
891}
892
893bool ComputeStunCredentialHash(const std::string& username,
894 const std::string& realm,
895 const std::string& password,
896 std::string* hash) {
897 // http://tools.ietf.org/html/rfc5389#section-15.4
898 // long-term credentials will be calculated using the key and key is
899 // key = MD5(username ":" realm ":" SASLprep(password))
900 std::string input = username;
901 input += ':';
902 input += realm;
903 input += ':';
904 input += password;
905
906 char digest[rtc::MessageDigest::kMaxSize];
907 size_t size = rtc::ComputeDigest(
908 rtc::DIGEST_MD5, input.c_str(), input.size(),
909 digest, sizeof(digest));
910 if (size == 0) {
911 return false;
912 }
913
914 *hash = std::string(digest, size);
915 return true;
916}
917
918} // namespace cricket