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/common.h"
33#include "talk/base/logging.h"
34
35using talk_base::ByteBuffer;
36
37namespace cricket {
38
39const std::string STUN_ERROR_REASON_BAD_REQUEST = "BAD REQUEST";
40const std::string STUN_ERROR_REASON_UNAUTHORIZED = "UNAUTHORIZED";
41const std::string STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE = "UNKNOWN ATTRIBUTE";
42const std::string STUN_ERROR_REASON_STALE_CREDENTIALS = "STALE CREDENTIALS";
43const std::string STUN_ERROR_REASON_INTEGRITY_CHECK_FAILURE = "INTEGRITY CHECK FAILURE";
44const std::string STUN_ERROR_REASON_MISSING_USERNAME = "MISSING USERNAME";
45const std::string STUN_ERROR_REASON_USE_TLS = "USE TLS";
46const std::string STUN_ERROR_REASON_SERVER_ERROR = "SERVER ERROR";
47const std::string STUN_ERROR_REASON_GLOBAL_FAILURE = "GLOBAL FAILURE";
48
49StunMessage::StunMessage() : type_(0), length_(0),
50    transaction_id_("0000000000000000") {
51  ASSERT(transaction_id_.size() == 16);
52  attrs_ = new std::vector<StunAttribute*>();
53}
54
55StunMessage::~StunMessage() {
56  for (unsigned i = 0; i < attrs_->size(); i++)
57    delete (*attrs_)[i];
58  delete attrs_;
59}
60
61void StunMessage::SetTransactionID(const std::string& str) {
62  ASSERT(str.size() == 16);
63  transaction_id_ = str;
64}
65
66void StunMessage::AddAttribute(StunAttribute* attr) {
67  attrs_->push_back(attr);
68  length_ += attr->length() + 4;
69}
70
71const StunAddressAttribute*
72StunMessage::GetAddress(StunAttributeType type) const {
73  switch (type) {
74  case STUN_ATTR_MAPPED_ADDRESS:
75  case STUN_ATTR_RESPONSE_ADDRESS:
76  case STUN_ATTR_SOURCE_ADDRESS:
77  case STUN_ATTR_CHANGED_ADDRESS:
78  case STUN_ATTR_REFLECTED_FROM:
79  case STUN_ATTR_ALTERNATE_SERVER:
80  case STUN_ATTR_DESTINATION_ADDRESS:
81  case STUN_ATTR_SOURCE_ADDRESS2:
82    return reinterpret_cast<const StunAddressAttribute*>(GetAttribute(type));
83
84  default:
85    ASSERT(0);
86    return 0;
87  }
88}
89
90const StunUInt32Attribute*
91StunMessage::GetUInt32(StunAttributeType type) const {
92  switch (type) {
93  case STUN_ATTR_CHANGE_REQUEST:
94  case STUN_ATTR_LIFETIME:
95  case STUN_ATTR_BANDWIDTH:
96  case STUN_ATTR_OPTIONS:
97    return reinterpret_cast<const StunUInt32Attribute*>(GetAttribute(type));
98
99  default:
100    ASSERT(0);
101    return 0;
102  }
103}
104
105const StunByteStringAttribute*
106StunMessage::GetByteString(StunAttributeType type) const {
107  switch (type) {
108  case STUN_ATTR_USERNAME:
109  case STUN_ATTR_PASSWORD:
110  case STUN_ATTR_MESSAGE_INTEGRITY:
111  case STUN_ATTR_DATA:
112  case STUN_ATTR_MAGIC_COOKIE:
113    return reinterpret_cast<const StunByteStringAttribute*>(GetAttribute(type));
114
115  default:
116    ASSERT(0);
117    return 0;
118  }
119}
120
121const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
122  return reinterpret_cast<const StunErrorCodeAttribute*>(
123      GetAttribute(STUN_ATTR_ERROR_CODE));
124}
125
126const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
127  return reinterpret_cast<const StunUInt16ListAttribute*>(
128      GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
129}
130
131const StunTransportPrefsAttribute* StunMessage::GetTransportPrefs() const {
132  return reinterpret_cast<const StunTransportPrefsAttribute*>(
133      GetAttribute(STUN_ATTR_TRANSPORT_PREFERENCES));
134}
135
136const StunAttribute* StunMessage::GetAttribute(StunAttributeType type) const {
137  for (unsigned i = 0; i < attrs_->size(); i++) {
138    if ((*attrs_)[i]->type() == type)
139      return (*attrs_)[i];
140  }
141  return 0;
142}
143
144bool StunMessage::Read(ByteBuffer* buf) {
145  if (!buf->ReadUInt16(&type_))
146    return false;
147
148  if (type_ & 0x8000) {
149    // rtp and rtcp set MSB of first byte, since first two bits are version,
150    // and version is always 2 (10).  If set, this is not a stun packet.
151    return false;
152  }
153
154  if (!buf->ReadUInt16(&length_))
155    return false;
156
157  std::string transaction_id;
158  if (!buf->ReadString(&transaction_id, 16))
159    return false;
160  ASSERT(transaction_id.size() == 16);
161  transaction_id_ = transaction_id;
162
163  if (length_ > buf->Length())
164    return false;
165
166  attrs_->resize(0);
167
168  size_t rest = buf->Length() - length_;
169  while (buf->Length() > rest) {
170    uint16 attr_type, attr_length;
171    if (!buf->ReadUInt16(&attr_type))
172      return false;
173    if (!buf->ReadUInt16(&attr_length))
174      return false;
175
176    StunAttribute* attr = StunAttribute::Create(attr_type, attr_length);
177    if (!attr || !attr->Read(buf))
178      return false;
179
180    attrs_->push_back(attr);
181  }
182
183  if (buf->Length() != rest) {
184    // fixme: shouldn't be doing this
185    LOG(LERROR) << "wrong message length (" << rest << " != " << buf->Length()
186                << ")";
187    return false;
188  }
189
190  return true;
191}
192
193void StunMessage::Write(ByteBuffer* buf) const {
194  buf->WriteUInt16(type_);
195  buf->WriteUInt16(length_);
196  buf->WriteString(transaction_id_);
197
198  for (unsigned i = 0; i < attrs_->size(); i++) {
199    buf->WriteUInt16((*attrs_)[i]->type());
200    buf->WriteUInt16((*attrs_)[i]->length());
201    (*attrs_)[i]->Write(buf);
202  }
203}
204
205StunAttribute::StunAttribute(uint16 type, uint16 length)
206    : type_(type), length_(length) {
207}
208
209StunAttribute* StunAttribute::Create(uint16 type, uint16 length) {
210  switch (type) {
211  case STUN_ATTR_MAPPED_ADDRESS:
212  case STUN_ATTR_RESPONSE_ADDRESS:
213  case STUN_ATTR_SOURCE_ADDRESS:
214  case STUN_ATTR_CHANGED_ADDRESS:
215  case STUN_ATTR_REFLECTED_FROM:
216  case STUN_ATTR_ALTERNATE_SERVER:
217  case STUN_ATTR_DESTINATION_ADDRESS:
218  case STUN_ATTR_SOURCE_ADDRESS2:
219    if (length != StunAddressAttribute::SIZE)
220      return 0;
221    return new StunAddressAttribute(type);
222
223  case STUN_ATTR_CHANGE_REQUEST:
224  case STUN_ATTR_LIFETIME:
225  case STUN_ATTR_BANDWIDTH:
226  case STUN_ATTR_OPTIONS:
227    if (length != StunUInt32Attribute::SIZE)
228      return 0;
229    return new StunUInt32Attribute(type);
230
231  case STUN_ATTR_USERNAME:
232  case STUN_ATTR_PASSWORD:
233  case STUN_ATTR_MAGIC_COOKIE:
234    return (length % 4 == 0) ? new StunByteStringAttribute(type, length) : 0;
235
236  case STUN_ATTR_MESSAGE_INTEGRITY:
237    return (length == 20) ? new StunByteStringAttribute(type, length) : 0;
238
239  case STUN_ATTR_DATA:
240    return new StunByteStringAttribute(type, length);
241
242  case STUN_ATTR_ERROR_CODE:
243    if (length < StunErrorCodeAttribute::MIN_SIZE)
244      return 0;
245    return new StunErrorCodeAttribute(type, length);
246
247  case STUN_ATTR_UNKNOWN_ATTRIBUTES:
248    return (length % 2 == 0) ? new StunUInt16ListAttribute(type, length) : 0;
249
250  case STUN_ATTR_TRANSPORT_PREFERENCES:
251    if ((length != StunTransportPrefsAttribute::SIZE1) &&
252        (length != StunTransportPrefsAttribute::SIZE2))
253      return 0;
254    return new StunTransportPrefsAttribute(type, length);
255
256  default:
257    return 0;
258  }
259}
260
261StunAddressAttribute* StunAttribute::CreateAddress(uint16 type) {
262  switch (type) {
263  case STUN_ATTR_MAPPED_ADDRESS:
264  case STUN_ATTR_RESPONSE_ADDRESS:
265  case STUN_ATTR_SOURCE_ADDRESS:
266  case STUN_ATTR_CHANGED_ADDRESS:
267  case STUN_ATTR_REFLECTED_FROM:
268  case STUN_ATTR_ALTERNATE_SERVER:
269  case STUN_ATTR_DESTINATION_ADDRESS:
270  case STUN_ATTR_SOURCE_ADDRESS2:
271    return new StunAddressAttribute(type);
272
273  default:
274    ASSERT(false);
275    return 0;
276  }
277}
278
279StunUInt32Attribute* StunAttribute::CreateUInt32(uint16 type) {
280  switch (type) {
281  case STUN_ATTR_CHANGE_REQUEST:
282  case STUN_ATTR_LIFETIME:
283  case STUN_ATTR_BANDWIDTH:
284  case STUN_ATTR_OPTIONS:
285    return new StunUInt32Attribute(type);
286
287  default:
288    ASSERT(false);
289    return 0;
290  }
291}
292
293StunByteStringAttribute* StunAttribute::CreateByteString(uint16 type) {
294  switch (type) {
295  case STUN_ATTR_USERNAME:
296  case STUN_ATTR_PASSWORD:
297  case STUN_ATTR_MESSAGE_INTEGRITY:
298  case STUN_ATTR_DATA:
299  case STUN_ATTR_MAGIC_COOKIE:
300    return new StunByteStringAttribute(type, 0);
301
302  default:
303    ASSERT(false);
304    return 0;
305  }
306}
307
308StunErrorCodeAttribute* StunAttribute::CreateErrorCode() {
309  return new StunErrorCodeAttribute(
310      STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
311}
312
313StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() {
314  return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
315}
316
317StunTransportPrefsAttribute* StunAttribute::CreateTransportPrefs() {
318  return new StunTransportPrefsAttribute(
319      STUN_ATTR_TRANSPORT_PREFERENCES, StunTransportPrefsAttribute::SIZE1);
320}
321
322StunAddressAttribute::StunAddressAttribute(uint16 type)
323    : StunAttribute(type, SIZE), family_(0), port_(0), ip_(0) {
324}
325
326bool StunAddressAttribute::Read(ByteBuffer* buf) {
327  uint8 dummy;
328  if (!buf->ReadUInt8(&dummy))
329    return false;
330  if (!buf->ReadUInt8(&family_))
331    return false;
332  if (!buf->ReadUInt16(&port_))
333    return false;
334  if (!buf->ReadUInt32(&ip_))
335    return false;
336  return true;
337}
338
339void StunAddressAttribute::Write(ByteBuffer* buf) const {
340  buf->WriteUInt8(0);
341  buf->WriteUInt8(family_);
342  buf->WriteUInt16(port_);
343  buf->WriteUInt32(ip_);
344}
345
346StunUInt32Attribute::StunUInt32Attribute(uint16 type)
347    : StunAttribute(type, SIZE), bits_(0) {
348}
349
350bool StunUInt32Attribute::GetBit(int index) const {
351  ASSERT((0 <= index) && (index < 32));
352  return static_cast<bool>((bits_ >> index) & 0x1);
353}
354
355void StunUInt32Attribute::SetBit(int index, bool value) {
356  ASSERT((0 <= index) && (index < 32));
357  bits_ &= ~(1 << index);
358  bits_ |= value ? (1 << index) : 0;
359}
360
361bool StunUInt32Attribute::Read(ByteBuffer* buf) {
362  if (!buf->ReadUInt32(&bits_))
363    return false;
364  return true;
365}
366
367void StunUInt32Attribute::Write(ByteBuffer* buf) const {
368  buf->WriteUInt32(bits_);
369}
370
371StunByteStringAttribute::StunByteStringAttribute(uint16 type, uint16 length)
372    : StunAttribute(type, length), bytes_(0) {
373}
374
375StunByteStringAttribute::~StunByteStringAttribute() {
376  delete [] bytes_;
377}
378
379void StunByteStringAttribute::SetBytes(char* bytes, uint16 length) {
380  delete [] bytes_;
381  bytes_ = bytes;
382  SetLength(length);
383}
384
385void StunByteStringAttribute::CopyBytes(const char* bytes) {
386  CopyBytes(bytes, static_cast<uint16>(strlen(bytes)));
387}
388
389void StunByteStringAttribute::CopyBytes(const void* bytes, uint16 length) {
390  char* new_bytes = new char[length];
391  std::memcpy(new_bytes, bytes, length);
392  SetBytes(new_bytes, length);
393}
394
395uint8 StunByteStringAttribute::GetByte(int index) const {
396  ASSERT(bytes_ != NULL);
397  ASSERT((0 <= index) && (index < length()));
398  return static_cast<uint8>(bytes_[index]);
399}
400
401void StunByteStringAttribute::SetByte(int index, uint8 value) {
402  ASSERT(bytes_ != NULL);
403  ASSERT((0 <= index) && (index < length()));
404  bytes_[index] = value;
405}
406
407bool StunByteStringAttribute::Read(ByteBuffer* buf) {
408  bytes_ = new char[length()];
409  if (!buf->ReadBytes(bytes_, length()))
410    return false;
411  return true;
412}
413
414void StunByteStringAttribute::Write(ByteBuffer* buf) const {
415  buf->WriteBytes(bytes_, length());
416}
417
418StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, uint16 length)
419    : StunAttribute(type, length), class_(0), number_(0) {
420}
421
422StunErrorCodeAttribute::~StunErrorCodeAttribute() {
423}
424
425void StunErrorCodeAttribute::SetErrorCode(uint32 code) {
426  class_ = (uint8)((code >> 8) & 0x7);
427  number_ = (uint8)(code & 0xff);
428}
429
430void StunErrorCodeAttribute::SetReason(const std::string& reason) {
431  SetLength(MIN_SIZE + static_cast<uint16>(reason.size()));
432  reason_ = reason;
433}
434
435bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
436  uint32 val;
437  if (!buf->ReadUInt32(&val))
438    return false;
439
440  if ((val >> 11) != 0)
441    LOG(LERROR) << "error-code bits not zero";
442
443  SetErrorCode(val);
444
445  if (!buf->ReadString(&reason_, length() - 4))
446    return false;
447
448  return true;
449}
450
451void StunErrorCodeAttribute::Write(ByteBuffer* buf) const {
452  buf->WriteUInt32(error_code());
453  buf->WriteString(reason_);
454}
455
456StunUInt16ListAttribute::StunUInt16ListAttribute(uint16 type, uint16 length)
457    : StunAttribute(type, length) {
458  attr_types_ = new std::vector<uint16>();
459}
460
461StunUInt16ListAttribute::~StunUInt16ListAttribute() {
462  delete attr_types_;
463}
464
465size_t StunUInt16ListAttribute::Size() const {
466  return attr_types_->size();
467}
468
469uint16 StunUInt16ListAttribute::GetType(int index) const {
470  return (*attr_types_)[index];
471}
472
473void StunUInt16ListAttribute::SetType(int index, uint16 value) {
474  (*attr_types_)[index] = value;
475}
476
477void StunUInt16ListAttribute::AddType(uint16 value) {
478  attr_types_->push_back(value);
479  SetLength(static_cast<uint16>(attr_types_->size() * 2));
480}
481
482bool StunUInt16ListAttribute::Read(ByteBuffer* buf) {
483  for (int i = 0; i < length() / 2; i++) {
484    uint16 attr;
485    if (!buf->ReadUInt16(&attr))
486      return false;
487    attr_types_->push_back(attr);
488  }
489  return true;
490}
491
492void StunUInt16ListAttribute::Write(ByteBuffer* buf) const {
493  for (unsigned i = 0; i < attr_types_->size(); i++)
494    buf->WriteUInt16((*attr_types_)[i]);
495}
496
497StunTransportPrefsAttribute::StunTransportPrefsAttribute(
498    uint16 type, uint16 length)
499    : StunAttribute(type, length), preallocate_(false), prefs_(0), addr_(0) {
500}
501
502StunTransportPrefsAttribute::~StunTransportPrefsAttribute() {
503  delete addr_;
504}
505
506void StunTransportPrefsAttribute::SetPreallocateAddress(
507    StunAddressAttribute* addr) {
508  if (!addr) {
509    preallocate_ = false;
510    addr_ = 0;
511    SetLength(SIZE1);
512  } else {
513    preallocate_ = true;
514    addr_ = addr;
515    SetLength(SIZE2);
516  }
517}
518
519bool StunTransportPrefsAttribute::Read(ByteBuffer* buf) {
520  uint32 val;
521  if (!buf->ReadUInt32(&val))
522    return false;
523
524  if ((val >> 3) != 0)
525    LOG(LERROR) << "transport-preferences bits not zero";
526
527  preallocate_ = static_cast<bool>((val >> 2) & 0x1);
528  prefs_ = (uint8)(val & 0x3);
529
530  if (preallocate_ && (prefs_ == 3))
531    LOG(LERROR) << "transport-preferences imcompatible P and Typ";
532
533  if (!preallocate_) {
534    if (length() != StunUInt32Attribute::SIZE)
535      return false;
536  } else {
537    if (length() != StunUInt32Attribute::SIZE + StunAddressAttribute::SIZE)
538      return false;
539
540    addr_ = new StunAddressAttribute(STUN_ATTR_SOURCE_ADDRESS);
541    addr_->Read(buf);
542  }
543
544  return true;
545}
546
547void StunTransportPrefsAttribute::Write(ByteBuffer* buf) const {
548  buf->WriteUInt32((preallocate_ ? 4 : 0) | prefs_);
549
550  if (preallocate_)
551    addr_->Write(buf);
552}
553
554StunMessageType GetStunResponseType(StunMessageType request_type) {
555  switch (request_type) {
556  case STUN_SHARED_SECRET_REQUEST:
557    return STUN_SHARED_SECRET_RESPONSE;
558  case STUN_ALLOCATE_REQUEST:
559    return STUN_ALLOCATE_RESPONSE;
560  case STUN_SEND_REQUEST:
561    return STUN_SEND_RESPONSE;
562  default:
563    return STUN_BINDING_RESPONSE;
564  }
565}
566
567StunMessageType GetStunErrorResponseType(StunMessageType request_type) {
568  switch (request_type) {
569  case STUN_SHARED_SECRET_REQUEST:
570    return STUN_SHARED_SECRET_ERROR_RESPONSE;
571  case STUN_ALLOCATE_REQUEST:
572    return STUN_ALLOCATE_ERROR_RESPONSE;
573  case STUN_SEND_REQUEST:
574    return STUN_SEND_ERROR_RESPONSE;
575  default:
576    return STUN_BINDING_ERROR_RESPONSE;
577  }
578}
579
580} // namespace cricket
581