blob: 2a0f6d97830fc0cb2f71fe1b3f5023237b3cafa7 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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.
15 *
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.
26 */
27
28#include "talk/p2p/base/stun.h"
29
30#include <cstring>
31
32#include "talk/base/byteorder.h"
33#include "talk/base/common.h"
34#include "talk/base/crc32.h"
35#include "talk/base/logging.h"
36#include "talk/base/messagedigest.h"
37#include "talk/base/scoped_ptr.h"
38#include "talk/base/stringencode.h"
39
40using talk_base::ByteBuffer;
41
42namespace cricket {
43
44const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
45const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
46const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
47const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials";
48const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
49const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
50const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
51const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
52const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
53const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
54
55const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' };
56const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
57const uint32 STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
58
59// StunMessage
60
61StunMessage::StunMessage()
62 : type_(0),
63 length_(0),
64 transaction_id_(EMPTY_TRANSACTION_ID) {
65 ASSERT(IsValidTransactionId(transaction_id_));
66 attrs_ = new std::vector<StunAttribute*>();
67}
68
69StunMessage::~StunMessage() {
70 for (size_t i = 0; i < attrs_->size(); i++)
71 delete (*attrs_)[i];
72 delete attrs_;
73}
74
75bool StunMessage::IsLegacy() const {
76 if (transaction_id_.size() == kStunLegacyTransactionIdLength)
77 return true;
78 ASSERT(transaction_id_.size() == kStunTransactionIdLength);
79 return false;
80}
81
82bool StunMessage::SetTransactionID(const std::string& str) {
83 if (!IsValidTransactionId(str)) {
84 return false;
85 }
86 transaction_id_ = str;
87 return true;
88}
89
90bool 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())) {
93 return false;
94 }
95 attrs_->push_back(attr);
96 attr->SetOwner(this);
97 size_t attr_length = attr->length();
98 if (attr_length % 4 != 0) {
99 attr_length += (4 - (attr_length % 4));
100 }
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000101 length_ += static_cast<uint16>(attr_length + 4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102 return true;
103}
104
105const StunAddressAttribute* StunMessage::GetAddress(int type) const {
106 switch (type) {
107 case STUN_ATTR_MAPPED_ADDRESS: {
108 // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
109 // missing.
110 const StunAttribute* mapped_address =
111 GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
112 if (!mapped_address)
113 mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
114 return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
115 }
116
117 default:
118 return static_cast<const StunAddressAttribute*>(GetAttribute(type));
119 }
120}
121
122const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
123 return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
124}
125
126const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
127 return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
128}
129
130const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
131 return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
132}
133
134const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
135 return static_cast<const StunErrorCodeAttribute*>(
136 GetAttribute(STUN_ATTR_ERROR_CODE));
137}
138
139const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
140 return static_cast<const StunUInt16ListAttribute*>(
141 GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
142}
143
144// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
145// procedure outlined in RFC 5389, section 15.4.
146bool 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) {
150 return false;
151 }
152
153 // Getting the message length from the STUN header.
154 uint16 msg_length = talk_base::GetBE16(&data[2]);
155 if (size != (msg_length + kStunHeaderSize)) {
156 return false;
157 }
158
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 = talk_base::GetBE16(&data[current_pos]);
166 attr_length = talk_base::GetBE16(&data[current_pos + sizeof(attr_type)]);
167
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) {
172 return false;
173 }
174 has_message_integrity_attr = true;
175 break;
176 }
177
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));
182 }
183 }
184
185 if (!has_message_integrity_attr) {
186 return false;
187 }
188
189 // Getting length of the message to calculate Message Integrity.
190 size_t mi_pos = current_pos;
191 talk_base::scoped_array<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;
199
200 // Writing new length of the STUN message @ Message Length in temp buffer.
201 // 0 1 2 3
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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000206 talk_base::SetBE16(temp_data.get() + 2,
207 static_cast<uint16>(new_adjusted_len));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208 }
209
210 char hmac[kStunMessageIntegritySize];
211 size_t ret = talk_base::ComputeHmac(talk_base::DIGEST_SHA_1,
212 password.c_str(), password.size(),
213 temp_data.get(), mi_pos,
214 hmac, sizeof(hmac));
215 ASSERT(ret == sizeof(hmac));
216 if (ret != sizeof(hmac))
217 return false;
218
219 // Comparing the calculated HMAC with the one present in the message.
220 return (std::memcmp(data + current_pos + kStunAttributeHeaderSize,
221 hmac, sizeof(hmac)) == 0);
222}
223
224bool StunMessage::AddMessageIntegrity(const std::string& password) {
225 return AddMessageIntegrity(password.c_str(), password.size());
226}
227
228bool StunMessage::AddMessageIntegrity(const char* key,
229 size_t keylen) {
230 // Add the attribute with a dummy value. Since this is a known attribute, it
231 // can't fail.
232 StunByteStringAttribute* msg_integrity_attr =
233 new StunByteStringAttribute(STUN_ATTR_MESSAGE_INTEGRITY,
234 std::string(kStunMessageIntegritySize, '0'));
235 VERIFY(AddAttribute(msg_integrity_attr));
236
237 // Calculate the HMAC for the message.
238 talk_base::ByteBuffer buf;
239 if (!Write(&buf))
240 return false;
241
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000242 int msg_len_for_hmac = static_cast<int>(
243 buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 char hmac[kStunMessageIntegritySize];
245 size_t ret = talk_base::ComputeHmac(talk_base::DIGEST_SHA_1,
246 key, keylen,
247 buf.Data(), msg_len_for_hmac,
248 hmac, sizeof(hmac));
249 ASSERT(ret == sizeof(hmac));
250 if (ret != sizeof(hmac)) {
251 LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
252 << "has dummy value.";
253 return false;
254 }
255
256 // Insert correct HMAC into the attribute.
257 msg_integrity_attr->CopyBytes(hmac, sizeof(hmac));
258 return true;
259}
260
261// Verifies a message is in fact a STUN message, by performing the checks
262// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
263// in section 15.5.
264bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
265 // Check the message length.
266 size_t fingerprint_attr_size =
267 kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
268 if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
269 return false;
270
271 // Skip the rest if the magic cookie isn't present.
272 const char* magic_cookie =
273 data + kStunTransactionIdOffset - kStunMagicCookieLength;
274 if (talk_base::GetBE32(magic_cookie) != kStunMagicCookie)
275 return false;
276
277 // Check the fingerprint type and length.
278 const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
279 if (talk_base::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
280 talk_base::GetBE16(fingerprint_attr_data + sizeof(uint16)) !=
281 StunUInt32Attribute::SIZE)
282 return false;
283
284 // Check the fingerprint value.
285 uint32 fingerprint =
286 talk_base::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
287 return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
288 talk_base::ComputeCrc32(data, size - fingerprint_attr_size));
289}
290
291bool StunMessage::AddFingerprint() {
292 // Add the attribute with a dummy value. Since this is a known attribute,
293 // it can't fail.
294 StunUInt32Attribute* fingerprint_attr =
295 new StunUInt32Attribute(STUN_ATTR_FINGERPRINT, 0);
296 VERIFY(AddAttribute(fingerprint_attr));
297
298 // Calculate the CRC-32 for the message and insert it.
299 talk_base::ByteBuffer buf;
300 if (!Write(&buf))
301 return false;
302
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000303 int msg_len_for_crc32 = static_cast<int>(
304 buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000305 uint32 c = talk_base::ComputeCrc32(buf.Data(), msg_len_for_crc32);
306
307 // Insert the correct CRC-32, XORed with a constant, into the attribute.
308 fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
309 return true;
310}
311
312bool StunMessage::Read(ByteBuffer* buf) {
313 if (!buf->ReadUInt16(&type_))
314 return false;
315
316 if (type_ & 0x8000) {
317 // RTP and RTCP set the MSB of first byte, since first two bits are version,
318 // and version is always 2 (10). If set, this is not a STUN packet.
319 return false;
320 }
321
322 if (!buf->ReadUInt16(&length_))
323 return false;
324
325 std::string magic_cookie;
326 if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength))
327 return false;
328
329 std::string transaction_id;
330 if (!buf->ReadString(&transaction_id, kStunTransactionIdLength))
331 return false;
332
333 uint32 magic_cookie_int =
334 *reinterpret_cast<const uint32*>(magic_cookie.data());
335 if (talk_base::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
336 // If magic cookie is invalid it means that the peer implements
337 // RFC3489 instead of RFC5389.
338 transaction_id.insert(0, magic_cookie);
339 }
340 ASSERT(IsValidTransactionId(transaction_id));
341 transaction_id_ = transaction_id;
342
343 if (length_ != buf->Length())
344 return false;
345
346 attrs_->resize(0);
347
348 size_t rest = buf->Length() - length_;
349 while (buf->Length() > rest) {
350 uint16 attr_type, attr_length;
351 if (!buf->ReadUInt16(&attr_type))
352 return false;
353 if (!buf->ReadUInt16(&attr_length))
354 return false;
355
356 StunAttribute* attr = CreateAttribute(attr_type, attr_length);
357 if (!attr) {
358 // Skip any unknown or malformed attributes.
359 if ((attr_length % 4) != 0) {
360 attr_length += (4 - (attr_length % 4));
361 }
362 if (!buf->Consume(attr_length))
363 return false;
364 } else {
365 if (!attr->Read(buf))
366 return false;
367 attrs_->push_back(attr);
368 }
369 }
370
371 ASSERT(buf->Length() == rest);
372 return true;
373}
374
375bool StunMessage::Write(ByteBuffer* buf) const {
376 buf->WriteUInt16(type_);
377 buf->WriteUInt16(length_);
378 if (!IsLegacy())
379 buf->WriteUInt32(kStunMagicCookie);
380 buf->WriteString(transaction_id_);
381
382 for (size_t i = 0; i < attrs_->size(); ++i) {
383 buf->WriteUInt16((*attrs_)[i]->type());
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000384 buf->WriteUInt16(static_cast<uint16>((*attrs_)[i]->length()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385 if (!(*attrs_)[i]->Write(buf))
386 return false;
387 }
388
389 return true;
390}
391
392StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
393 switch (type) {
394 case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS;
395 case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING;
396 case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING;
397 case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE;
398 case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST;
399 case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING;
400 case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING;
401 case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS;
402 case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING;
403 case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_BYTE_STRING;
404 case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32;
405 case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32;
406 default: return STUN_VALUE_UNKNOWN;
407 }
408}
409
410StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
411 StunAttributeValueType value_type = GetAttributeValueType(type);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000412 return StunAttribute::Create(value_type, type,
413 static_cast<uint16>(length), this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000414}
415
416const StunAttribute* StunMessage::GetAttribute(int type) const {
417 for (size_t i = 0; i < attrs_->size(); ++i) {
418 if ((*attrs_)[i]->type() == type)
419 return (*attrs_)[i];
420 }
421 return NULL;
422}
423
424bool StunMessage::IsValidTransactionId(const std::string& transaction_id) {
425 return transaction_id.size() == kStunTransactionIdLength ||
426 transaction_id.size() == kStunLegacyTransactionIdLength;
427}
428
429// StunAttribute
430
431StunAttribute::StunAttribute(uint16 type, uint16 length)
432 : type_(type), length_(length) {
433}
434
435void StunAttribute::ConsumePadding(talk_base::ByteBuffer* buf) const {
436 int remainder = length_ % 4;
437 if (remainder > 0) {
438 buf->Consume(4 - remainder);
439 }
440}
441
442void StunAttribute::WritePadding(talk_base::ByteBuffer* buf) const {
443 int remainder = length_ % 4;
444 if (remainder > 0) {
445 char zeroes[4] = {0};
446 buf->WriteBytes(zeroes, 4 - remainder);
447 }
448}
449
450StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
451 uint16 type, uint16 length,
452 StunMessage* owner) {
453 switch (value_type) {
454 case STUN_VALUE_ADDRESS:
455 return new StunAddressAttribute(type, length);
456 case STUN_VALUE_XOR_ADDRESS:
457 return new StunXorAddressAttribute(type, length, owner);
458 case STUN_VALUE_UINT32:
459 return new StunUInt32Attribute(type);
460 case STUN_VALUE_UINT64:
461 return new StunUInt64Attribute(type);
462 case STUN_VALUE_BYTE_STRING:
463 return new StunByteStringAttribute(type, length);
464 case STUN_VALUE_ERROR_CODE:
465 return new StunErrorCodeAttribute(type, length);
466 case STUN_VALUE_UINT16_LIST:
467 return new StunUInt16ListAttribute(type, length);
468 default:
469 return NULL;
470 }
471}
472
473StunAddressAttribute* StunAttribute::CreateAddress(uint16 type) {
474 return new StunAddressAttribute(type, 0);
475}
476
477StunXorAddressAttribute* StunAttribute::CreateXorAddress(uint16 type) {
478 return new StunXorAddressAttribute(type, 0, NULL);
479}
480
481StunUInt64Attribute* StunAttribute::CreateUInt64(uint16 type) {
482 return new StunUInt64Attribute(type);
483}
484
485StunUInt32Attribute* StunAttribute::CreateUInt32(uint16 type) {
486 return new StunUInt32Attribute(type);
487}
488
489StunByteStringAttribute* StunAttribute::CreateByteString(uint16 type) {
490 return new StunByteStringAttribute(type, 0);
491}
492
493StunErrorCodeAttribute* StunAttribute::CreateErrorCode() {
494 return new StunErrorCodeAttribute(
495 STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
496}
497
498StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() {
499 return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
500}
501
502StunAddressAttribute::StunAddressAttribute(uint16 type,
503 const talk_base::SocketAddress& addr)
504 : StunAttribute(type, 0) {
505 SetAddress(addr);
506}
507
508StunAddressAttribute::StunAddressAttribute(uint16 type, uint16 length)
509 : StunAttribute(type, length) {
510}
511
512bool StunAddressAttribute::Read(ByteBuffer* buf) {
513 uint8 dummy;
514 if (!buf->ReadUInt8(&dummy))
515 return false;
516
517 uint8 stun_family;
518 if (!buf->ReadUInt8(&stun_family)) {
519 return false;
520 }
521 uint16 port;
522 if (!buf->ReadUInt16(&port))
523 return false;
524 if (stun_family == STUN_ADDRESS_IPV4) {
525 in_addr v4addr;
526 if (length() != SIZE_IP4) {
527 return false;
528 }
529 if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
530 return false;
531 }
532 talk_base::IPAddress ipaddr(v4addr);
533 SetAddress(talk_base::SocketAddress(ipaddr, port));
534 } else if (stun_family == STUN_ADDRESS_IPV6) {
535 in6_addr v6addr;
536 if (length() != SIZE_IP6) {
537 return false;
538 }
539 if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
540 return false;
541 }
542 talk_base::IPAddress ipaddr(v6addr);
543 SetAddress(talk_base::SocketAddress(ipaddr, port));
544 } else {
545 return false;
546 }
547 return true;
548}
549
550bool StunAddressAttribute::Write(ByteBuffer* buf) const {
551 StunAddressFamily address_family = family();
552 if (address_family == STUN_ADDRESS_UNDEF) {
553 LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
554 return false;
555 }
556 buf->WriteUInt8(0);
557 buf->WriteUInt8(address_family);
558 buf->WriteUInt16(address_.port());
559 switch (address_.family()) {
560 case AF_INET: {
561 in_addr v4addr = address_.ipaddr().ipv4_address();
562 buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
563 break;
564 }
565 case AF_INET6: {
566 in6_addr v6addr = address_.ipaddr().ipv6_address();
567 buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
568 break;
569 }
570 }
571 return true;
572}
573
574StunXorAddressAttribute::StunXorAddressAttribute(uint16 type,
575 const talk_base::SocketAddress& addr)
576 : StunAddressAttribute(type, addr), owner_(NULL) {
577}
578
579StunXorAddressAttribute::StunXorAddressAttribute(uint16 type,
580 uint16 length,
581 StunMessage* owner)
582 : StunAddressAttribute(type, length), owner_(owner) {}
583
584talk_base::IPAddress StunXorAddressAttribute::GetXoredIP() const {
585 if (owner_) {
586 talk_base::IPAddress ip = ipaddr();
587 switch (ip.family()) {
588 case AF_INET: {
589 in_addr v4addr = ip.ipv4_address();
590 v4addr.s_addr =
591 (v4addr.s_addr ^ talk_base::HostToNetwork32(kStunMagicCookie));
592 return talk_base::IPAddress(v4addr);
593 }
594 case AF_INET6: {
595 in6_addr v6addr = ip.ipv6_address();
596 const std::string& transaction_id = owner_->transaction_id();
597 if (transaction_id.length() == kStunTransactionIdLength) {
598 uint32 transactionid_as_ints[3];
599 memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
600 transaction_id.length());
601 uint32* ip_as_ints = reinterpret_cast<uint32*>(&v6addr.s6_addr);
602 // Transaction ID is in network byte order, but magic cookie
603 // is stored in host byte order.
604 ip_as_ints[0] =
605 (ip_as_ints[0] ^ talk_base::HostToNetwork32(kStunMagicCookie));
606 ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
607 ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
608 ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
609 return talk_base::IPAddress(v6addr);
610 }
611 break;
612 }
613 }
614 }
615 // Invalid ip family or transaction ID, or missing owner.
616 // Return an AF_UNSPEC address.
617 return talk_base::IPAddress();
618}
619
620bool StunXorAddressAttribute::Read(ByteBuffer* buf) {
621 if (!StunAddressAttribute::Read(buf))
622 return false;
623 uint16 xoredport = port() ^ (kStunMagicCookie >> 16);
624 talk_base::IPAddress xored_ip = GetXoredIP();
625 SetAddress(talk_base::SocketAddress(xored_ip, xoredport));
626 return true;
627}
628
629bool StunXorAddressAttribute::Write(ByteBuffer* buf) const {
630 StunAddressFamily address_family = family();
631 if (address_family == STUN_ADDRESS_UNDEF) {
632 LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
633 return false;
634 }
635 talk_base::IPAddress xored_ip = GetXoredIP();
636 if (xored_ip.family() == AF_UNSPEC) {
637 return false;
638 }
639 buf->WriteUInt8(0);
640 buf->WriteUInt8(family());
641 buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
642 switch (xored_ip.family()) {
643 case AF_INET: {
644 in_addr v4addr = xored_ip.ipv4_address();
645 buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
646 break;
647 }
648 case AF_INET6: {
649 in6_addr v6addr = xored_ip.ipv6_address();
650 buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
651 break;
652 }
653 }
654 return true;
655}
656
657StunUInt32Attribute::StunUInt32Attribute(uint16 type, uint32 value)
658 : StunAttribute(type, SIZE), bits_(value) {
659}
660
661StunUInt32Attribute::StunUInt32Attribute(uint16 type)
662 : StunAttribute(type, SIZE), bits_(0) {
663}
664
665bool StunUInt32Attribute::GetBit(size_t index) const {
666 ASSERT(index < 32);
667 return static_cast<bool>((bits_ >> index) & 0x1);
668}
669
670void StunUInt32Attribute::SetBit(size_t index, bool value) {
671 ASSERT(index < 32);
672 bits_ &= ~(1 << index);
673 bits_ |= value ? (1 << index) : 0;
674}
675
676bool StunUInt32Attribute::Read(ByteBuffer* buf) {
677 if (length() != SIZE || !buf->ReadUInt32(&bits_))
678 return false;
679 return true;
680}
681
682bool StunUInt32Attribute::Write(ByteBuffer* buf) const {
683 buf->WriteUInt32(bits_);
684 return true;
685}
686
687StunUInt64Attribute::StunUInt64Attribute(uint16 type, uint64 value)
688 : StunAttribute(type, SIZE), bits_(value) {
689}
690
691StunUInt64Attribute::StunUInt64Attribute(uint16 type)
692 : StunAttribute(type, SIZE), bits_(0) {
693}
694
695bool StunUInt64Attribute::Read(ByteBuffer* buf) {
696 if (length() != SIZE || !buf->ReadUInt64(&bits_))
697 return false;
698 return true;
699}
700
701bool StunUInt64Attribute::Write(ByteBuffer* buf) const {
702 buf->WriteUInt64(bits_);
703 return true;
704}
705
706StunByteStringAttribute::StunByteStringAttribute(uint16 type)
707 : StunAttribute(type, 0), bytes_(NULL) {
708}
709
710StunByteStringAttribute::StunByteStringAttribute(uint16 type,
711 const std::string& str)
712 : StunAttribute(type, 0), bytes_(NULL) {
713 CopyBytes(str.c_str(), str.size());
714}
715
716StunByteStringAttribute::StunByteStringAttribute(uint16 type,
717 const void* bytes,
718 size_t length)
719 : StunAttribute(type, 0), bytes_(NULL) {
720 CopyBytes(bytes, length);
721}
722
723StunByteStringAttribute::StunByteStringAttribute(uint16 type, uint16 length)
724 : StunAttribute(type, length), bytes_(NULL) {
725}
726
727StunByteStringAttribute::~StunByteStringAttribute() {
728 delete [] bytes_;
729}
730
731void StunByteStringAttribute::CopyBytes(const char* bytes) {
732 CopyBytes(bytes, strlen(bytes));
733}
734
735void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
736 char* new_bytes = new char[length];
737 std::memcpy(new_bytes, bytes, length);
738 SetBytes(new_bytes, length);
739}
740
741uint8 StunByteStringAttribute::GetByte(size_t index) const {
742 ASSERT(bytes_ != NULL);
743 ASSERT(index < length());
744 return static_cast<uint8>(bytes_[index]);
745}
746
747void StunByteStringAttribute::SetByte(size_t index, uint8 value) {
748 ASSERT(bytes_ != NULL);
749 ASSERT(index < length());
750 bytes_[index] = value;
751}
752
753bool StunByteStringAttribute::Read(ByteBuffer* buf) {
754 bytes_ = new char[length()];
755 if (!buf->ReadBytes(bytes_, length())) {
756 return false;
757 }
758
759 ConsumePadding(buf);
760 return true;
761}
762
763bool StunByteStringAttribute::Write(ByteBuffer* buf) const {
764 buf->WriteBytes(bytes_, length());
765 WritePadding(buf);
766 return true;
767}
768
769void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
770 delete [] bytes_;
771 bytes_ = bytes;
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000772 SetLength(static_cast<uint16>(length));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773}
774
775StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, int code,
776 const std::string& reason)
777 : StunAttribute(type, 0) {
778 SetCode(code);
779 SetReason(reason);
780}
781
782StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, uint16 length)
783 : StunAttribute(type, length), class_(0), number_(0) {
784}
785
786StunErrorCodeAttribute::~StunErrorCodeAttribute() {
787}
788
789int StunErrorCodeAttribute::code() const {
790 return class_ * 100 + number_;
791}
792
793void StunErrorCodeAttribute::SetCode(int code) {
794 class_ = static_cast<uint8>(code / 100);
795 number_ = static_cast<uint8>(code % 100);
796}
797
798void StunErrorCodeAttribute::SetReason(const std::string& reason) {
799 SetLength(MIN_SIZE + static_cast<uint16>(reason.size()));
800 reason_ = reason;
801}
802
803bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
804 uint32 val;
805 if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
806 return false;
807
808 if ((val >> 11) != 0)
809 LOG(LS_ERROR) << "error-code bits not zero";
810
811 class_ = ((val >> 8) & 0x7);
812 number_ = (val & 0xff);
813
814 if (!buf->ReadString(&reason_, length() - 4))
815 return false;
816
817 ConsumePadding(buf);
818 return true;
819}
820
821bool StunErrorCodeAttribute::Write(ByteBuffer* buf) const {
822 buf->WriteUInt32(class_ << 8 | number_);
823 buf->WriteString(reason_);
824 WritePadding(buf);
825 return true;
826}
827
828StunUInt16ListAttribute::StunUInt16ListAttribute(uint16 type, uint16 length)
829 : StunAttribute(type, length) {
830 attr_types_ = new std::vector<uint16>();
831}
832
833StunUInt16ListAttribute::~StunUInt16ListAttribute() {
834 delete attr_types_;
835}
836
837size_t StunUInt16ListAttribute::Size() const {
838 return attr_types_->size();
839}
840
841uint16 StunUInt16ListAttribute::GetType(int index) const {
842 return (*attr_types_)[index];
843}
844
845void StunUInt16ListAttribute::SetType(int index, uint16 value) {
846 (*attr_types_)[index] = value;
847}
848
849void StunUInt16ListAttribute::AddType(uint16 value) {
850 attr_types_->push_back(value);
851 SetLength(static_cast<uint16>(attr_types_->size() * 2));
852}
853
854bool StunUInt16ListAttribute::Read(ByteBuffer* buf) {
855 if (length() % 2)
856 return false;
857
858 for (size_t i = 0; i < length() / 2; i++) {
859 uint16 attr;
860 if (!buf->ReadUInt16(&attr))
861 return false;
862 attr_types_->push_back(attr);
863 }
864 // Padding of these attributes is done in RFC 5389 style. This is
865 // slightly different from RFC3489, but it shouldn't be important.
866 // RFC3489 pads out to a 32 bit boundary by duplicating one of the
867 // entries in the list (not necessarily the last one - it's unspecified).
868 // RFC5389 pads on the end, and the bytes are always ignored.
869 ConsumePadding(buf);
870 return true;
871}
872
873bool StunUInt16ListAttribute::Write(ByteBuffer* buf) const {
874 for (size_t i = 0; i < attr_types_->size(); ++i) {
875 buf->WriteUInt16((*attr_types_)[i]);
876 }
877 WritePadding(buf);
878 return true;
879}
880
881int GetStunSuccessResponseType(int req_type) {
882 return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
883}
884
885int GetStunErrorResponseType(int req_type) {
886 return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
887}
888
889bool IsStunRequestType(int msg_type) {
890 return ((msg_type & kStunTypeMask) == 0x000);
891}
892
893bool IsStunIndicationType(int msg_type) {
894 return ((msg_type & kStunTypeMask) == 0x010);
895}
896
897bool IsStunSuccessResponseType(int msg_type) {
898 return ((msg_type & kStunTypeMask) == 0x100);
899}
900
901bool IsStunErrorResponseType(int msg_type) {
902 return ((msg_type & kStunTypeMask) == 0x110);
903}
904
905bool ComputeStunCredentialHash(const std::string& username,
906 const std::string& realm,
907 const std::string& password,
908 std::string* hash) {
909 // http://tools.ietf.org/html/rfc5389#section-15.4
910 // long-term credentials will be calculated using the key and key is
911 // key = MD5(username ":" realm ":" SASLprep(password))
912 std::string input = username;
913 input += ':';
914 input += realm;
915 input += ':';
916 input += password;
917
918 char digest[talk_base::MessageDigest::kMaxSize];
919 size_t size = talk_base::ComputeDigest(
920 talk_base::DIGEST_MD5, input.c_str(), input.size(),
921 digest, sizeof(digest));
922 if (size == 0) {
923 return false;
924 }
925
926 *hash = std::string(digest, size);
927 return true;
928}
929
930} // namespace cricket