| /* |
| * libjingle |
| * Copyright 2004--2005, Google Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef TALK_P2P_BASE_STUN_H_ |
| #define TALK_P2P_BASE_STUN_H_ |
| |
| // This file contains classes for dealing with the STUN and TURN protocols. |
| // Both protocols use the same wire format. |
| |
| #include <string> |
| #include <vector> |
| |
| #include "talk/base/basictypes.h" |
| #include "talk/base/bytebuffer.h" |
| #include "talk/base/socketaddress.h" |
| |
| namespace cricket { |
| |
| // These are the types of STUN & TURN messages as of last check. |
| enum StunMessageType { |
| STUN_BINDING_REQUEST = 0x0001, |
| STUN_BINDING_RESPONSE = 0x0101, |
| STUN_BINDING_ERROR_RESPONSE = 0x0111, |
| STUN_SHARED_SECRET_REQUEST = 0x0002, |
| STUN_SHARED_SECRET_RESPONSE = 0x0102, |
| STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112, |
| STUN_ALLOCATE_REQUEST = 0x0003, |
| STUN_ALLOCATE_RESPONSE = 0x0103, |
| STUN_ALLOCATE_ERROR_RESPONSE = 0x0113, |
| STUN_SEND_REQUEST = 0x0004, |
| STUN_SEND_RESPONSE = 0x0104, |
| STUN_SEND_ERROR_RESPONSE = 0x0114, |
| STUN_DATA_INDICATION = 0x0115 |
| }; |
| |
| // These are the types of attributes defined in STUN & TURN. Next to each is |
| // the name of the class (T is StunTAttribute) that implements that type. |
| // |
| // TODO: Some attributes defined in RFC5389 are not |
| // implemented yet, particularly REALM, NONCE, SOFTWARE, |
| // ALTERNATE-SERVE and FINGEPRINT. Implement them. |
| enum StunAttributeType { |
| STUN_ATTR_MAPPED_ADDRESS = 0x0001, // Address |
| STUN_ATTR_USERNAME = 0x0006, // ByteString, multiple of 4 bytes |
| STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, // ByteString, 20 bytes |
| STUN_ATTR_ERROR_CODE = 0x0009, // ErrorCode |
| STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000a, // UInt16List |
| STUN_ATTR_LIFETIME = 0x000d, // UInt32 |
| STUN_ATTR_MAGIC_COOKIE = 0x000f, // ByteString, 4 bytes |
| STUN_ATTR_BANDWIDTH = 0x0010, // UInt32 |
| STUN_ATTR_DESTINATION_ADDRESS = 0x0011, // Address |
| STUN_ATTR_SOURCE_ADDRESS2 = 0x0012, // Address |
| STUN_ATTR_DATA = 0x0013, // ByteString |
| STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020, // XorAddress |
| STUN_ATTR_OPTIONS = 0x8001 // UInt32 |
| }; |
| |
| enum StunErrorCodes { |
| STUN_ERROR_BAD_REQUEST = 400, |
| STUN_ERROR_UNAUTHORIZED = 401, |
| STUN_ERROR_UNKNOWN_ATTRIBUTE = 420, |
| STUN_ERROR_STALE_CREDENTIALS = 430, |
| STUN_ERROR_INTEGRITY_CHECK_FAILURE = 431, |
| STUN_ERROR_MISSING_USERNAME = 432, |
| STUN_ERROR_USE_TLS = 433, |
| STUN_ERROR_SERVER_ERROR = 500, |
| STUN_ERROR_GLOBAL_FAILURE = 600 |
| }; |
| |
| enum StunAddressFamily { |
| // NB: UNDEF is not part of the STUN spec. |
| STUN_ADDRESS_UNDEF = 0, |
| STUN_ADDRESS_IPV4 = 1, |
| STUN_ADDRESS_IPV6 = 2 |
| }; |
| |
| extern const char STUN_ERROR_REASON_BAD_REQUEST[]; |
| extern const char STUN_ERROR_REASON_STALE_CREDENTIALS[]; |
| extern const char STUN_ERROR_REASON_SERVER_ERROR[]; |
| |
| // Following values correspond to RFC5389. |
| const size_t kStunTransactionIdOffset = 8; |
| const size_t kStunTransactionIdLength = 12; |
| const uint32 kStunMagicCookie = 0x2112A442; |
| const size_t kStunMagicCookieLength = sizeof(kStunMagicCookie); |
| |
| // Following value corresponds to an earlier version of STUN from |
| // RFC3489. |
| const size_t kStunLegacyTransactionIdLength = 16; |
| |
| class StunAttribute; |
| class StunAddressAttribute; |
| class StunUInt32Attribute; |
| class StunByteStringAttribute; |
| class StunErrorCodeAttribute; |
| class StunUInt16ListAttribute; |
| class StunTransportPrefsAttribute; |
| |
| // Records a complete STUN/TURN message. Each message consists of a type and |
| // any number of attributes. Each attribute is parsed into an instance of an |
| // appropriate class (see above). The Get* methods will return instances of |
| // that attribute class. |
| class StunMessage { |
| public: |
| StunMessage(); |
| ~StunMessage(); |
| StunMessageType type() const { return static_cast<StunMessageType>(type_); } |
| uint16 length() const { return length_; } |
| const std::string& transaction_id() const { return transaction_id_; } |
| |
| // Returns true if the message confirms to RFC3489 rather than |
| // RFC5389. The main difference between two version of the STUN |
| // protocol is the presence of the magic cookie and different length |
| // of transaction ID. For outgoing packets version of the protocol |
| // is determined by the lengths of the transaction ID. |
| bool IsLegacy() const; |
| |
| void SetType(StunMessageType type) { type_ = type; } |
| bool SetTransactionID(const std::string& str); |
| |
| const StunAddressAttribute* GetAddress(StunAttributeType type) const; |
| const StunUInt32Attribute* GetUInt32(StunAttributeType type) const; |
| const StunByteStringAttribute* GetByteString(StunAttributeType type) const; |
| const StunErrorCodeAttribute* GetErrorCode() const; |
| const StunUInt16ListAttribute* GetUnknownAttributes() const; |
| const StunTransportPrefsAttribute* GetTransportPrefs() const; |
| |
| void AddAttribute(StunAttribute* attr); |
| |
| // Parses the STUN/TURN packet in the given buffer and records it here. The |
| // return value indicates whether this was successful. |
| bool Read(talk_base::ByteBuffer* buf); |
| |
| // Writes this object into a STUN/TURN packet. Return value is true if |
| // successful. |
| void Write(talk_base::ByteBuffer* buf) const; |
| |
| private: |
| uint16 type_; |
| uint16 length_; |
| std::string transaction_id_; |
| std::vector<StunAttribute*>* attrs_; |
| |
| const StunAttribute* GetAttribute(StunAttributeType type) const; |
| static bool IsValidTransactionId(const std::string& transaction_id); |
| }; |
| |
| // Base class for all STUN/TURN attributes. |
| class StunAttribute { |
| public: |
| virtual ~StunAttribute() {} |
| |
| StunAttributeType type() const { |
| return static_cast<StunAttributeType>(type_); |
| } |
| uint16 length() const { return length_; } |
| |
| // Only XorAddressAttribute needs this so far. |
| virtual void SetOwner(StunMessage* owner) { } |
| |
| // Reads the body (not the type or length) for this type of attribute from |
| // the given buffer. Return value is true if successful. |
| virtual bool Read(talk_base::ByteBuffer* buf) = 0; |
| |
| // Writes the body (not the type or length) to the given buffer. Return |
| // value is true if successful. |
| virtual void Write(talk_base::ByteBuffer* buf) const = 0; |
| |
| // Creates an attribute object with the given type, length and transaction id. |
| static StunAttribute* Create(uint16 type, uint16 length, |
| StunMessage* owner); |
| |
| // Creates an attribute object with the given type and smallest length. |
| static StunAddressAttribute* CreateAddress(uint16 type); |
| static StunUInt32Attribute* CreateUInt32(uint16 type); |
| static StunByteStringAttribute* CreateByteString(uint16 type); |
| static StunErrorCodeAttribute* CreateErrorCode(); |
| static StunUInt16ListAttribute* CreateUnknownAttributes(); |
| static StunTransportPrefsAttribute* CreateTransportPrefs(); |
| |
| protected: |
| StunAttribute(uint16 type, uint16 length); |
| void SetLength(uint16 length) { length_ = length; } |
| void WritePadding(talk_base::ByteBuffer* buf) const; |
| void ConsumePadding(talk_base::ByteBuffer* buf) const; |
| |
| private: |
| uint16 type_; |
| uint16 length_; |
| }; |
| |
| // Implements STUN/TURN attributes that record an Internet address. |
| class StunAddressAttribute : public StunAttribute { |
| public: |
| StunAddressAttribute(uint16 type, uint16 length); |
| |
| static const uint16 SIZE_UNDEF = 0; |
| static const uint16 SIZE_IP4 = 8; |
| static const uint16 SIZE_IP6 = 20; |
| |
| StunAddressFamily family() const { |
| switch (address_.ipaddr().family()) { |
| case AF_INET: |
| return STUN_ADDRESS_IPV4; |
| case AF_INET6: |
| return STUN_ADDRESS_IPV6; |
| } |
| return STUN_ADDRESS_UNDEF; |
| } |
| |
| uint16 port() const { return address_.port(); } |
| const talk_base::IPAddress& ipaddr() const { return address_.ipaddr(); } |
| void SetAddress(const talk_base::SocketAddress& addr) { |
| address_ = addr; |
| EnsureAddressLength(); |
| } |
| const talk_base::SocketAddress& GetAddress() const { return address_; } |
| void SetIP(const talk_base::IPAddress& ip) { |
| address_.SetIP(ip); |
| EnsureAddressLength(); |
| } |
| void SetPort(uint16 port) { address_.SetPort(port); } |
| |
| virtual bool Read(talk_base::ByteBuffer* buf); |
| virtual void Write(talk_base::ByteBuffer* buf) const; |
| |
| private: |
| void EnsureAddressLength() { |
| switch (family()) { |
| case STUN_ADDRESS_IPV4: { |
| SetLength(SIZE_IP4); |
| break; |
| } |
| case STUN_ADDRESS_IPV6: { |
| SetLength(SIZE_IP6); |
| break; |
| } |
| default: { |
| SetLength(SIZE_UNDEF); |
| break; |
| } |
| } |
| } |
| talk_base::SocketAddress address_; |
| }; |
| |
| // Implements STUN/TURN attributes that record an Internet address. When encoded |
| // in a STUN message, the address contained in this attribute is XORed with the |
| // transaction ID of the message. |
| class StunXorAddressAttribute : public StunAddressAttribute { |
| public: |
| StunXorAddressAttribute(uint16 type, uint16 length); |
| StunXorAddressAttribute(uint16 type, uint16 length, |
| StunMessage* owner); |
| |
| virtual void SetOwner(StunMessage* owner) { |
| owner_ = owner; |
| } |
| virtual bool Read(talk_base::ByteBuffer* buf); |
| virtual void Write(talk_base::ByteBuffer* buf) const; |
| private: |
| talk_base::IPAddress GetXoredIP() const; |
| StunMessage* owner_; |
| }; |
| |
| // Implements STUN/TURN attributs that record a 32-bit integer. |
| class StunUInt32Attribute : public StunAttribute { |
| public: |
| explicit StunUInt32Attribute(uint16 type); |
| |
| static const uint16 SIZE = 4; |
| |
| uint32 value() const { return bits_; } |
| |
| void SetValue(uint32 bits) { bits_ = bits; } |
| |
| bool GetBit(int index) const; |
| void SetBit(int index, bool value); |
| |
| bool Read(talk_base::ByteBuffer* buf); |
| void Write(talk_base::ByteBuffer* buf) const; |
| |
| private: |
| uint32 bits_; |
| }; |
| |
| // Implements STUN/TURN attributes that record an arbitrary byte string |
| class StunByteStringAttribute : public StunAttribute { |
| public: |
| StunByteStringAttribute(uint16 type, uint16 length); |
| ~StunByteStringAttribute(); |
| |
| const char* bytes() const { return bytes_; } |
| |
| void SetBytes(char* bytes, uint16 length); |
| |
| void CopyBytes(const char* bytes); // uses strlen |
| void CopyBytes(const void* bytes, uint16 length); |
| |
| uint8 GetByte(int index) const; |
| void SetByte(int index, uint8 value); |
| |
| bool Read(talk_base::ByteBuffer* buf); |
| void Write(talk_base::ByteBuffer* buf) const; |
| |
| private: |
| char* bytes_; |
| }; |
| |
| // Implements STUN/TURN attributes that record an error code. |
| class StunErrorCodeAttribute : public StunAttribute { |
| public: |
| StunErrorCodeAttribute(uint16 type, uint16 length); |
| ~StunErrorCodeAttribute(); |
| |
| static const uint16 MIN_SIZE = 4; |
| |
| uint32 error_code() const { return (class_ << 8) | number_; } |
| uint8 error_class() const { return class_; } |
| uint8 number() const { return number_; } |
| const std::string& reason() const { return reason_; } |
| |
| void SetErrorCode(uint32 code); |
| void SetErrorClass(uint8 eclass) { class_ = eclass; } |
| void SetNumber(uint8 number) { number_ = number; } |
| void SetReason(const std::string& reason); |
| |
| bool Read(talk_base::ByteBuffer* buf); |
| void Write(talk_base::ByteBuffer* buf) const; |
| |
| private: |
| uint8 class_; |
| uint8 number_; |
| std::string reason_; |
| }; |
| |
| // Implements STUN/TURN attributes that record a list of attribute names. |
| class StunUInt16ListAttribute : public StunAttribute { |
| public: |
| StunUInt16ListAttribute(uint16 type, uint16 length); |
| ~StunUInt16ListAttribute(); |
| |
| size_t Size() const; |
| uint16 GetType(int index) const; |
| void SetType(int index, uint16 value); |
| void AddType(uint16 value); |
| |
| bool Read(talk_base::ByteBuffer* buf); |
| void Write(talk_base::ByteBuffer* buf) const; |
| |
| private: |
| std::vector<uint16>* attr_types_; |
| }; |
| |
| // The special MAGIC-COOKIE attribute is used to distinguish TURN packets from |
| // other kinds of traffic. |
| // TODO: This value has nothing to do with STUN. Move it to a |
| // separate file. |
| extern const char TURN_MAGIC_COOKIE_VALUE[4]; |
| |
| // Returns the (successful) response type for the given request type. |
| StunMessageType GetStunResponseType(StunMessageType request_type); |
| |
| // Returns the error response type for the given request type. |
| StunMessageType GetStunErrorResponseType(StunMessageType request_type); |
| |
| } // namespace cricket |
| |
| #endif // TALK_P2P_BASE_STUN_H_ |