1 /*
2  *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef P2P_BASE_TEST_TURN_SERVER_H_
12 #define P2P_BASE_TEST_TURN_SERVER_H_
13 
14 #include <string>
15 #include <vector>
16 
17 #include "api/transport/stun.h"
18 #include "p2p/base/basic_packet_socket_factory.h"
19 #include "p2p/base/turn_server.h"
20 #include "rtc_base/async_udp_socket.h"
21 #include "rtc_base/ssl_adapter.h"
22 #include "rtc_base/ssl_identity.h"
23 #include "rtc_base/thread.h"
24 #include "rtc_base/thread_checker.h"
25 
26 namespace cricket {
27 
28 static const char kTestRealm[] = "example.org";
29 static const char kTestSoftware[] = "TestTurnServer";
30 
31 class TestTurnRedirector : public TurnRedirectInterface {
32  public:
TestTurnRedirector(const std::vector<rtc::SocketAddress> & addresses)33   explicit TestTurnRedirector(const std::vector<rtc::SocketAddress>& addresses)
34       : alternate_server_addresses_(addresses),
35         iter_(alternate_server_addresses_.begin()) {}
36 
ShouldRedirect(const rtc::SocketAddress &,rtc::SocketAddress * out)37   virtual bool ShouldRedirect(const rtc::SocketAddress&,
38                               rtc::SocketAddress* out) {
39     if (!out || iter_ == alternate_server_addresses_.end()) {
40       return false;
41     }
42     *out = *iter_++;
43     return true;
44   }
45 
46  private:
47   const std::vector<rtc::SocketAddress>& alternate_server_addresses_;
48   std::vector<rtc::SocketAddress>::const_iterator iter_;
49 };
50 
51 class TestTurnServer : public TurnAuthInterface {
52  public:
53   TestTurnServer(rtc::Thread* thread,
54                  const rtc::SocketAddress& int_addr,
55                  const rtc::SocketAddress& udp_ext_addr,
56                  ProtocolType int_protocol = PROTO_UDP,
57                  bool ignore_bad_cert = true,
58                  const std::string& common_name = "test turn server")
server_(thread)59       : server_(thread), thread_(thread) {
60     AddInternalSocket(int_addr, int_protocol, ignore_bad_cert, common_name);
61     server_.SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(thread),
62                                      udp_ext_addr);
63     server_.set_realm(kTestRealm);
64     server_.set_software(kTestSoftware);
65     server_.set_auth_hook(this);
66   }
67 
~TestTurnServer()68   ~TestTurnServer() { RTC_DCHECK(thread_checker_.IsCurrent()); }
69 
set_enable_otu_nonce(bool enable)70   void set_enable_otu_nonce(bool enable) {
71     RTC_DCHECK(thread_checker_.IsCurrent());
72     server_.set_enable_otu_nonce(enable);
73   }
74 
server()75   TurnServer* server() {
76     RTC_DCHECK(thread_checker_.IsCurrent());
77     return &server_;
78   }
79 
set_redirect_hook(TurnRedirectInterface * redirect_hook)80   void set_redirect_hook(TurnRedirectInterface* redirect_hook) {
81     RTC_DCHECK(thread_checker_.IsCurrent());
82     server_.set_redirect_hook(redirect_hook);
83   }
84 
set_enable_permission_checks(bool enable)85   void set_enable_permission_checks(bool enable) {
86     RTC_DCHECK(thread_checker_.IsCurrent());
87     server_.set_enable_permission_checks(enable);
88   }
89 
90   void AddInternalSocket(const rtc::SocketAddress& int_addr,
91                          ProtocolType proto,
92                          bool ignore_bad_cert = true,
93                          const std::string& common_name = "test turn server") {
94     RTC_DCHECK(thread_checker_.IsCurrent());
95     if (proto == cricket::PROTO_UDP) {
96       server_.AddInternalSocket(
97           rtc::AsyncUDPSocket::Create(thread_->socketserver(), int_addr),
98           proto);
99     } else if (proto == cricket::PROTO_TCP || proto == cricket::PROTO_TLS) {
100       // For TCP we need to create a server socket which can listen for incoming
101       // new connections.
102       rtc::AsyncSocket* socket =
103           thread_->socketserver()->CreateAsyncSocket(AF_INET, SOCK_STREAM);
104       if (proto == cricket::PROTO_TLS) {
105         // For TLS, wrap the TCP socket with an SSL adapter. The adapter must
106         // be configured with a self-signed certificate for testing.
107         // Additionally, the client will not present a valid certificate, so we
108         // must not fail when checking the peer's identity.
109         rtc::SSLAdapter* adapter = rtc::SSLAdapter::Create(socket);
110         adapter->SetRole(rtc::SSL_SERVER);
111         adapter->SetIdentity(
112             rtc::SSLIdentity::Create(common_name, rtc::KeyParams()));
113         adapter->SetIgnoreBadCert(ignore_bad_cert);
114         socket = adapter;
115       }
116       socket->Bind(int_addr);
117       socket->Listen(5);
118       server_.AddInternalServerSocket(socket, proto);
119     } else {
120       RTC_NOTREACHED() << "Unknown protocol type: " << proto;
121     }
122   }
123 
124   // Finds the first allocation in the server allocation map with a source
125   // ip and port matching the socket address provided.
FindAllocation(const rtc::SocketAddress & src)126   TurnServerAllocation* FindAllocation(const rtc::SocketAddress& src) {
127     RTC_DCHECK(thread_checker_.IsCurrent());
128     const TurnServer::AllocationMap& map = server_.allocations();
129     for (TurnServer::AllocationMap::const_iterator it = map.begin();
130          it != map.end(); ++it) {
131       if (src == it->first.src()) {
132         return it->second.get();
133       }
134     }
135     return NULL;
136   }
137 
138  private:
139   // For this test server, succeed if the password is the same as the username.
140   // Obviously, do not use this in a production environment.
GetKey(const std::string & username,const std::string & realm,std::string * key)141   virtual bool GetKey(const std::string& username,
142                       const std::string& realm,
143                       std::string* key) {
144     RTC_DCHECK(thread_checker_.IsCurrent());
145     return ComputeStunCredentialHash(username, realm, username, key);
146   }
147 
148   TurnServer server_;
149   rtc::Thread* thread_;
150   rtc::ThreadChecker thread_checker_;
151 };
152 
153 }  // namespace cricket
154 
155 #endif  // P2P_BASE_TEST_TURN_SERVER_H_
156