/* * Copyright 2012 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef WEBRTC_P2P_BASE_TURNSERVER_H_ #define WEBRTC_P2P_BASE_TURNSERVER_H_ #include #include #include #include #include #include "webrtc/p2p/base/portinterface.h" #include "webrtc/base/asyncpacketsocket.h" #include "webrtc/base/messagequeue.h" #include "webrtc/base/sigslot.h" #include "webrtc/base/socketaddress.h" namespace rtc { class ByteBufferWriter; class PacketSocketFactory; class Thread; } namespace cricket { class StunMessage; class TurnMessage; class TurnServer; // The default server port for TURN, as specified in RFC5766. const int TURN_SERVER_PORT = 3478; // Encapsulates the client's connection to the server. class TurnServerConnection { public: TurnServerConnection() : proto_(PROTO_UDP), socket_(NULL) {} TurnServerConnection(const rtc::SocketAddress& src, ProtocolType proto, rtc::AsyncPacketSocket* socket); const rtc::SocketAddress& src() const { return src_; } rtc::AsyncPacketSocket* socket() { return socket_; } bool operator==(const TurnServerConnection& t) const; bool operator<(const TurnServerConnection& t) const; std::string ToString() const; private: rtc::SocketAddress src_; rtc::SocketAddress dst_; cricket::ProtocolType proto_; rtc::AsyncPacketSocket* socket_; }; // Encapsulates a TURN allocation. // The object is created when an allocation request is received, and then // handles TURN messages (via HandleTurnMessage) and channel data messages // (via HandleChannelData) for this allocation when received by the server. // The object self-deletes and informs the server if its lifetime timer expires. class TurnServerAllocation : public rtc::MessageHandler, public sigslot::has_slots<> { public: TurnServerAllocation(TurnServer* server_, rtc::Thread* thread, const TurnServerConnection& conn, rtc::AsyncPacketSocket* server_socket, const std::string& key); virtual ~TurnServerAllocation(); TurnServerConnection* conn() { return &conn_; } const std::string& key() const { return key_; } const std::string& transaction_id() const { return transaction_id_; } const std::string& username() const { return username_; } const std::string& origin() const { return origin_; } const std::string& last_nonce() const { return last_nonce_; } void set_last_nonce(const std::string& nonce) { last_nonce_ = nonce; } std::string ToString() const; void HandleTurnMessage(const TurnMessage* msg); void HandleChannelData(const char* data, size_t size); sigslot::signal1 SignalDestroyed; private: class Channel; class Permission; typedef std::list PermissionList; typedef std::list ChannelList; void HandleAllocateRequest(const TurnMessage* msg); void HandleRefreshRequest(const TurnMessage* msg); void HandleSendIndication(const TurnMessage* msg); void HandleCreatePermissionRequest(const TurnMessage* msg); void HandleChannelBindRequest(const TurnMessage* msg); void OnExternalPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& addr, const rtc::PacketTime& packet_time); static int ComputeLifetime(const TurnMessage* msg); bool HasPermission(const rtc::IPAddress& addr); void AddPermission(const rtc::IPAddress& addr); Permission* FindPermission(const rtc::IPAddress& addr) const; Channel* FindChannel(int channel_id) const; Channel* FindChannel(const rtc::SocketAddress& addr) const; void SendResponse(TurnMessage* msg); void SendBadRequestResponse(const TurnMessage* req); void SendErrorResponse(const TurnMessage* req, int code, const std::string& reason); void SendExternal(const void* data, size_t size, const rtc::SocketAddress& peer); void OnPermissionDestroyed(Permission* perm); void OnChannelDestroyed(Channel* channel); virtual void OnMessage(rtc::Message* msg); TurnServer* server_; rtc::Thread* thread_; TurnServerConnection conn_; std::unique_ptr external_socket_; std::string key_; std::string transaction_id_; std::string username_; std::string origin_; std::string last_nonce_; PermissionList perms_; ChannelList channels_; }; // An interface through which the MD5 credential hash can be retrieved. class TurnAuthInterface { public: // Gets HA1 for the specified user and realm. // HA1 = MD5(A1) = MD5(username:realm:password). // Return true if the given username and realm are valid, or false if not. virtual bool GetKey(const std::string& username, const std::string& realm, std::string* key) = 0; virtual ~TurnAuthInterface() = default; }; // An interface enables Turn Server to control redirection behavior. class TurnRedirectInterface { public: virtual bool ShouldRedirect(const rtc::SocketAddress& address, rtc::SocketAddress* out) = 0; virtual ~TurnRedirectInterface() {} }; // The core TURN server class. Give it a socket to listen on via // AddInternalServerSocket, and a factory to create external sockets via // SetExternalSocketFactory, and it's ready to go. // Not yet wired up: TCP support. class TurnServer : public sigslot::has_slots<> { public: typedef std::map AllocationMap; explicit TurnServer(rtc::Thread* thread); ~TurnServer(); // Gets/sets the realm value to use for the server. const std::string& realm() const { return realm_; } void set_realm(const std::string& realm) { realm_ = realm; } // Gets/sets the value for the SOFTWARE attribute for TURN messages. const std::string& software() const { return software_; } void set_software(const std::string& software) { software_ = software; } const AllocationMap& allocations() const { return allocations_; } // Sets the authentication callback; does not take ownership. void set_auth_hook(TurnAuthInterface* auth_hook) { auth_hook_ = auth_hook; } void set_redirect_hook(TurnRedirectInterface* redirect_hook) { redirect_hook_ = redirect_hook; } void set_enable_otu_nonce(bool enable) { enable_otu_nonce_ = enable; } // If set to true, reject CreatePermission requests to RFC1918 addresses. void set_reject_private_addresses(bool filter) { reject_private_addresses_ = filter; } // Starts listening for packets from internal clients. void AddInternalSocket(rtc::AsyncPacketSocket* socket, ProtocolType proto); // Starts listening for the connections on this socket. When someone tries // to connect, the connection will be accepted and a new internal socket // will be added. void AddInternalServerSocket(rtc::AsyncSocket* socket, ProtocolType proto); // Specifies the factory to use for creating external sockets. void SetExternalSocketFactory(rtc::PacketSocketFactory* factory, const rtc::SocketAddress& address); // For testing only. std::string SetTimestampForNextNonce(int64_t timestamp) { ts_for_next_nonce_ = timestamp; return GenerateNonce(timestamp); } private: std::string GenerateNonce(int64_t now) const; void OnInternalPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& address, const rtc::PacketTime& packet_time); void OnNewInternalConnection(rtc::AsyncSocket* socket); // Accept connections on this server socket. void AcceptConnection(rtc::AsyncSocket* server_socket); void OnInternalSocketClose(rtc::AsyncPacketSocket* socket, int err); void HandleStunMessage( TurnServerConnection* conn, const char* data, size_t size); void HandleBindingRequest(TurnServerConnection* conn, const StunMessage* msg); void HandleAllocateRequest(TurnServerConnection* conn, const TurnMessage* msg, const std::string& key); bool GetKey(const StunMessage* msg, std::string* key); bool CheckAuthorization(TurnServerConnection* conn, const StunMessage* msg, const char* data, size_t size, const std::string& key); bool ValidateNonce(const std::string& nonce) const; TurnServerAllocation* FindAllocation(TurnServerConnection* conn); TurnServerAllocation* CreateAllocation( TurnServerConnection* conn, int proto, const std::string& key); void SendErrorResponse(TurnServerConnection* conn, const StunMessage* req, int code, const std::string& reason); void SendErrorResponseWithRealmAndNonce(TurnServerConnection* conn, const StunMessage* req, int code, const std::string& reason); void SendErrorResponseWithAlternateServer(TurnServerConnection* conn, const StunMessage* req, const rtc::SocketAddress& addr); void SendStun(TurnServerConnection* conn, StunMessage* msg); void Send(TurnServerConnection* conn, const rtc::ByteBufferWriter& buf); void OnAllocationDestroyed(TurnServerAllocation* allocation); void DestroyInternalSocket(rtc::AsyncPacketSocket* socket); typedef std::map InternalSocketMap; typedef std::map ServerSocketMap; rtc::Thread* thread_; std::string nonce_key_; std::string realm_; std::string software_; TurnAuthInterface* auth_hook_; TurnRedirectInterface* redirect_hook_; // otu - one-time-use. Server will respond with 438 if it's // sees the same nonce in next transaction. bool enable_otu_nonce_; bool reject_private_addresses_ = false; InternalSocketMap server_sockets_; ServerSocketMap server_listen_sockets_; std::unique_ptr external_socket_factory_; rtc::SocketAddress external_addr_; AllocationMap allocations_; // For testing only. If this is non-zero, the next NONCE will be generated // from this value, and it will be reset to 0 after generating the NONCE. int64_t ts_for_next_nonce_ = 0; friend class TurnServerAllocation; }; } // namespace cricket #endif // WEBRTC_P2P_BASE_TURNSERVER_H_