Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/talk/p2p/base/stun.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 29.4 KB
Line 
1/*
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  }
101  length_ += static_cast<uint16>(attr_length + 4);
102  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_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;
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    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206    talk_base::SetBE16(temp_data.get() + 2,
207                       static_cast<uint16>(new_adjusted_len));
208  }
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
242  int msg_len_for_hmac = static_cast<int>(
243      buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
244  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
303  int msg_len_for_crc32 = static_cast<int>(
304      buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
305  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());
384    buf->WriteUInt16(static_cast<uint16>((*attrs_)[i]->length()));
385    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);
412  return StunAttribute::Create(value_type, type,
413                               static_cast<uint16>(length), this);
414}
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;
772  SetLength(static_cast<uint16>(length));
773}
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
Note: See TracBrowser for help on using the repository browser.