3 * Copyright 2004--2005, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "talk/p2p/base/stun.h"
32 #include "webrtc/base/byteorder.h"
33 #include "webrtc/base/common.h"
34 #include "webrtc/base/crc32.h"
35 #include "webrtc/base/logging.h"
36 #include "webrtc/base/messagedigest.h"
37 #include "webrtc/base/scoped_ptr.h"
38 #include "webrtc/base/stringencode.h"
40 using rtc::ByteBuffer;
44 const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
45 const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
46 const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
47 const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
48 const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
49 const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
50 const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
51 const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
52 const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
53 const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
55 const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
56 const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
57 const uint32 STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
61 StunMessage::StunMessage()
64 transaction_id_(EMPTY_TRANSACTION_ID) {
65 ASSERT(IsValidTransactionId(transaction_id_));
66 attrs_ = new std::vector<StunAttribute*>();
69 StunMessage::~StunMessage() {
70 for (size_t i = 0; i < attrs_->size(); i++)
75 bool StunMessage::IsLegacy() const {
76 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
78 ASSERT(transaction_id_.size() == kStunTransactionIdLength);
82 bool StunMessage::SetTransactionID(const std::string& str) {
83 if (!IsValidTransactionId(str)) {
86 transaction_id_ = str;
90 bool StunMessage::AddAttribute(StunAttribute* attr) {
91 // Fail any attributes that aren't valid for this type of message.
92 if (attr->value_type() != GetAttributeValueType(attr->type())) {
95 attrs_->push_back(attr);
97 size_t attr_length = attr->length();
98 if (attr_length % 4 != 0) {
99 attr_length += (4 - (attr_length % 4));
101 length_ += static_cast<uint16>(attr_length + 4);
105 const StunAddressAttribute* StunMessage::GetAddress(int type) const {
107 case STUN_ATTR_MAPPED_ADDRESS: {
108 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
110 const StunAttribute* mapped_address =
111 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
113 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
114 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
118 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
122 const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
123 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
126 const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
127 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
130 const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
131 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
134 const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
135 return static_cast<const StunErrorCodeAttribute*>(
136 GetAttribute(STUN_ATTR_ERROR_CODE));
139 const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
140 return static_cast<const StunUInt16ListAttribute*>(
141 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
144 // Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
145 // procedure outlined in RFC 5389, section 15.4.
146 bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
147 const std::string& password) {
148 // Verifying the size of the message.
149 if ((size % 4) != 0) {
153 // Getting the message length from the STUN header.
154 uint16 msg_length = rtc::GetBE16(&data[2]);
155 if (size != (msg_length + kStunHeaderSize)) {
159 // Finding Message Integrity attribute in stun message.
160 size_t current_pos = kStunHeaderSize;
161 bool has_message_integrity_attr = false;
162 while (current_pos < size) {
163 uint16 attr_type, attr_length;
164 // Getting attribute type and length.
165 attr_type = rtc::GetBE16(&data[current_pos]);
166 attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
168 // If M-I, sanity check it, and break out.
169 if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
170 if (attr_length != kStunMessageIntegritySize ||
171 current_pos + attr_length > size) {
174 has_message_integrity_attr = true;
178 // Otherwise, skip to the next attribute.
179 current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
180 if ((attr_length % 4) != 0) {
181 current_pos += (4 - (attr_length % 4));
185 if (!has_message_integrity_attr) {
189 // Getting length of the message to calculate Message Integrity.
190 size_t mi_pos = current_pos;
191 rtc::scoped_ptr<char[]> temp_data(new char[current_pos]);
192 memcpy(temp_data.get(), data, current_pos);
193 if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
194 // Stun message has other attributes after message integrity.
195 // Adjust the length parameter in stun message to calculate HMAC.
196 size_t extra_offset = size -
197 (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
198 size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
200 // Writing new length of the STUN message @ Message Length in temp buffer.
202 // 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
203 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204 // |0 0| STUN Message Type | Message Length |
205 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206 rtc::SetBE16(temp_data.get() + 2,
207 static_cast<uint16>(new_adjusted_len));
210 char hmac[kStunMessageIntegritySize];
211 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
212 password.c_str(), password.size(),
213 temp_data.get(), mi_pos,
215 ASSERT(ret == sizeof(hmac));
216 if (ret != sizeof(hmac))
219 // Comparing the calculated HMAC with the one present in the message.
220 return memcmp(data + current_pos + kStunAttributeHeaderSize,
225 bool StunMessage::AddMessageIntegrity(const std::string& password) {
226 return AddMessageIntegrity(password.c_str(), password.size());
229 bool StunMessage::AddMessageIntegrity(const char* key,
231 // Add the attribute with a dummy value. Since this is a known attribute, it
233 StunByteStringAttribute* msg_integrity_attr =
234 new StunByteStringAttribute(STUN_ATTR_MESSAGE_INTEGRITY,
235 std::string(kStunMessageIntegritySize, '0'));
236 VERIFY(AddAttribute(msg_integrity_attr));
238 // Calculate the HMAC for the message.
243 int msg_len_for_hmac = static_cast<int>(
244 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
245 char hmac[kStunMessageIntegritySize];
246 size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1,
248 buf.Data(), msg_len_for_hmac,
250 ASSERT(ret == sizeof(hmac));
251 if (ret != sizeof(hmac)) {
252 LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
253 << "has dummy value.";
257 // Insert correct HMAC into the attribute.
258 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
262 // Verifies a message is in fact a STUN message, by performing the checks
263 // outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
265 bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
266 // Check the message length.
267 size_t fingerprint_attr_size =
268 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
269 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
272 // Skip the rest if the magic cookie isn't present.
273 const char* magic_cookie =
274 data + kStunTransactionIdOffset - kStunMagicCookieLength;
275 if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
278 // Check the fingerprint type and length.
279 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
280 if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
281 rtc::GetBE16(fingerprint_attr_data + sizeof(uint16)) !=
282 StunUInt32Attribute::SIZE)
285 // Check the fingerprint value.
287 rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
288 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
289 rtc::ComputeCrc32(data, size - fingerprint_attr_size));
292 bool StunMessage::AddFingerprint() {
293 // Add the attribute with a dummy value. Since this is a known attribute,
295 StunUInt32Attribute* fingerprint_attr =
296 new StunUInt32Attribute(STUN_ATTR_FINGERPRINT, 0);
297 VERIFY(AddAttribute(fingerprint_attr));
299 // Calculate the CRC-32 for the message and insert it.
304 int msg_len_for_crc32 = static_cast<int>(
305 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
306 uint32 c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
308 // Insert the correct CRC-32, XORed with a constant, into the attribute.
309 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
313 bool StunMessage::Read(ByteBuffer* buf) {
314 if (!buf->ReadUInt16(&type_))
317 if (type_ & 0x8000) {
318 // RTP and RTCP set the MSB of first byte, since first two bits are version,
319 // and version is always 2 (10). If set, this is not a STUN packet.
323 if (!buf->ReadUInt16(&length_))
326 std::string magic_cookie;
327 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
330 std::string transaction_id;
331 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
334 uint32 magic_cookie_int =
335 *reinterpret_cast<const uint32*>(magic_cookie.data());
336 if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
337 // If magic cookie is invalid it means that the peer implements
338 // RFC3489 instead of RFC5389.
339 transaction_id.insert(0, magic_cookie);
341 ASSERT(IsValidTransactionId(transaction_id));
342 transaction_id_ = transaction_id;
344 if (length_ != buf->Length())
349 size_t rest = buf->Length() - length_;
350 while (buf->Length() > rest) {
351 uint16 attr_type, attr_length;
352 if (!buf->ReadUInt16(&attr_type))
354 if (!buf->ReadUInt16(&attr_length))
357 StunAttribute* attr = CreateAttribute(attr_type, attr_length);
359 // Skip any unknown or malformed attributes.
360 if ((attr_length % 4) != 0) {
361 attr_length += (4 - (attr_length % 4));
363 if (!buf->Consume(attr_length))
366 if (!attr->Read(buf))
368 attrs_->push_back(attr);
372 ASSERT(buf->Length() == rest);
376 bool StunMessage::Write(ByteBuffer* buf) const {
377 buf->WriteUInt16(type_);
378 buf->WriteUInt16(length_);
380 buf->WriteUInt32(kStunMagicCookie);
381 buf->WriteString(transaction_id_);
383 for (size_t i = 0; i < attrs_->size(); ++i) {
384 buf->WriteUInt16((*attrs_)[i]->type());
385 buf->WriteUInt16(static_cast<uint16>((*attrs_)[i]->length()));
386 if (!(*attrs_)[i]->Write(buf))
393 StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
395 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
396 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
397 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
398 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
399 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
400 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
401 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
402 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
403 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
404 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_BYTE_STRING;
405 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
406 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
407 default: return STUN_VALUE_UNKNOWN;
411 StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
412 StunAttributeValueType value_type = GetAttributeValueType(type);
413 return StunAttribute::Create(value_type, type,
414 static_cast<uint16>(length), this);
417 const StunAttribute* StunMessage::GetAttribute(int type) const {
418 for (size_t i = 0; i < attrs_->size(); ++i) {
419 if ((*attrs_)[i]->type() == type)
425 bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
426 return transaction_id.size() == kStunTransactionIdLength ||
427 transaction_id.size() == kStunLegacyTransactionIdLength;
432 StunAttribute::StunAttribute(uint16 type, uint16 length)
433 : type_(type), length_(length) {
436 void StunAttribute::ConsumePadding(rtc::ByteBuffer* buf) const {
437 int remainder = length_ % 4;
439 buf->Consume(4 - remainder);
443 void StunAttribute::WritePadding(rtc::ByteBuffer* buf) const {
444 int remainder = length_ % 4;
446 char zeroes[4] = {0};
447 buf->WriteBytes(zeroes, 4 - remainder);
451 StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
452 uint16 type, uint16 length,
453 StunMessage* owner) {
454 switch (value_type) {
455 case STUN_VALUE_ADDRESS:
456 return new StunAddressAttribute(type, length);
457 case STUN_VALUE_XOR_ADDRESS:
458 return new StunXorAddressAttribute(type, length, owner);
459 case STUN_VALUE_UINT32:
460 return new StunUInt32Attribute(type);
461 case STUN_VALUE_UINT64:
462 return new StunUInt64Attribute(type);
463 case STUN_VALUE_BYTE_STRING:
464 return new StunByteStringAttribute(type, length);
465 case STUN_VALUE_ERROR_CODE:
466 return new StunErrorCodeAttribute(type, length);
467 case STUN_VALUE_UINT16_LIST:
468 return new StunUInt16ListAttribute(type, length);
474 StunAddressAttribute* StunAttribute::CreateAddress(uint16 type) {
475 return new StunAddressAttribute(type, 0);
478 StunXorAddressAttribute* StunAttribute::CreateXorAddress(uint16 type) {
479 return new StunXorAddressAttribute(type, 0, NULL);
482 StunUInt64Attribute* StunAttribute::CreateUInt64(uint16 type) {
483 return new StunUInt64Attribute(type);
486 StunUInt32Attribute* StunAttribute::CreateUInt32(uint16 type) {
487 return new StunUInt32Attribute(type);
490 StunByteStringAttribute* StunAttribute::CreateByteString(uint16 type) {
491 return new StunByteStringAttribute(type, 0);
494 StunErrorCodeAttribute* StunAttribute::CreateErrorCode() {
495 return new StunErrorCodeAttribute(
496 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
499 StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() {
500 return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
503 StunAddressAttribute::StunAddressAttribute(uint16 type,
504 const rtc::SocketAddress& addr)
505 : StunAttribute(type, 0) {
509 StunAddressAttribute::StunAddressAttribute(uint16 type, uint16 length)
510 : StunAttribute(type, length) {
513 bool StunAddressAttribute::Read(ByteBuffer* buf) {
515 if (!buf->ReadUInt8(&dummy))
519 if (!buf->ReadUInt8(&stun_family)) {
523 if (!buf->ReadUInt16(&port))
525 if (stun_family == STUN_ADDRESS_IPV4) {
527 if (length() != SIZE_IP4) {
530 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
533 rtc::IPAddress ipaddr(v4addr);
534 SetAddress(rtc::SocketAddress(ipaddr, port));
535 } else if (stun_family == STUN_ADDRESS_IPV6) {
537 if (length() != SIZE_IP6) {
540 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
543 rtc::IPAddress ipaddr(v6addr);
544 SetAddress(rtc::SocketAddress(ipaddr, port));
551 bool StunAddressAttribute::Write(ByteBuffer* buf) const {
552 StunAddressFamily address_family = family();
553 if (address_family == STUN_ADDRESS_UNDEF) {
554 LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
558 buf->WriteUInt8(address_family);
559 buf->WriteUInt16(address_.port());
560 switch (address_.family()) {
562 in_addr v4addr = address_.ipaddr().ipv4_address();
563 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
567 in6_addr v6addr = address_.ipaddr().ipv6_address();
568 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
575 StunXorAddressAttribute::StunXorAddressAttribute(uint16 type,
576 const rtc::SocketAddress& addr)
577 : StunAddressAttribute(type, addr), owner_(NULL) {
580 StunXorAddressAttribute::StunXorAddressAttribute(uint16 type,
583 : StunAddressAttribute(type, length), owner_(owner) {}
585 rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
587 rtc::IPAddress ip = ipaddr();
588 switch (ip.family()) {
590 in_addr v4addr = ip.ipv4_address();
592 (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
593 return rtc::IPAddress(v4addr);
596 in6_addr v6addr = ip.ipv6_address();
597 const std::string& transaction_id = owner_->transaction_id();
598 if (transaction_id.length() == kStunTransactionIdLength) {
599 uint32 transactionid_as_ints[3];
600 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
601 transaction_id.length());
602 uint32* ip_as_ints = reinterpret_cast<uint32*>(&v6addr.s6_addr);
603 // Transaction ID is in network byte order, but magic cookie
604 // is stored in host byte order.
606 (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
607 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
608 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
609 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
610 return rtc::IPAddress(v6addr);
616 // Invalid ip family or transaction ID, or missing owner.
617 // Return an AF_UNSPEC address.
618 return rtc::IPAddress();
621 bool StunXorAddressAttribute::Read(ByteBuffer* buf) {
622 if (!StunAddressAttribute::Read(buf))
624 uint16 xoredport = port() ^ (kStunMagicCookie >> 16);
625 rtc::IPAddress xored_ip = GetXoredIP();
626 SetAddress(rtc::SocketAddress(xored_ip, xoredport));
630 bool StunXorAddressAttribute::Write(ByteBuffer* buf) const {
631 StunAddressFamily address_family = family();
632 if (address_family == STUN_ADDRESS_UNDEF) {
633 LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
636 rtc::IPAddress xored_ip = GetXoredIP();
637 if (xored_ip.family() == AF_UNSPEC) {
641 buf->WriteUInt8(family());
642 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
643 switch (xored_ip.family()) {
645 in_addr v4addr = xored_ip.ipv4_address();
646 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
650 in6_addr v6addr = xored_ip.ipv6_address();
651 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
658 StunUInt32Attribute::StunUInt32Attribute(uint16 type, uint32 value)
659 : StunAttribute(type, SIZE), bits_(value) {
662 StunUInt32Attribute::StunUInt32Attribute(uint16 type)
663 : StunAttribute(type, SIZE), bits_(0) {
666 bool StunUInt32Attribute::GetBit(size_t index) const {
668 return static_cast<bool>((bits_ >> index) & 0x1);
671 void StunUInt32Attribute::SetBit(size_t index, bool value) {
673 bits_ &= ~(1 << index);
674 bits_ |= value ? (1 << index) : 0;
677 bool StunUInt32Attribute::Read(ByteBuffer* buf) {
678 if (length() != SIZE || !buf->ReadUInt32(&bits_))
683 bool StunUInt32Attribute::Write(ByteBuffer* buf) const {
684 buf->WriteUInt32(bits_);
688 StunUInt64Attribute::StunUInt64Attribute(uint16 type, uint64 value)
689 : StunAttribute(type, SIZE), bits_(value) {
692 StunUInt64Attribute::StunUInt64Attribute(uint16 type)
693 : StunAttribute(type, SIZE), bits_(0) {
696 bool StunUInt64Attribute::Read(ByteBuffer* buf) {
697 if (length() != SIZE || !buf->ReadUInt64(&bits_))
702 bool StunUInt64Attribute::Write(ByteBuffer* buf) const {
703 buf->WriteUInt64(bits_);
707 StunByteStringAttribute::StunByteStringAttribute(uint16 type)
708 : StunAttribute(type, 0), bytes_(NULL) {
711 StunByteStringAttribute::StunByteStringAttribute(uint16 type,
712 const std::string& str)
713 : StunAttribute(type, 0), bytes_(NULL) {
714 CopyBytes(str.c_str(), str.size());
717 StunByteStringAttribute::StunByteStringAttribute(uint16 type,
720 : StunAttribute(type, 0), bytes_(NULL) {
721 CopyBytes(bytes, length);
724 StunByteStringAttribute::StunByteStringAttribute(uint16 type, uint16 length)
725 : StunAttribute(type, length), bytes_(NULL) {
728 StunByteStringAttribute::~StunByteStringAttribute() {
732 void StunByteStringAttribute::CopyBytes(const char* bytes) {
733 CopyBytes(bytes, strlen(bytes));
736 void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
737 char* new_bytes = new char[length];
738 memcpy(new_bytes, bytes, length);
739 SetBytes(new_bytes, length);
742 uint8 StunByteStringAttribute::GetByte(size_t index) const {
743 ASSERT(bytes_ != NULL);
744 ASSERT(index < length());
745 return static_cast<uint8>(bytes_[index]);
748 void StunByteStringAttribute::SetByte(size_t index, uint8 value) {
749 ASSERT(bytes_ != NULL);
750 ASSERT(index < length());
751 bytes_[index] = value;
754 bool StunByteStringAttribute::Read(ByteBuffer* buf) {
755 bytes_ = new char[length()];
756 if (!buf->ReadBytes(bytes_, length())) {
764 bool StunByteStringAttribute::Write(ByteBuffer* buf) const {
765 buf->WriteBytes(bytes_, length());
770 void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
773 SetLength(static_cast<uint16>(length));
776 StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, int code,
777 const std::string& reason)
778 : StunAttribute(type, 0) {
783 StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, uint16 length)
784 : StunAttribute(type, length), class_(0), number_(0) {
787 StunErrorCodeAttribute::~StunErrorCodeAttribute() {
790 int StunErrorCodeAttribute::code() const {
791 return class_ * 100 + number_;
794 void StunErrorCodeAttribute::SetCode(int code) {
795 class_ = static_cast<uint8>(code / 100);
796 number_ = static_cast<uint8>(code % 100);
799 void StunErrorCodeAttribute::SetReason(const std::string& reason) {
800 SetLength(MIN_SIZE + static_cast<uint16>(reason.size()));
804 bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
806 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
809 if ((val >> 11) != 0)
810 LOG(LS_ERROR) << "error-code bits not zero";
812 class_ = ((val >> 8) & 0x7);
813 number_ = (val & 0xff);
815 if (!buf->ReadString(&reason_, length() - 4))
822 bool StunErrorCodeAttribute::Write(ByteBuffer* buf) const {
823 buf->WriteUInt32(class_ << 8 | number_);
824 buf->WriteString(reason_);
829 StunUInt16ListAttribute::StunUInt16ListAttribute(uint16 type, uint16 length)
830 : StunAttribute(type, length) {
831 attr_types_ = new std::vector<uint16>();
834 StunUInt16ListAttribute::~StunUInt16ListAttribute() {
838 size_t StunUInt16ListAttribute::Size() const {
839 return attr_types_->size();
842 uint16 StunUInt16ListAttribute::GetType(int index) const {
843 return (*attr_types_)[index];
846 void StunUInt16ListAttribute::SetType(int index, uint16 value) {
847 (*attr_types_)[index] = value;
850 void StunUInt16ListAttribute::AddType(uint16 value) {
851 attr_types_->push_back(value);
852 SetLength(static_cast<uint16>(attr_types_->size() * 2));
855 bool StunUInt16ListAttribute::Read(ByteBuffer* buf) {
859 for (size_t i = 0; i < length() / 2; i++) {
861 if (!buf->ReadUInt16(&attr))
863 attr_types_->push_back(attr);
865 // Padding of these attributes is done in RFC 5389 style. This is
866 // slightly different from RFC3489, but it shouldn't be important.
867 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
868 // entries in the list (not necessarily the last one - it's unspecified).
869 // RFC5389 pads on the end, and the bytes are always ignored.
874 bool StunUInt16ListAttribute::Write(ByteBuffer* buf) const {
875 for (size_t i = 0; i < attr_types_->size(); ++i) {
876 buf->WriteUInt16((*attr_types_)[i]);
882 int GetStunSuccessResponseType(int req_type) {
883 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
886 int GetStunErrorResponseType(int req_type) {
887 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
890 bool IsStunRequestType(int msg_type) {
891 return ((msg_type & kStunTypeMask) == 0x000);
894 bool IsStunIndicationType(int msg_type) {
895 return ((msg_type & kStunTypeMask) == 0x010);
898 bool IsStunSuccessResponseType(int msg_type) {
899 return ((msg_type & kStunTypeMask) == 0x100);
902 bool IsStunErrorResponseType(int msg_type) {
903 return ((msg_type & kStunTypeMask) == 0x110);
906 bool ComputeStunCredentialHash(const std::string& username,
907 const std::string& realm,
908 const std::string& password,
910 // http://tools.ietf.org/html/rfc5389#section-15.4
911 // long-term credentials will be calculated using the key and key is
912 // key = MD5(username ":" realm ":" SASLprep(password))
913 std::string input = username;
919 char digest[rtc::MessageDigest::kMaxSize];
920 size_t size = rtc::ComputeDigest(
921 rtc::DIGEST_MD5, input.c_str(), input.size(),
922 digest, sizeof(digest));
927 *hash = std::string(digest, size);
931 } // namespace cricket