xref: /aosp_15_r20/external/webrtc/p2p/base/turn_server.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/turn_server.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <tuple>  // for std::tie
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker 
18*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
19*d9f75844SAndroid Build Coastguard Worker #include "absl/memory/memory.h"
20*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/array_view.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/packet_socket_factory.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/task_queue_base.h"
24*d9f75844SAndroid Build Coastguard Worker #include "api/transport/stun.h"
25*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/async_stun_tcp_socket.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/byte_buffer.h"
27*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
28*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/helpers.h"
29*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
30*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/message_digest.h"
31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/socket_adapters.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/string_builder.h"
33*d9f75844SAndroid Build Coastguard Worker 
34*d9f75844SAndroid Build Coastguard Worker namespace cricket {
35*d9f75844SAndroid Build Coastguard Worker namespace {
36*d9f75844SAndroid Build Coastguard Worker using ::webrtc::TimeDelta;
37*d9f75844SAndroid Build Coastguard Worker 
38*d9f75844SAndroid Build Coastguard Worker // TODO(juberti): Move this all to a future turnmessage.h
39*d9f75844SAndroid Build Coastguard Worker //  static const int IPPROTO_UDP = 17;
40*d9f75844SAndroid Build Coastguard Worker constexpr TimeDelta kNonceTimeout = TimeDelta::Minutes(60);
41*d9f75844SAndroid Build Coastguard Worker constexpr TimeDelta kDefaultAllocationTimeout = TimeDelta::Minutes(10);
42*d9f75844SAndroid Build Coastguard Worker constexpr TimeDelta kPermissionTimeout = TimeDelta::Minutes(5);
43*d9f75844SAndroid Build Coastguard Worker constexpr TimeDelta kChannelTimeout = TimeDelta::Minutes(10);
44*d9f75844SAndroid Build Coastguard Worker 
45*d9f75844SAndroid Build Coastguard Worker constexpr int kMinChannelNumber = 0x4000;
46*d9f75844SAndroid Build Coastguard Worker constexpr int kMaxChannelNumber = 0x7FFF;
47*d9f75844SAndroid Build Coastguard Worker 
48*d9f75844SAndroid Build Coastguard Worker constexpr size_t kNonceKeySize = 16;
49*d9f75844SAndroid Build Coastguard Worker constexpr size_t kNonceSize = 48;
50*d9f75844SAndroid Build Coastguard Worker 
51*d9f75844SAndroid Build Coastguard Worker constexpr size_t TURN_CHANNEL_HEADER_SIZE = 4U;
52*d9f75844SAndroid Build Coastguard Worker 
53*d9f75844SAndroid Build Coastguard Worker // TODO(mallinath) - Move these to a common place.
IsTurnChannelData(uint16_t msg_type)54*d9f75844SAndroid Build Coastguard Worker bool IsTurnChannelData(uint16_t msg_type) {
55*d9f75844SAndroid Build Coastguard Worker   // The first two bits of a channel data message are 0b01.
56*d9f75844SAndroid Build Coastguard Worker   return ((msg_type & 0xC000) == 0x4000);
57*d9f75844SAndroid Build Coastguard Worker }
58*d9f75844SAndroid Build Coastguard Worker 
59*d9f75844SAndroid Build Coastguard Worker }  // namespace
60*d9f75844SAndroid Build Coastguard Worker 
GetStunSuccessResponseTypeOrZero(const StunMessage & req)61*d9f75844SAndroid Build Coastguard Worker int GetStunSuccessResponseTypeOrZero(const StunMessage& req) {
62*d9f75844SAndroid Build Coastguard Worker   const int resp_type = GetStunSuccessResponseType(req.type());
63*d9f75844SAndroid Build Coastguard Worker   return resp_type == -1 ? 0 : resp_type;
64*d9f75844SAndroid Build Coastguard Worker }
65*d9f75844SAndroid Build Coastguard Worker 
GetStunErrorResponseTypeOrZero(const StunMessage & req)66*d9f75844SAndroid Build Coastguard Worker int GetStunErrorResponseTypeOrZero(const StunMessage& req) {
67*d9f75844SAndroid Build Coastguard Worker   const int resp_type = GetStunErrorResponseType(req.type());
68*d9f75844SAndroid Build Coastguard Worker   return resp_type == -1 ? 0 : resp_type;
69*d9f75844SAndroid Build Coastguard Worker }
70*d9f75844SAndroid Build Coastguard Worker 
InitErrorResponse(int code,absl::string_view reason,StunMessage * resp)71*d9f75844SAndroid Build Coastguard Worker static void InitErrorResponse(int code,
72*d9f75844SAndroid Build Coastguard Worker                               absl::string_view reason,
73*d9f75844SAndroid Build Coastguard Worker                               StunMessage* resp) {
74*d9f75844SAndroid Build Coastguard Worker   resp->AddAttribute(std::make_unique<cricket::StunErrorCodeAttribute>(
75*d9f75844SAndroid Build Coastguard Worker       STUN_ATTR_ERROR_CODE, code, std::string(reason)));
76*d9f75844SAndroid Build Coastguard Worker }
77*d9f75844SAndroid Build Coastguard Worker 
TurnServer(webrtc::TaskQueueBase * thread)78*d9f75844SAndroid Build Coastguard Worker TurnServer::TurnServer(webrtc::TaskQueueBase* thread)
79*d9f75844SAndroid Build Coastguard Worker     : thread_(thread),
80*d9f75844SAndroid Build Coastguard Worker       nonce_key_(rtc::CreateRandomString(kNonceKeySize)),
81*d9f75844SAndroid Build Coastguard Worker       auth_hook_(NULL),
82*d9f75844SAndroid Build Coastguard Worker       redirect_hook_(NULL),
83*d9f75844SAndroid Build Coastguard Worker       enable_otu_nonce_(false) {}
84*d9f75844SAndroid Build Coastguard Worker 
~TurnServer()85*d9f75844SAndroid Build Coastguard Worker TurnServer::~TurnServer() {
86*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
87*d9f75844SAndroid Build Coastguard Worker   for (InternalSocketMap::iterator it = server_sockets_.begin();
88*d9f75844SAndroid Build Coastguard Worker        it != server_sockets_.end(); ++it) {
89*d9f75844SAndroid Build Coastguard Worker     rtc::AsyncPacketSocket* socket = it->first;
90*d9f75844SAndroid Build Coastguard Worker     delete socket;
91*d9f75844SAndroid Build Coastguard Worker   }
92*d9f75844SAndroid Build Coastguard Worker 
93*d9f75844SAndroid Build Coastguard Worker   for (ServerSocketMap::iterator it = server_listen_sockets_.begin();
94*d9f75844SAndroid Build Coastguard Worker        it != server_listen_sockets_.end(); ++it) {
95*d9f75844SAndroid Build Coastguard Worker     rtc::Socket* socket = it->first;
96*d9f75844SAndroid Build Coastguard Worker     delete socket;
97*d9f75844SAndroid Build Coastguard Worker   }
98*d9f75844SAndroid Build Coastguard Worker }
99*d9f75844SAndroid Build Coastguard Worker 
AddInternalSocket(rtc::AsyncPacketSocket * socket,ProtocolType proto)100*d9f75844SAndroid Build Coastguard Worker void TurnServer::AddInternalSocket(rtc::AsyncPacketSocket* socket,
101*d9f75844SAndroid Build Coastguard Worker                                    ProtocolType proto) {
102*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
103*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(server_sockets_.end() == server_sockets_.find(socket));
104*d9f75844SAndroid Build Coastguard Worker   server_sockets_[socket] = proto;
105*d9f75844SAndroid Build Coastguard Worker   socket->SignalReadPacket.connect(this, &TurnServer::OnInternalPacket);
106*d9f75844SAndroid Build Coastguard Worker }
107*d9f75844SAndroid Build Coastguard Worker 
AddInternalServerSocket(rtc::Socket * socket,ProtocolType proto,std::unique_ptr<rtc::SSLAdapterFactory> ssl_adapter_factory)108*d9f75844SAndroid Build Coastguard Worker void TurnServer::AddInternalServerSocket(
109*d9f75844SAndroid Build Coastguard Worker     rtc::Socket* socket,
110*d9f75844SAndroid Build Coastguard Worker     ProtocolType proto,
111*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<rtc::SSLAdapterFactory> ssl_adapter_factory) {
112*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
113*d9f75844SAndroid Build Coastguard Worker 
114*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(server_listen_sockets_.end() ==
115*d9f75844SAndroid Build Coastguard Worker              server_listen_sockets_.find(socket));
116*d9f75844SAndroid Build Coastguard Worker   server_listen_sockets_[socket] = {proto, std::move(ssl_adapter_factory)};
117*d9f75844SAndroid Build Coastguard Worker   socket->SignalReadEvent.connect(this, &TurnServer::OnNewInternalConnection);
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker 
SetExternalSocketFactory(rtc::PacketSocketFactory * factory,const rtc::SocketAddress & external_addr)120*d9f75844SAndroid Build Coastguard Worker void TurnServer::SetExternalSocketFactory(
121*d9f75844SAndroid Build Coastguard Worker     rtc::PacketSocketFactory* factory,
122*d9f75844SAndroid Build Coastguard Worker     const rtc::SocketAddress& external_addr) {
123*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
124*d9f75844SAndroid Build Coastguard Worker   external_socket_factory_.reset(factory);
125*d9f75844SAndroid Build Coastguard Worker   external_addr_ = external_addr;
126*d9f75844SAndroid Build Coastguard Worker }
127*d9f75844SAndroid Build Coastguard Worker 
OnNewInternalConnection(rtc::Socket * socket)128*d9f75844SAndroid Build Coastguard Worker void TurnServer::OnNewInternalConnection(rtc::Socket* socket) {
129*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
130*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(server_listen_sockets_.find(socket) !=
131*d9f75844SAndroid Build Coastguard Worker              server_listen_sockets_.end());
132*d9f75844SAndroid Build Coastguard Worker   AcceptConnection(socket);
133*d9f75844SAndroid Build Coastguard Worker }
134*d9f75844SAndroid Build Coastguard Worker 
AcceptConnection(rtc::Socket * server_socket)135*d9f75844SAndroid Build Coastguard Worker void TurnServer::AcceptConnection(rtc::Socket* server_socket) {
136*d9f75844SAndroid Build Coastguard Worker   // Check if someone is trying to connect to us.
137*d9f75844SAndroid Build Coastguard Worker   rtc::SocketAddress accept_addr;
138*d9f75844SAndroid Build Coastguard Worker   rtc::Socket* accepted_socket = server_socket->Accept(&accept_addr);
139*d9f75844SAndroid Build Coastguard Worker   if (accepted_socket != NULL) {
140*d9f75844SAndroid Build Coastguard Worker     const ServerSocketInfo& info = server_listen_sockets_[server_socket];
141*d9f75844SAndroid Build Coastguard Worker     if (info.ssl_adapter_factory) {
142*d9f75844SAndroid Build Coastguard Worker       rtc::SSLAdapter* ssl_adapter =
143*d9f75844SAndroid Build Coastguard Worker           info.ssl_adapter_factory->CreateAdapter(accepted_socket);
144*d9f75844SAndroid Build Coastguard Worker       ssl_adapter->StartSSL("");
145*d9f75844SAndroid Build Coastguard Worker       accepted_socket = ssl_adapter;
146*d9f75844SAndroid Build Coastguard Worker     }
147*d9f75844SAndroid Build Coastguard Worker     cricket::AsyncStunTCPSocket* tcp_socket =
148*d9f75844SAndroid Build Coastguard Worker         new cricket::AsyncStunTCPSocket(accepted_socket);
149*d9f75844SAndroid Build Coastguard Worker 
150*d9f75844SAndroid Build Coastguard Worker     tcp_socket->SubscribeClose(this,
151*d9f75844SAndroid Build Coastguard Worker                                [this](rtc::AsyncPacketSocket* s, int err) {
152*d9f75844SAndroid Build Coastguard Worker                                  OnInternalSocketClose(s, err);
153*d9f75844SAndroid Build Coastguard Worker                                });
154*d9f75844SAndroid Build Coastguard Worker     // Finally add the socket so it can start communicating with the client.
155*d9f75844SAndroid Build Coastguard Worker     AddInternalSocket(tcp_socket, info.proto);
156*d9f75844SAndroid Build Coastguard Worker   }
157*d9f75844SAndroid Build Coastguard Worker }
158*d9f75844SAndroid Build Coastguard Worker 
OnInternalSocketClose(rtc::AsyncPacketSocket * socket,int err)159*d9f75844SAndroid Build Coastguard Worker void TurnServer::OnInternalSocketClose(rtc::AsyncPacketSocket* socket,
160*d9f75844SAndroid Build Coastguard Worker                                        int err) {
161*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
162*d9f75844SAndroid Build Coastguard Worker   DestroyInternalSocket(socket);
163*d9f75844SAndroid Build Coastguard Worker }
164*d9f75844SAndroid Build Coastguard Worker 
OnInternalPacket(rtc::AsyncPacketSocket * socket,const char * data,size_t size,const rtc::SocketAddress & addr,const int64_t &)165*d9f75844SAndroid Build Coastguard Worker void TurnServer::OnInternalPacket(rtc::AsyncPacketSocket* socket,
166*d9f75844SAndroid Build Coastguard Worker                                   const char* data,
167*d9f75844SAndroid Build Coastguard Worker                                   size_t size,
168*d9f75844SAndroid Build Coastguard Worker                                   const rtc::SocketAddress& addr,
169*d9f75844SAndroid Build Coastguard Worker                                   const int64_t& /* packet_time_us */) {
170*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
171*d9f75844SAndroid Build Coastguard Worker   // Fail if the packet is too small to even contain a channel header.
172*d9f75844SAndroid Build Coastguard Worker   if (size < TURN_CHANNEL_HEADER_SIZE) {
173*d9f75844SAndroid Build Coastguard Worker     return;
174*d9f75844SAndroid Build Coastguard Worker   }
175*d9f75844SAndroid Build Coastguard Worker   InternalSocketMap::iterator iter = server_sockets_.find(socket);
176*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(iter != server_sockets_.end());
177*d9f75844SAndroid Build Coastguard Worker   TurnServerConnection conn(addr, iter->second, socket);
178*d9f75844SAndroid Build Coastguard Worker   uint16_t msg_type = rtc::GetBE16(data);
179*d9f75844SAndroid Build Coastguard Worker   if (!IsTurnChannelData(msg_type)) {
180*d9f75844SAndroid Build Coastguard Worker     // This is a STUN message.
181*d9f75844SAndroid Build Coastguard Worker     HandleStunMessage(&conn, data, size);
182*d9f75844SAndroid Build Coastguard Worker   } else {
183*d9f75844SAndroid Build Coastguard Worker     // This is a channel message; let the allocation handle it.
184*d9f75844SAndroid Build Coastguard Worker     TurnServerAllocation* allocation = FindAllocation(&conn);
185*d9f75844SAndroid Build Coastguard Worker     if (allocation) {
186*d9f75844SAndroid Build Coastguard Worker       allocation->HandleChannelData(data, size);
187*d9f75844SAndroid Build Coastguard Worker     }
188*d9f75844SAndroid Build Coastguard Worker     if (stun_message_observer_ != nullptr) {
189*d9f75844SAndroid Build Coastguard Worker       stun_message_observer_->ReceivedChannelData(data, size);
190*d9f75844SAndroid Build Coastguard Worker     }
191*d9f75844SAndroid Build Coastguard Worker   }
192*d9f75844SAndroid Build Coastguard Worker }
193*d9f75844SAndroid Build Coastguard Worker 
HandleStunMessage(TurnServerConnection * conn,const char * data,size_t size)194*d9f75844SAndroid Build Coastguard Worker void TurnServer::HandleStunMessage(TurnServerConnection* conn,
195*d9f75844SAndroid Build Coastguard Worker                                    const char* data,
196*d9f75844SAndroid Build Coastguard Worker                                    size_t size) {
197*d9f75844SAndroid Build Coastguard Worker   TurnMessage msg;
198*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferReader buf(data, size);
199*d9f75844SAndroid Build Coastguard Worker   if (!msg.Read(&buf) || (buf.Length() > 0)) {
200*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Received invalid STUN message";
201*d9f75844SAndroid Build Coastguard Worker     return;
202*d9f75844SAndroid Build Coastguard Worker   }
203*d9f75844SAndroid Build Coastguard Worker 
204*d9f75844SAndroid Build Coastguard Worker   if (stun_message_observer_ != nullptr) {
205*d9f75844SAndroid Build Coastguard Worker     stun_message_observer_->ReceivedMessage(&msg);
206*d9f75844SAndroid Build Coastguard Worker   }
207*d9f75844SAndroid Build Coastguard Worker 
208*d9f75844SAndroid Build Coastguard Worker   // If it's a STUN binding request, handle that specially.
209*d9f75844SAndroid Build Coastguard Worker   if (msg.type() == STUN_BINDING_REQUEST) {
210*d9f75844SAndroid Build Coastguard Worker     HandleBindingRequest(conn, &msg);
211*d9f75844SAndroid Build Coastguard Worker     return;
212*d9f75844SAndroid Build Coastguard Worker   }
213*d9f75844SAndroid Build Coastguard Worker 
214*d9f75844SAndroid Build Coastguard Worker   if (redirect_hook_ != NULL && msg.type() == STUN_ALLOCATE_REQUEST) {
215*d9f75844SAndroid Build Coastguard Worker     rtc::SocketAddress address;
216*d9f75844SAndroid Build Coastguard Worker     if (redirect_hook_->ShouldRedirect(conn->src(), &address)) {
217*d9f75844SAndroid Build Coastguard Worker       SendErrorResponseWithAlternateServer(conn, &msg, address);
218*d9f75844SAndroid Build Coastguard Worker       return;
219*d9f75844SAndroid Build Coastguard Worker     }
220*d9f75844SAndroid Build Coastguard Worker   }
221*d9f75844SAndroid Build Coastguard Worker 
222*d9f75844SAndroid Build Coastguard Worker   // Look up the key that we'll use to validate the M-I. If we have an
223*d9f75844SAndroid Build Coastguard Worker   // existing allocation, the key will already be cached.
224*d9f75844SAndroid Build Coastguard Worker   TurnServerAllocation* allocation = FindAllocation(conn);
225*d9f75844SAndroid Build Coastguard Worker   std::string key;
226*d9f75844SAndroid Build Coastguard Worker   if (!allocation) {
227*d9f75844SAndroid Build Coastguard Worker     GetKey(&msg, &key);
228*d9f75844SAndroid Build Coastguard Worker   } else {
229*d9f75844SAndroid Build Coastguard Worker     key = allocation->key();
230*d9f75844SAndroid Build Coastguard Worker   }
231*d9f75844SAndroid Build Coastguard Worker 
232*d9f75844SAndroid Build Coastguard Worker   // Ensure the message is authorized; only needed for requests.
233*d9f75844SAndroid Build Coastguard Worker   if (IsStunRequestType(msg.type())) {
234*d9f75844SAndroid Build Coastguard Worker     if (!CheckAuthorization(conn, &msg, data, size, key)) {
235*d9f75844SAndroid Build Coastguard Worker       return;
236*d9f75844SAndroid Build Coastguard Worker     }
237*d9f75844SAndroid Build Coastguard Worker   }
238*d9f75844SAndroid Build Coastguard Worker 
239*d9f75844SAndroid Build Coastguard Worker   if (!allocation && msg.type() == STUN_ALLOCATE_REQUEST) {
240*d9f75844SAndroid Build Coastguard Worker     HandleAllocateRequest(conn, &msg, key);
241*d9f75844SAndroid Build Coastguard Worker   } else if (allocation &&
242*d9f75844SAndroid Build Coastguard Worker              (msg.type() != STUN_ALLOCATE_REQUEST ||
243*d9f75844SAndroid Build Coastguard Worker               msg.transaction_id() == allocation->transaction_id())) {
244*d9f75844SAndroid Build Coastguard Worker     // This is a non-allocate request, or a retransmit of an allocate.
245*d9f75844SAndroid Build Coastguard Worker     // Check that the username matches the previous username used.
246*d9f75844SAndroid Build Coastguard Worker     if (IsStunRequestType(msg.type()) &&
247*d9f75844SAndroid Build Coastguard Worker         msg.GetByteString(STUN_ATTR_USERNAME)->string_view() !=
248*d9f75844SAndroid Build Coastguard Worker             allocation->username()) {
249*d9f75844SAndroid Build Coastguard Worker       SendErrorResponse(conn, &msg, STUN_ERROR_WRONG_CREDENTIALS,
250*d9f75844SAndroid Build Coastguard Worker                         STUN_ERROR_REASON_WRONG_CREDENTIALS);
251*d9f75844SAndroid Build Coastguard Worker       return;
252*d9f75844SAndroid Build Coastguard Worker     }
253*d9f75844SAndroid Build Coastguard Worker     allocation->HandleTurnMessage(&msg);
254*d9f75844SAndroid Build Coastguard Worker   } else {
255*d9f75844SAndroid Build Coastguard Worker     // Allocation mismatch.
256*d9f75844SAndroid Build Coastguard Worker     SendErrorResponse(conn, &msg, STUN_ERROR_ALLOCATION_MISMATCH,
257*d9f75844SAndroid Build Coastguard Worker                       STUN_ERROR_REASON_ALLOCATION_MISMATCH);
258*d9f75844SAndroid Build Coastguard Worker   }
259*d9f75844SAndroid Build Coastguard Worker }
260*d9f75844SAndroid Build Coastguard Worker 
GetKey(const StunMessage * msg,std::string * key)261*d9f75844SAndroid Build Coastguard Worker bool TurnServer::GetKey(const StunMessage* msg, std::string* key) {
262*d9f75844SAndroid Build Coastguard Worker   const StunByteStringAttribute* username_attr =
263*d9f75844SAndroid Build Coastguard Worker       msg->GetByteString(STUN_ATTR_USERNAME);
264*d9f75844SAndroid Build Coastguard Worker   if (!username_attr) {
265*d9f75844SAndroid Build Coastguard Worker     return false;
266*d9f75844SAndroid Build Coastguard Worker   }
267*d9f75844SAndroid Build Coastguard Worker 
268*d9f75844SAndroid Build Coastguard Worker   return (auth_hook_ != NULL &&
269*d9f75844SAndroid Build Coastguard Worker           auth_hook_->GetKey(std::string(username_attr->string_view()), realm_,
270*d9f75844SAndroid Build Coastguard Worker                              key));
271*d9f75844SAndroid Build Coastguard Worker }
272*d9f75844SAndroid Build Coastguard Worker 
CheckAuthorization(TurnServerConnection * conn,StunMessage * msg,const char * data,size_t size,absl::string_view key)273*d9f75844SAndroid Build Coastguard Worker bool TurnServer::CheckAuthorization(TurnServerConnection* conn,
274*d9f75844SAndroid Build Coastguard Worker                                     StunMessage* msg,
275*d9f75844SAndroid Build Coastguard Worker                                     const char* data,
276*d9f75844SAndroid Build Coastguard Worker                                     size_t size,
277*d9f75844SAndroid Build Coastguard Worker                                     absl::string_view key) {
278*d9f75844SAndroid Build Coastguard Worker   // RFC 5389, 10.2.2.
279*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(IsStunRequestType(msg->type()));
280*d9f75844SAndroid Build Coastguard Worker   const StunByteStringAttribute* mi_attr =
281*d9f75844SAndroid Build Coastguard Worker       msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
282*d9f75844SAndroid Build Coastguard Worker   const StunByteStringAttribute* username_attr =
283*d9f75844SAndroid Build Coastguard Worker       msg->GetByteString(STUN_ATTR_USERNAME);
284*d9f75844SAndroid Build Coastguard Worker   const StunByteStringAttribute* realm_attr =
285*d9f75844SAndroid Build Coastguard Worker       msg->GetByteString(STUN_ATTR_REALM);
286*d9f75844SAndroid Build Coastguard Worker   const StunByteStringAttribute* nonce_attr =
287*d9f75844SAndroid Build Coastguard Worker       msg->GetByteString(STUN_ATTR_NONCE);
288*d9f75844SAndroid Build Coastguard Worker 
289*d9f75844SAndroid Build Coastguard Worker   // Fail if no MESSAGE_INTEGRITY.
290*d9f75844SAndroid Build Coastguard Worker   if (!mi_attr) {
291*d9f75844SAndroid Build Coastguard Worker     SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_UNAUTHORIZED,
292*d9f75844SAndroid Build Coastguard Worker                                        STUN_ERROR_REASON_UNAUTHORIZED);
293*d9f75844SAndroid Build Coastguard Worker     return false;
294*d9f75844SAndroid Build Coastguard Worker   }
295*d9f75844SAndroid Build Coastguard Worker 
296*d9f75844SAndroid Build Coastguard Worker   // Fail if there is MESSAGE_INTEGRITY but no username, nonce, or realm.
297*d9f75844SAndroid Build Coastguard Worker   if (!username_attr || !realm_attr || !nonce_attr) {
298*d9f75844SAndroid Build Coastguard Worker     SendErrorResponse(conn, msg, STUN_ERROR_BAD_REQUEST,
299*d9f75844SAndroid Build Coastguard Worker                       STUN_ERROR_REASON_BAD_REQUEST);
300*d9f75844SAndroid Build Coastguard Worker     return false;
301*d9f75844SAndroid Build Coastguard Worker   }
302*d9f75844SAndroid Build Coastguard Worker 
303*d9f75844SAndroid Build Coastguard Worker   // Fail if bad nonce.
304*d9f75844SAndroid Build Coastguard Worker   if (!ValidateNonce(nonce_attr->string_view())) {
305*d9f75844SAndroid Build Coastguard Worker     SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE,
306*d9f75844SAndroid Build Coastguard Worker                                        STUN_ERROR_REASON_STALE_NONCE);
307*d9f75844SAndroid Build Coastguard Worker     return false;
308*d9f75844SAndroid Build Coastguard Worker   }
309*d9f75844SAndroid Build Coastguard Worker 
310*d9f75844SAndroid Build Coastguard Worker   // Fail if bad MESSAGE_INTEGRITY.
311*d9f75844SAndroid Build Coastguard Worker   if (key.empty() || msg->ValidateMessageIntegrity(std::string(key)) !=
312*d9f75844SAndroid Build Coastguard Worker                          StunMessage::IntegrityStatus::kIntegrityOk) {
313*d9f75844SAndroid Build Coastguard Worker     SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_UNAUTHORIZED,
314*d9f75844SAndroid Build Coastguard Worker                                        STUN_ERROR_REASON_UNAUTHORIZED);
315*d9f75844SAndroid Build Coastguard Worker     return false;
316*d9f75844SAndroid Build Coastguard Worker   }
317*d9f75844SAndroid Build Coastguard Worker 
318*d9f75844SAndroid Build Coastguard Worker   // Fail if one-time-use nonce feature is enabled.
319*d9f75844SAndroid Build Coastguard Worker   TurnServerAllocation* allocation = FindAllocation(conn);
320*d9f75844SAndroid Build Coastguard Worker   if (enable_otu_nonce_ && allocation &&
321*d9f75844SAndroid Build Coastguard Worker       allocation->last_nonce() == nonce_attr->string_view()) {
322*d9f75844SAndroid Build Coastguard Worker     SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE,
323*d9f75844SAndroid Build Coastguard Worker                                        STUN_ERROR_REASON_STALE_NONCE);
324*d9f75844SAndroid Build Coastguard Worker     return false;
325*d9f75844SAndroid Build Coastguard Worker   }
326*d9f75844SAndroid Build Coastguard Worker 
327*d9f75844SAndroid Build Coastguard Worker   if (allocation) {
328*d9f75844SAndroid Build Coastguard Worker     allocation->set_last_nonce(nonce_attr->string_view());
329*d9f75844SAndroid Build Coastguard Worker   }
330*d9f75844SAndroid Build Coastguard Worker   // Success.
331*d9f75844SAndroid Build Coastguard Worker   return true;
332*d9f75844SAndroid Build Coastguard Worker }
333*d9f75844SAndroid Build Coastguard Worker 
HandleBindingRequest(TurnServerConnection * conn,const StunMessage * req)334*d9f75844SAndroid Build Coastguard Worker void TurnServer::HandleBindingRequest(TurnServerConnection* conn,
335*d9f75844SAndroid Build Coastguard Worker                                       const StunMessage* req) {
336*d9f75844SAndroid Build Coastguard Worker   StunMessage response(GetStunSuccessResponseTypeOrZero(*req),
337*d9f75844SAndroid Build Coastguard Worker                        req->transaction_id());
338*d9f75844SAndroid Build Coastguard Worker   // Tell the user the address that we received their request from.
339*d9f75844SAndroid Build Coastguard Worker   auto mapped_addr_attr = std::make_unique<StunXorAddressAttribute>(
340*d9f75844SAndroid Build Coastguard Worker       STUN_ATTR_XOR_MAPPED_ADDRESS, conn->src());
341*d9f75844SAndroid Build Coastguard Worker   response.AddAttribute(std::move(mapped_addr_attr));
342*d9f75844SAndroid Build Coastguard Worker 
343*d9f75844SAndroid Build Coastguard Worker   SendStun(conn, &response);
344*d9f75844SAndroid Build Coastguard Worker }
345*d9f75844SAndroid Build Coastguard Worker 
HandleAllocateRequest(TurnServerConnection * conn,const TurnMessage * msg,absl::string_view key)346*d9f75844SAndroid Build Coastguard Worker void TurnServer::HandleAllocateRequest(TurnServerConnection* conn,
347*d9f75844SAndroid Build Coastguard Worker                                        const TurnMessage* msg,
348*d9f75844SAndroid Build Coastguard Worker                                        absl::string_view key) {
349*d9f75844SAndroid Build Coastguard Worker   // Check the parameters in the request.
350*d9f75844SAndroid Build Coastguard Worker   const StunUInt32Attribute* transport_attr =
351*d9f75844SAndroid Build Coastguard Worker       msg->GetUInt32(STUN_ATTR_REQUESTED_TRANSPORT);
352*d9f75844SAndroid Build Coastguard Worker   if (!transport_attr) {
353*d9f75844SAndroid Build Coastguard Worker     SendErrorResponse(conn, msg, STUN_ERROR_BAD_REQUEST,
354*d9f75844SAndroid Build Coastguard Worker                       STUN_ERROR_REASON_BAD_REQUEST);
355*d9f75844SAndroid Build Coastguard Worker     return;
356*d9f75844SAndroid Build Coastguard Worker   }
357*d9f75844SAndroid Build Coastguard Worker 
358*d9f75844SAndroid Build Coastguard Worker   // Only UDP is supported right now.
359*d9f75844SAndroid Build Coastguard Worker   int proto = transport_attr->value() >> 24;
360*d9f75844SAndroid Build Coastguard Worker   if (proto != IPPROTO_UDP) {
361*d9f75844SAndroid Build Coastguard Worker     SendErrorResponse(conn, msg, STUN_ERROR_UNSUPPORTED_PROTOCOL,
362*d9f75844SAndroid Build Coastguard Worker                       STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL);
363*d9f75844SAndroid Build Coastguard Worker     return;
364*d9f75844SAndroid Build Coastguard Worker   }
365*d9f75844SAndroid Build Coastguard Worker 
366*d9f75844SAndroid Build Coastguard Worker   // Create the allocation and let it send the success response.
367*d9f75844SAndroid Build Coastguard Worker   // If the actual socket allocation fails, send an internal error.
368*d9f75844SAndroid Build Coastguard Worker   TurnServerAllocation* alloc = CreateAllocation(conn, proto, key);
369*d9f75844SAndroid Build Coastguard Worker   if (alloc) {
370*d9f75844SAndroid Build Coastguard Worker     alloc->HandleTurnMessage(msg);
371*d9f75844SAndroid Build Coastguard Worker   } else {
372*d9f75844SAndroid Build Coastguard Worker     SendErrorResponse(conn, msg, STUN_ERROR_SERVER_ERROR,
373*d9f75844SAndroid Build Coastguard Worker                       "Failed to allocate socket");
374*d9f75844SAndroid Build Coastguard Worker   }
375*d9f75844SAndroid Build Coastguard Worker }
376*d9f75844SAndroid Build Coastguard Worker 
GenerateNonce(int64_t now) const377*d9f75844SAndroid Build Coastguard Worker std::string TurnServer::GenerateNonce(int64_t now) const {
378*d9f75844SAndroid Build Coastguard Worker   // Generate a nonce of the form hex(now + HMAC-MD5(nonce_key_, now))
379*d9f75844SAndroid Build Coastguard Worker   std::string input(reinterpret_cast<const char*>(&now), sizeof(now));
380*d9f75844SAndroid Build Coastguard Worker   std::string nonce = rtc::hex_encode(input);
381*d9f75844SAndroid Build Coastguard Worker   nonce += rtc::ComputeHmac(rtc::DIGEST_MD5, nonce_key_, input);
382*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(nonce.size() == kNonceSize);
383*d9f75844SAndroid Build Coastguard Worker 
384*d9f75844SAndroid Build Coastguard Worker   return nonce;
385*d9f75844SAndroid Build Coastguard Worker }
386*d9f75844SAndroid Build Coastguard Worker 
ValidateNonce(absl::string_view nonce) const387*d9f75844SAndroid Build Coastguard Worker bool TurnServer::ValidateNonce(absl::string_view nonce) const {
388*d9f75844SAndroid Build Coastguard Worker   // Check the size.
389*d9f75844SAndroid Build Coastguard Worker   if (nonce.size() != kNonceSize) {
390*d9f75844SAndroid Build Coastguard Worker     return false;
391*d9f75844SAndroid Build Coastguard Worker   }
392*d9f75844SAndroid Build Coastguard Worker 
393*d9f75844SAndroid Build Coastguard Worker   // Decode the timestamp.
394*d9f75844SAndroid Build Coastguard Worker   int64_t then;
395*d9f75844SAndroid Build Coastguard Worker   char* p = reinterpret_cast<char*>(&then);
396*d9f75844SAndroid Build Coastguard Worker   size_t len = rtc::hex_decode(rtc::ArrayView<char>(p, sizeof(then)),
397*d9f75844SAndroid Build Coastguard Worker                                nonce.substr(0, sizeof(then) * 2));
398*d9f75844SAndroid Build Coastguard Worker   if (len != sizeof(then)) {
399*d9f75844SAndroid Build Coastguard Worker     return false;
400*d9f75844SAndroid Build Coastguard Worker   }
401*d9f75844SAndroid Build Coastguard Worker 
402*d9f75844SAndroid Build Coastguard Worker   // Verify the HMAC.
403*d9f75844SAndroid Build Coastguard Worker   if (nonce.substr(sizeof(then) * 2) !=
404*d9f75844SAndroid Build Coastguard Worker       rtc::ComputeHmac(rtc::DIGEST_MD5, nonce_key_,
405*d9f75844SAndroid Build Coastguard Worker                        std::string(p, sizeof(then)))) {
406*d9f75844SAndroid Build Coastguard Worker     return false;
407*d9f75844SAndroid Build Coastguard Worker   }
408*d9f75844SAndroid Build Coastguard Worker 
409*d9f75844SAndroid Build Coastguard Worker   // Validate the timestamp.
410*d9f75844SAndroid Build Coastguard Worker   return TimeDelta::Millis(rtc::TimeMillis() - then) < kNonceTimeout;
411*d9f75844SAndroid Build Coastguard Worker }
412*d9f75844SAndroid Build Coastguard Worker 
FindAllocation(TurnServerConnection * conn)413*d9f75844SAndroid Build Coastguard Worker TurnServerAllocation* TurnServer::FindAllocation(TurnServerConnection* conn) {
414*d9f75844SAndroid Build Coastguard Worker   AllocationMap::const_iterator it = allocations_.find(*conn);
415*d9f75844SAndroid Build Coastguard Worker   return (it != allocations_.end()) ? it->second.get() : nullptr;
416*d9f75844SAndroid Build Coastguard Worker }
417*d9f75844SAndroid Build Coastguard Worker 
CreateAllocation(TurnServerConnection * conn,int proto,absl::string_view key)418*d9f75844SAndroid Build Coastguard Worker TurnServerAllocation* TurnServer::CreateAllocation(TurnServerConnection* conn,
419*d9f75844SAndroid Build Coastguard Worker                                                    int proto,
420*d9f75844SAndroid Build Coastguard Worker                                                    absl::string_view key) {
421*d9f75844SAndroid Build Coastguard Worker   rtc::AsyncPacketSocket* external_socket =
422*d9f75844SAndroid Build Coastguard Worker       (external_socket_factory_)
423*d9f75844SAndroid Build Coastguard Worker           ? external_socket_factory_->CreateUdpSocket(external_addr_, 0, 0)
424*d9f75844SAndroid Build Coastguard Worker           : NULL;
425*d9f75844SAndroid Build Coastguard Worker   if (!external_socket) {
426*d9f75844SAndroid Build Coastguard Worker     return NULL;
427*d9f75844SAndroid Build Coastguard Worker   }
428*d9f75844SAndroid Build Coastguard Worker 
429*d9f75844SAndroid Build Coastguard Worker   // The Allocation takes ownership of the socket.
430*d9f75844SAndroid Build Coastguard Worker   TurnServerAllocation* allocation =
431*d9f75844SAndroid Build Coastguard Worker       new TurnServerAllocation(this, thread_, *conn, external_socket, key);
432*d9f75844SAndroid Build Coastguard Worker   allocations_[*conn].reset(allocation);
433*d9f75844SAndroid Build Coastguard Worker   return allocation;
434*d9f75844SAndroid Build Coastguard Worker }
435*d9f75844SAndroid Build Coastguard Worker 
SendErrorResponse(TurnServerConnection * conn,const StunMessage * req,int code,absl::string_view reason)436*d9f75844SAndroid Build Coastguard Worker void TurnServer::SendErrorResponse(TurnServerConnection* conn,
437*d9f75844SAndroid Build Coastguard Worker                                    const StunMessage* req,
438*d9f75844SAndroid Build Coastguard Worker                                    int code,
439*d9f75844SAndroid Build Coastguard Worker                                    absl::string_view reason) {
440*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
441*d9f75844SAndroid Build Coastguard Worker   TurnMessage resp(GetStunErrorResponseTypeOrZero(*req), req->transaction_id());
442*d9f75844SAndroid Build Coastguard Worker   InitErrorResponse(code, reason, &resp);
443*d9f75844SAndroid Build Coastguard Worker 
444*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "Sending error response, type=" << resp.type()
445*d9f75844SAndroid Build Coastguard Worker                    << ", code=" << code << ", reason=" << reason;
446*d9f75844SAndroid Build Coastguard Worker   SendStun(conn, &resp);
447*d9f75844SAndroid Build Coastguard Worker }
448*d9f75844SAndroid Build Coastguard Worker 
SendErrorResponseWithRealmAndNonce(TurnServerConnection * conn,const StunMessage * msg,int code,absl::string_view reason)449*d9f75844SAndroid Build Coastguard Worker void TurnServer::SendErrorResponseWithRealmAndNonce(TurnServerConnection* conn,
450*d9f75844SAndroid Build Coastguard Worker                                                     const StunMessage* msg,
451*d9f75844SAndroid Build Coastguard Worker                                                     int code,
452*d9f75844SAndroid Build Coastguard Worker                                                     absl::string_view reason) {
453*d9f75844SAndroid Build Coastguard Worker   TurnMessage resp(GetStunErrorResponseTypeOrZero(*msg), msg->transaction_id());
454*d9f75844SAndroid Build Coastguard Worker   InitErrorResponse(code, reason, &resp);
455*d9f75844SAndroid Build Coastguard Worker 
456*d9f75844SAndroid Build Coastguard Worker   int64_t timestamp = rtc::TimeMillis();
457*d9f75844SAndroid Build Coastguard Worker   if (ts_for_next_nonce_) {
458*d9f75844SAndroid Build Coastguard Worker     timestamp = ts_for_next_nonce_;
459*d9f75844SAndroid Build Coastguard Worker     ts_for_next_nonce_ = 0;
460*d9f75844SAndroid Build Coastguard Worker   }
461*d9f75844SAndroid Build Coastguard Worker   resp.AddAttribute(std::make_unique<StunByteStringAttribute>(
462*d9f75844SAndroid Build Coastguard Worker       STUN_ATTR_NONCE, GenerateNonce(timestamp)));
463*d9f75844SAndroid Build Coastguard Worker   resp.AddAttribute(
464*d9f75844SAndroid Build Coastguard Worker       std::make_unique<StunByteStringAttribute>(STUN_ATTR_REALM, realm_));
465*d9f75844SAndroid Build Coastguard Worker   SendStun(conn, &resp);
466*d9f75844SAndroid Build Coastguard Worker }
467*d9f75844SAndroid Build Coastguard Worker 
SendErrorResponseWithAlternateServer(TurnServerConnection * conn,const StunMessage * msg,const rtc::SocketAddress & addr)468*d9f75844SAndroid Build Coastguard Worker void TurnServer::SendErrorResponseWithAlternateServer(
469*d9f75844SAndroid Build Coastguard Worker     TurnServerConnection* conn,
470*d9f75844SAndroid Build Coastguard Worker     const StunMessage* msg,
471*d9f75844SAndroid Build Coastguard Worker     const rtc::SocketAddress& addr) {
472*d9f75844SAndroid Build Coastguard Worker   TurnMessage resp(GetStunErrorResponseTypeOrZero(*msg), msg->transaction_id());
473*d9f75844SAndroid Build Coastguard Worker   InitErrorResponse(STUN_ERROR_TRY_ALTERNATE,
474*d9f75844SAndroid Build Coastguard Worker                     STUN_ERROR_REASON_TRY_ALTERNATE_SERVER, &resp);
475*d9f75844SAndroid Build Coastguard Worker   resp.AddAttribute(
476*d9f75844SAndroid Build Coastguard Worker       std::make_unique<StunAddressAttribute>(STUN_ATTR_ALTERNATE_SERVER, addr));
477*d9f75844SAndroid Build Coastguard Worker   SendStun(conn, &resp);
478*d9f75844SAndroid Build Coastguard Worker }
479*d9f75844SAndroid Build Coastguard Worker 
SendStun(TurnServerConnection * conn,StunMessage * msg)480*d9f75844SAndroid Build Coastguard Worker void TurnServer::SendStun(TurnServerConnection* conn, StunMessage* msg) {
481*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
482*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferWriter buf;
483*d9f75844SAndroid Build Coastguard Worker   // Add a SOFTWARE attribute if one is set.
484*d9f75844SAndroid Build Coastguard Worker   if (!software_.empty()) {
485*d9f75844SAndroid Build Coastguard Worker     msg->AddAttribute(std::make_unique<StunByteStringAttribute>(
486*d9f75844SAndroid Build Coastguard Worker         STUN_ATTR_SOFTWARE, software_));
487*d9f75844SAndroid Build Coastguard Worker   }
488*d9f75844SAndroid Build Coastguard Worker   msg->Write(&buf);
489*d9f75844SAndroid Build Coastguard Worker   Send(conn, buf);
490*d9f75844SAndroid Build Coastguard Worker }
491*d9f75844SAndroid Build Coastguard Worker 
Send(TurnServerConnection * conn,const rtc::ByteBufferWriter & buf)492*d9f75844SAndroid Build Coastguard Worker void TurnServer::Send(TurnServerConnection* conn,
493*d9f75844SAndroid Build Coastguard Worker                       const rtc::ByteBufferWriter& buf) {
494*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
495*d9f75844SAndroid Build Coastguard Worker   rtc::PacketOptions options;
496*d9f75844SAndroid Build Coastguard Worker   conn->socket()->SendTo(buf.Data(), buf.Length(), conn->src(), options);
497*d9f75844SAndroid Build Coastguard Worker }
498*d9f75844SAndroid Build Coastguard Worker 
DestroyAllocation(TurnServerAllocation * allocation)499*d9f75844SAndroid Build Coastguard Worker void TurnServer::DestroyAllocation(TurnServerAllocation* allocation) {
500*d9f75844SAndroid Build Coastguard Worker   // Removing the internal socket if the connection is not udp.
501*d9f75844SAndroid Build Coastguard Worker   rtc::AsyncPacketSocket* socket = allocation->conn()->socket();
502*d9f75844SAndroid Build Coastguard Worker   InternalSocketMap::iterator iter = server_sockets_.find(socket);
503*d9f75844SAndroid Build Coastguard Worker   // Skip if the socket serving this allocation is UDP, as this will be shared
504*d9f75844SAndroid Build Coastguard Worker   // by all allocations.
505*d9f75844SAndroid Build Coastguard Worker   // Note: We may not find a socket if it's a TCP socket that was closed, and
506*d9f75844SAndroid Build Coastguard Worker   // the allocation is only now timing out.
507*d9f75844SAndroid Build Coastguard Worker   if (iter != server_sockets_.end() && iter->second != cricket::PROTO_UDP) {
508*d9f75844SAndroid Build Coastguard Worker     DestroyInternalSocket(socket);
509*d9f75844SAndroid Build Coastguard Worker   }
510*d9f75844SAndroid Build Coastguard Worker 
511*d9f75844SAndroid Build Coastguard Worker   allocations_.erase(*(allocation->conn()));
512*d9f75844SAndroid Build Coastguard Worker }
513*d9f75844SAndroid Build Coastguard Worker 
DestroyInternalSocket(rtc::AsyncPacketSocket * socket)514*d9f75844SAndroid Build Coastguard Worker void TurnServer::DestroyInternalSocket(rtc::AsyncPacketSocket* socket) {
515*d9f75844SAndroid Build Coastguard Worker   InternalSocketMap::iterator iter = server_sockets_.find(socket);
516*d9f75844SAndroid Build Coastguard Worker   if (iter != server_sockets_.end()) {
517*d9f75844SAndroid Build Coastguard Worker     rtc::AsyncPacketSocket* socket = iter->first;
518*d9f75844SAndroid Build Coastguard Worker     socket->UnsubscribeClose(this);
519*d9f75844SAndroid Build Coastguard Worker     socket->SignalReadPacket.disconnect(this);
520*d9f75844SAndroid Build Coastguard Worker     server_sockets_.erase(iter);
521*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<rtc::AsyncPacketSocket> socket_to_delete =
522*d9f75844SAndroid Build Coastguard Worker         absl::WrapUnique(socket);
523*d9f75844SAndroid Build Coastguard Worker     // We must destroy the socket async to avoid invalidating the sigslot
524*d9f75844SAndroid Build Coastguard Worker     // callback list iterator inside a sigslot callback. (In other words,
525*d9f75844SAndroid Build Coastguard Worker     // deleting an object from within a callback from that object).
526*d9f75844SAndroid Build Coastguard Worker     thread_->PostTask([socket_to_delete = std::move(socket_to_delete)] {});
527*d9f75844SAndroid Build Coastguard Worker   }
528*d9f75844SAndroid Build Coastguard Worker }
529*d9f75844SAndroid Build Coastguard Worker 
TurnServerConnection(const rtc::SocketAddress & src,ProtocolType proto,rtc::AsyncPacketSocket * socket)530*d9f75844SAndroid Build Coastguard Worker TurnServerConnection::TurnServerConnection(const rtc::SocketAddress& src,
531*d9f75844SAndroid Build Coastguard Worker                                            ProtocolType proto,
532*d9f75844SAndroid Build Coastguard Worker                                            rtc::AsyncPacketSocket* socket)
533*d9f75844SAndroid Build Coastguard Worker     : src_(src),
534*d9f75844SAndroid Build Coastguard Worker       dst_(socket->GetRemoteAddress()),
535*d9f75844SAndroid Build Coastguard Worker       proto_(proto),
536*d9f75844SAndroid Build Coastguard Worker       socket_(socket) {}
537*d9f75844SAndroid Build Coastguard Worker 
operator ==(const TurnServerConnection & c) const538*d9f75844SAndroid Build Coastguard Worker bool TurnServerConnection::operator==(const TurnServerConnection& c) const {
539*d9f75844SAndroid Build Coastguard Worker   return src_ == c.src_ && dst_ == c.dst_ && proto_ == c.proto_;
540*d9f75844SAndroid Build Coastguard Worker }
541*d9f75844SAndroid Build Coastguard Worker 
operator <(const TurnServerConnection & c) const542*d9f75844SAndroid Build Coastguard Worker bool TurnServerConnection::operator<(const TurnServerConnection& c) const {
543*d9f75844SAndroid Build Coastguard Worker   return std::tie(src_, dst_, proto_) < std::tie(c.src_, c.dst_, c.proto_);
544*d9f75844SAndroid Build Coastguard Worker }
545*d9f75844SAndroid Build Coastguard Worker 
ToString() const546*d9f75844SAndroid Build Coastguard Worker std::string TurnServerConnection::ToString() const {
547*d9f75844SAndroid Build Coastguard Worker   const char* const kProtos[] = {"unknown", "udp", "tcp", "ssltcp"};
548*d9f75844SAndroid Build Coastguard Worker   rtc::StringBuilder ost;
549*d9f75844SAndroid Build Coastguard Worker   ost << src_.ToSensitiveString() << "-" << dst_.ToSensitiveString() << ":"
550*d9f75844SAndroid Build Coastguard Worker       << kProtos[proto_];
551*d9f75844SAndroid Build Coastguard Worker   return ost.Release();
552*d9f75844SAndroid Build Coastguard Worker }
553*d9f75844SAndroid Build Coastguard Worker 
TurnServerAllocation(TurnServer * server,webrtc::TaskQueueBase * thread,const TurnServerConnection & conn,rtc::AsyncPacketSocket * socket,absl::string_view key)554*d9f75844SAndroid Build Coastguard Worker TurnServerAllocation::TurnServerAllocation(TurnServer* server,
555*d9f75844SAndroid Build Coastguard Worker                                            webrtc::TaskQueueBase* thread,
556*d9f75844SAndroid Build Coastguard Worker                                            const TurnServerConnection& conn,
557*d9f75844SAndroid Build Coastguard Worker                                            rtc::AsyncPacketSocket* socket,
558*d9f75844SAndroid Build Coastguard Worker                                            absl::string_view key)
559*d9f75844SAndroid Build Coastguard Worker     : server_(server),
560*d9f75844SAndroid Build Coastguard Worker       thread_(thread),
561*d9f75844SAndroid Build Coastguard Worker       conn_(conn),
562*d9f75844SAndroid Build Coastguard Worker       external_socket_(socket),
563*d9f75844SAndroid Build Coastguard Worker       key_(key) {
564*d9f75844SAndroid Build Coastguard Worker   external_socket_->SignalReadPacket.connect(
565*d9f75844SAndroid Build Coastguard Worker       this, &TurnServerAllocation::OnExternalPacket);
566*d9f75844SAndroid Build Coastguard Worker }
567*d9f75844SAndroid Build Coastguard Worker 
~TurnServerAllocation()568*d9f75844SAndroid Build Coastguard Worker TurnServerAllocation::~TurnServerAllocation() {
569*d9f75844SAndroid Build Coastguard Worker   channels_.clear();
570*d9f75844SAndroid Build Coastguard Worker   perms_.clear();
571*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << ToString() << ": Allocation destroyed";
572*d9f75844SAndroid Build Coastguard Worker }
573*d9f75844SAndroid Build Coastguard Worker 
ToString() const574*d9f75844SAndroid Build Coastguard Worker std::string TurnServerAllocation::ToString() const {
575*d9f75844SAndroid Build Coastguard Worker   rtc::StringBuilder ost;
576*d9f75844SAndroid Build Coastguard Worker   ost << "Alloc[" << conn_.ToString() << "]";
577*d9f75844SAndroid Build Coastguard Worker   return ost.Release();
578*d9f75844SAndroid Build Coastguard Worker }
579*d9f75844SAndroid Build Coastguard Worker 
HandleTurnMessage(const TurnMessage * msg)580*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::HandleTurnMessage(const TurnMessage* msg) {
581*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(msg != NULL);
582*d9f75844SAndroid Build Coastguard Worker   switch (msg->type()) {
583*d9f75844SAndroid Build Coastguard Worker     case STUN_ALLOCATE_REQUEST:
584*d9f75844SAndroid Build Coastguard Worker       HandleAllocateRequest(msg);
585*d9f75844SAndroid Build Coastguard Worker       break;
586*d9f75844SAndroid Build Coastguard Worker     case TURN_REFRESH_REQUEST:
587*d9f75844SAndroid Build Coastguard Worker       HandleRefreshRequest(msg);
588*d9f75844SAndroid Build Coastguard Worker       break;
589*d9f75844SAndroid Build Coastguard Worker     case TURN_SEND_INDICATION:
590*d9f75844SAndroid Build Coastguard Worker       HandleSendIndication(msg);
591*d9f75844SAndroid Build Coastguard Worker       break;
592*d9f75844SAndroid Build Coastguard Worker     case TURN_CREATE_PERMISSION_REQUEST:
593*d9f75844SAndroid Build Coastguard Worker       HandleCreatePermissionRequest(msg);
594*d9f75844SAndroid Build Coastguard Worker       break;
595*d9f75844SAndroid Build Coastguard Worker     case TURN_CHANNEL_BIND_REQUEST:
596*d9f75844SAndroid Build Coastguard Worker       HandleChannelBindRequest(msg);
597*d9f75844SAndroid Build Coastguard Worker       break;
598*d9f75844SAndroid Build Coastguard Worker     default:
599*d9f75844SAndroid Build Coastguard Worker       // Not sure what to do with this, just eat it.
600*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_WARNING) << ToString()
601*d9f75844SAndroid Build Coastguard Worker                           << ": Invalid TURN message type received: "
602*d9f75844SAndroid Build Coastguard Worker                           << msg->type();
603*d9f75844SAndroid Build Coastguard Worker   }
604*d9f75844SAndroid Build Coastguard Worker }
605*d9f75844SAndroid Build Coastguard Worker 
HandleAllocateRequest(const TurnMessage * msg)606*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::HandleAllocateRequest(const TurnMessage* msg) {
607*d9f75844SAndroid Build Coastguard Worker   // Copy the important info from the allocate request.
608*d9f75844SAndroid Build Coastguard Worker   transaction_id_ = msg->transaction_id();
609*d9f75844SAndroid Build Coastguard Worker   const StunByteStringAttribute* username_attr =
610*d9f75844SAndroid Build Coastguard Worker       msg->GetByteString(STUN_ATTR_USERNAME);
611*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(username_attr != NULL);
612*d9f75844SAndroid Build Coastguard Worker   username_ = std::string(username_attr->string_view());
613*d9f75844SAndroid Build Coastguard Worker 
614*d9f75844SAndroid Build Coastguard Worker   // Figure out the lifetime and start the allocation timer.
615*d9f75844SAndroid Build Coastguard Worker   TimeDelta lifetime = ComputeLifetime(*msg);
616*d9f75844SAndroid Build Coastguard Worker   PostDeleteSelf(lifetime);
617*d9f75844SAndroid Build Coastguard Worker 
618*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << ToString() << ": Created allocation with lifetime="
619*d9f75844SAndroid Build Coastguard Worker                    << lifetime.seconds();
620*d9f75844SAndroid Build Coastguard Worker 
621*d9f75844SAndroid Build Coastguard Worker   // We've already validated all the important bits; just send a response here.
622*d9f75844SAndroid Build Coastguard Worker   TurnMessage response(GetStunSuccessResponseTypeOrZero(*msg),
623*d9f75844SAndroid Build Coastguard Worker                        msg->transaction_id());
624*d9f75844SAndroid Build Coastguard Worker 
625*d9f75844SAndroid Build Coastguard Worker   auto mapped_addr_attr = std::make_unique<StunXorAddressAttribute>(
626*d9f75844SAndroid Build Coastguard Worker       STUN_ATTR_XOR_MAPPED_ADDRESS, conn_.src());
627*d9f75844SAndroid Build Coastguard Worker   auto relayed_addr_attr = std::make_unique<StunXorAddressAttribute>(
628*d9f75844SAndroid Build Coastguard Worker       STUN_ATTR_XOR_RELAYED_ADDRESS, external_socket_->GetLocalAddress());
629*d9f75844SAndroid Build Coastguard Worker   auto lifetime_attr = std::make_unique<StunUInt32Attribute>(
630*d9f75844SAndroid Build Coastguard Worker       STUN_ATTR_LIFETIME, lifetime.seconds());
631*d9f75844SAndroid Build Coastguard Worker   response.AddAttribute(std::move(mapped_addr_attr));
632*d9f75844SAndroid Build Coastguard Worker   response.AddAttribute(std::move(relayed_addr_attr));
633*d9f75844SAndroid Build Coastguard Worker   response.AddAttribute(std::move(lifetime_attr));
634*d9f75844SAndroid Build Coastguard Worker 
635*d9f75844SAndroid Build Coastguard Worker   SendResponse(&response);
636*d9f75844SAndroid Build Coastguard Worker }
637*d9f75844SAndroid Build Coastguard Worker 
HandleRefreshRequest(const TurnMessage * msg)638*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::HandleRefreshRequest(const TurnMessage* msg) {
639*d9f75844SAndroid Build Coastguard Worker   // Figure out the new lifetime.
640*d9f75844SAndroid Build Coastguard Worker   TimeDelta lifetime = ComputeLifetime(*msg);
641*d9f75844SAndroid Build Coastguard Worker 
642*d9f75844SAndroid Build Coastguard Worker   // Reset the expiration timer.
643*d9f75844SAndroid Build Coastguard Worker   safety_.reset();
644*d9f75844SAndroid Build Coastguard Worker   PostDeleteSelf(lifetime);
645*d9f75844SAndroid Build Coastguard Worker 
646*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << ToString()
647*d9f75844SAndroid Build Coastguard Worker                    << ": Refreshed allocation, lifetime=" << lifetime.seconds();
648*d9f75844SAndroid Build Coastguard Worker 
649*d9f75844SAndroid Build Coastguard Worker   // Send a success response with a LIFETIME attribute.
650*d9f75844SAndroid Build Coastguard Worker   TurnMessage response(GetStunSuccessResponseTypeOrZero(*msg),
651*d9f75844SAndroid Build Coastguard Worker                        msg->transaction_id());
652*d9f75844SAndroid Build Coastguard Worker 
653*d9f75844SAndroid Build Coastguard Worker   auto lifetime_attr = std::make_unique<StunUInt32Attribute>(
654*d9f75844SAndroid Build Coastguard Worker       STUN_ATTR_LIFETIME, lifetime.seconds());
655*d9f75844SAndroid Build Coastguard Worker   response.AddAttribute(std::move(lifetime_attr));
656*d9f75844SAndroid Build Coastguard Worker 
657*d9f75844SAndroid Build Coastguard Worker   SendResponse(&response);
658*d9f75844SAndroid Build Coastguard Worker }
659*d9f75844SAndroid Build Coastguard Worker 
HandleSendIndication(const TurnMessage * msg)660*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::HandleSendIndication(const TurnMessage* msg) {
661*d9f75844SAndroid Build Coastguard Worker   // Check mandatory attributes.
662*d9f75844SAndroid Build Coastguard Worker   const StunByteStringAttribute* data_attr = msg->GetByteString(STUN_ATTR_DATA);
663*d9f75844SAndroid Build Coastguard Worker   const StunAddressAttribute* peer_attr =
664*d9f75844SAndroid Build Coastguard Worker       msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
665*d9f75844SAndroid Build Coastguard Worker   if (!data_attr || !peer_attr) {
666*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << ToString() << ": Received invalid send indication";
667*d9f75844SAndroid Build Coastguard Worker     return;
668*d9f75844SAndroid Build Coastguard Worker   }
669*d9f75844SAndroid Build Coastguard Worker 
670*d9f75844SAndroid Build Coastguard Worker   // If a permission exists, send the data on to the peer.
671*d9f75844SAndroid Build Coastguard Worker   if (HasPermission(peer_attr->GetAddress().ipaddr())) {
672*d9f75844SAndroid Build Coastguard Worker     SendExternal(data_attr->bytes(), data_attr->length(),
673*d9f75844SAndroid Build Coastguard Worker                  peer_attr->GetAddress());
674*d9f75844SAndroid Build Coastguard Worker   } else {
675*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << ToString()
676*d9f75844SAndroid Build Coastguard Worker                         << ": Received send indication without permission"
677*d9f75844SAndroid Build Coastguard Worker                            " peer="
678*d9f75844SAndroid Build Coastguard Worker                         << peer_attr->GetAddress().ToSensitiveString();
679*d9f75844SAndroid Build Coastguard Worker   }
680*d9f75844SAndroid Build Coastguard Worker }
681*d9f75844SAndroid Build Coastguard Worker 
HandleCreatePermissionRequest(const TurnMessage * msg)682*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::HandleCreatePermissionRequest(
683*d9f75844SAndroid Build Coastguard Worker     const TurnMessage* msg) {
684*d9f75844SAndroid Build Coastguard Worker   // Check mandatory attributes.
685*d9f75844SAndroid Build Coastguard Worker   const StunAddressAttribute* peer_attr =
686*d9f75844SAndroid Build Coastguard Worker       msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
687*d9f75844SAndroid Build Coastguard Worker   if (!peer_attr) {
688*d9f75844SAndroid Build Coastguard Worker     SendBadRequestResponse(msg);
689*d9f75844SAndroid Build Coastguard Worker     return;
690*d9f75844SAndroid Build Coastguard Worker   }
691*d9f75844SAndroid Build Coastguard Worker 
692*d9f75844SAndroid Build Coastguard Worker   if (server_->reject_private_addresses_ &&
693*d9f75844SAndroid Build Coastguard Worker       rtc::IPIsPrivate(peer_attr->GetAddress().ipaddr())) {
694*d9f75844SAndroid Build Coastguard Worker     SendErrorResponse(msg, STUN_ERROR_FORBIDDEN, STUN_ERROR_REASON_FORBIDDEN);
695*d9f75844SAndroid Build Coastguard Worker     return;
696*d9f75844SAndroid Build Coastguard Worker   }
697*d9f75844SAndroid Build Coastguard Worker 
698*d9f75844SAndroid Build Coastguard Worker   // Add this permission.
699*d9f75844SAndroid Build Coastguard Worker   AddPermission(peer_attr->GetAddress().ipaddr());
700*d9f75844SAndroid Build Coastguard Worker 
701*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << ToString() << ": Created permission, peer="
702*d9f75844SAndroid Build Coastguard Worker                    << peer_attr->GetAddress().ToSensitiveString();
703*d9f75844SAndroid Build Coastguard Worker 
704*d9f75844SAndroid Build Coastguard Worker   // Send a success response.
705*d9f75844SAndroid Build Coastguard Worker   TurnMessage response(GetStunSuccessResponseTypeOrZero(*msg),
706*d9f75844SAndroid Build Coastguard Worker                        msg->transaction_id());
707*d9f75844SAndroid Build Coastguard Worker   SendResponse(&response);
708*d9f75844SAndroid Build Coastguard Worker }
709*d9f75844SAndroid Build Coastguard Worker 
HandleChannelBindRequest(const TurnMessage * msg)710*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::HandleChannelBindRequest(const TurnMessage* msg) {
711*d9f75844SAndroid Build Coastguard Worker   // Check mandatory attributes.
712*d9f75844SAndroid Build Coastguard Worker   const StunUInt32Attribute* channel_attr =
713*d9f75844SAndroid Build Coastguard Worker       msg->GetUInt32(STUN_ATTR_CHANNEL_NUMBER);
714*d9f75844SAndroid Build Coastguard Worker   const StunAddressAttribute* peer_attr =
715*d9f75844SAndroid Build Coastguard Worker       msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS);
716*d9f75844SAndroid Build Coastguard Worker   if (!channel_attr || !peer_attr) {
717*d9f75844SAndroid Build Coastguard Worker     SendBadRequestResponse(msg);
718*d9f75844SAndroid Build Coastguard Worker     return;
719*d9f75844SAndroid Build Coastguard Worker   }
720*d9f75844SAndroid Build Coastguard Worker 
721*d9f75844SAndroid Build Coastguard Worker   // Check that channel id is valid.
722*d9f75844SAndroid Build Coastguard Worker   int channel_id = channel_attr->value() >> 16;
723*d9f75844SAndroid Build Coastguard Worker   if (channel_id < kMinChannelNumber || channel_id > kMaxChannelNumber) {
724*d9f75844SAndroid Build Coastguard Worker     SendBadRequestResponse(msg);
725*d9f75844SAndroid Build Coastguard Worker     return;
726*d9f75844SAndroid Build Coastguard Worker   }
727*d9f75844SAndroid Build Coastguard Worker 
728*d9f75844SAndroid Build Coastguard Worker   // Check that this channel id isn't bound to another transport address, and
729*d9f75844SAndroid Build Coastguard Worker   // that this transport address isn't bound to another channel id.
730*d9f75844SAndroid Build Coastguard Worker   auto channel1 = FindChannel(channel_id);
731*d9f75844SAndroid Build Coastguard Worker   auto channel2 = FindChannel(peer_attr->GetAddress());
732*d9f75844SAndroid Build Coastguard Worker   if (channel1 != channel2) {
733*d9f75844SAndroid Build Coastguard Worker     SendBadRequestResponse(msg);
734*d9f75844SAndroid Build Coastguard Worker     return;
735*d9f75844SAndroid Build Coastguard Worker   }
736*d9f75844SAndroid Build Coastguard Worker 
737*d9f75844SAndroid Build Coastguard Worker   // Add or refresh this channel.
738*d9f75844SAndroid Build Coastguard Worker   if (channel1 == channels_.end()) {
739*d9f75844SAndroid Build Coastguard Worker     channel1 = channels_.insert(
740*d9f75844SAndroid Build Coastguard Worker         channels_.end(), {.id = channel_id, .peer = peer_attr->GetAddress()});
741*d9f75844SAndroid Build Coastguard Worker   } else {
742*d9f75844SAndroid Build Coastguard Worker     channel1->pending_delete.reset();
743*d9f75844SAndroid Build Coastguard Worker   }
744*d9f75844SAndroid Build Coastguard Worker   thread_->PostDelayedTask(
745*d9f75844SAndroid Build Coastguard Worker       SafeTask(channel1->pending_delete.flag(),
746*d9f75844SAndroid Build Coastguard Worker                [this, channel1] { channels_.erase(channel1); }),
747*d9f75844SAndroid Build Coastguard Worker       kChannelTimeout);
748*d9f75844SAndroid Build Coastguard Worker 
749*d9f75844SAndroid Build Coastguard Worker   // Channel binds also refresh permissions.
750*d9f75844SAndroid Build Coastguard Worker   AddPermission(peer_attr->GetAddress().ipaddr());
751*d9f75844SAndroid Build Coastguard Worker 
752*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << ToString() << ": Bound channel, id=" << channel_id
753*d9f75844SAndroid Build Coastguard Worker                    << ", peer=" << peer_attr->GetAddress().ToSensitiveString();
754*d9f75844SAndroid Build Coastguard Worker 
755*d9f75844SAndroid Build Coastguard Worker   // Send a success response.
756*d9f75844SAndroid Build Coastguard Worker   TurnMessage response(GetStunSuccessResponseTypeOrZero(*msg),
757*d9f75844SAndroid Build Coastguard Worker                        msg->transaction_id());
758*d9f75844SAndroid Build Coastguard Worker   SendResponse(&response);
759*d9f75844SAndroid Build Coastguard Worker }
760*d9f75844SAndroid Build Coastguard Worker 
HandleChannelData(const char * data,size_t size)761*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::HandleChannelData(const char* data, size_t size) {
762*d9f75844SAndroid Build Coastguard Worker   // Extract the channel number from the data.
763*d9f75844SAndroid Build Coastguard Worker   uint16_t channel_id = rtc::GetBE16(data);
764*d9f75844SAndroid Build Coastguard Worker   auto channel = FindChannel(channel_id);
765*d9f75844SAndroid Build Coastguard Worker   if (channel != channels_.end()) {
766*d9f75844SAndroid Build Coastguard Worker     // Send the data to the peer address.
767*d9f75844SAndroid Build Coastguard Worker     SendExternal(data + TURN_CHANNEL_HEADER_SIZE,
768*d9f75844SAndroid Build Coastguard Worker                  size - TURN_CHANNEL_HEADER_SIZE, channel->peer);
769*d9f75844SAndroid Build Coastguard Worker   } else {
770*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << ToString()
771*d9f75844SAndroid Build Coastguard Worker                         << ": Received channel data for invalid channel, id="
772*d9f75844SAndroid Build Coastguard Worker                         << channel_id;
773*d9f75844SAndroid Build Coastguard Worker   }
774*d9f75844SAndroid Build Coastguard Worker }
775*d9f75844SAndroid Build Coastguard Worker 
OnExternalPacket(rtc::AsyncPacketSocket * socket,const char * data,size_t size,const rtc::SocketAddress & addr,const int64_t &)776*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::OnExternalPacket(
777*d9f75844SAndroid Build Coastguard Worker     rtc::AsyncPacketSocket* socket,
778*d9f75844SAndroid Build Coastguard Worker     const char* data,
779*d9f75844SAndroid Build Coastguard Worker     size_t size,
780*d9f75844SAndroid Build Coastguard Worker     const rtc::SocketAddress& addr,
781*d9f75844SAndroid Build Coastguard Worker     const int64_t& /* packet_time_us */) {
782*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(external_socket_.get() == socket);
783*d9f75844SAndroid Build Coastguard Worker   auto channel = FindChannel(addr);
784*d9f75844SAndroid Build Coastguard Worker   if (channel != channels_.end()) {
785*d9f75844SAndroid Build Coastguard Worker     // There is a channel bound to this address. Send as a channel message.
786*d9f75844SAndroid Build Coastguard Worker     rtc::ByteBufferWriter buf;
787*d9f75844SAndroid Build Coastguard Worker     buf.WriteUInt16(channel->id);
788*d9f75844SAndroid Build Coastguard Worker     buf.WriteUInt16(static_cast<uint16_t>(size));
789*d9f75844SAndroid Build Coastguard Worker     buf.WriteBytes(data, size);
790*d9f75844SAndroid Build Coastguard Worker     server_->Send(&conn_, buf);
791*d9f75844SAndroid Build Coastguard Worker   } else if (!server_->enable_permission_checks_ ||
792*d9f75844SAndroid Build Coastguard Worker              HasPermission(addr.ipaddr())) {
793*d9f75844SAndroid Build Coastguard Worker     // No channel, but a permission exists. Send as a data indication.
794*d9f75844SAndroid Build Coastguard Worker     TurnMessage msg(TURN_DATA_INDICATION);
795*d9f75844SAndroid Build Coastguard Worker     msg.AddAttribute(std::make_unique<StunXorAddressAttribute>(
796*d9f75844SAndroid Build Coastguard Worker         STUN_ATTR_XOR_PEER_ADDRESS, addr));
797*d9f75844SAndroid Build Coastguard Worker     msg.AddAttribute(
798*d9f75844SAndroid Build Coastguard Worker         std::make_unique<StunByteStringAttribute>(STUN_ATTR_DATA, data, size));
799*d9f75844SAndroid Build Coastguard Worker     server_->SendStun(&conn_, &msg);
800*d9f75844SAndroid Build Coastguard Worker   } else {
801*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING)
802*d9f75844SAndroid Build Coastguard Worker         << ToString() << ": Received external packet without permission, peer="
803*d9f75844SAndroid Build Coastguard Worker         << addr.ToSensitiveString();
804*d9f75844SAndroid Build Coastguard Worker   }
805*d9f75844SAndroid Build Coastguard Worker }
806*d9f75844SAndroid Build Coastguard Worker 
ComputeLifetime(const TurnMessage & msg)807*d9f75844SAndroid Build Coastguard Worker TimeDelta TurnServerAllocation::ComputeLifetime(const TurnMessage& msg) {
808*d9f75844SAndroid Build Coastguard Worker   if (const StunUInt32Attribute* attr = msg.GetUInt32(STUN_ATTR_LIFETIME)) {
809*d9f75844SAndroid Build Coastguard Worker     return std::min(TimeDelta::Seconds(static_cast<int>(attr->value())),
810*d9f75844SAndroid Build Coastguard Worker                     kDefaultAllocationTimeout);
811*d9f75844SAndroid Build Coastguard Worker   }
812*d9f75844SAndroid Build Coastguard Worker   return kDefaultAllocationTimeout;
813*d9f75844SAndroid Build Coastguard Worker }
814*d9f75844SAndroid Build Coastguard Worker 
HasPermission(const rtc::IPAddress & addr)815*d9f75844SAndroid Build Coastguard Worker bool TurnServerAllocation::HasPermission(const rtc::IPAddress& addr) {
816*d9f75844SAndroid Build Coastguard Worker   return FindPermission(addr) != perms_.end();
817*d9f75844SAndroid Build Coastguard Worker }
818*d9f75844SAndroid Build Coastguard Worker 
AddPermission(const rtc::IPAddress & addr)819*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::AddPermission(const rtc::IPAddress& addr) {
820*d9f75844SAndroid Build Coastguard Worker   auto perm = FindPermission(addr);
821*d9f75844SAndroid Build Coastguard Worker   if (perm == perms_.end()) {
822*d9f75844SAndroid Build Coastguard Worker     perm = perms_.insert(perms_.end(), {.peer = addr});
823*d9f75844SAndroid Build Coastguard Worker   } else {
824*d9f75844SAndroid Build Coastguard Worker     perm->pending_delete.reset();
825*d9f75844SAndroid Build Coastguard Worker   }
826*d9f75844SAndroid Build Coastguard Worker   thread_->PostDelayedTask(SafeTask(perm->pending_delete.flag(),
827*d9f75844SAndroid Build Coastguard Worker                                     [this, perm] { perms_.erase(perm); }),
828*d9f75844SAndroid Build Coastguard Worker                            kPermissionTimeout);
829*d9f75844SAndroid Build Coastguard Worker }
830*d9f75844SAndroid Build Coastguard Worker 
831*d9f75844SAndroid Build Coastguard Worker TurnServerAllocation::PermissionList::iterator
FindPermission(const rtc::IPAddress & addr)832*d9f75844SAndroid Build Coastguard Worker TurnServerAllocation::FindPermission(const rtc::IPAddress& addr) {
833*d9f75844SAndroid Build Coastguard Worker   return absl::c_find_if(perms_,
834*d9f75844SAndroid Build Coastguard Worker                          [&](const Permission& p) { return p.peer == addr; });
835*d9f75844SAndroid Build Coastguard Worker }
836*d9f75844SAndroid Build Coastguard Worker 
FindChannel(int channel_id)837*d9f75844SAndroid Build Coastguard Worker TurnServerAllocation::ChannelList::iterator TurnServerAllocation::FindChannel(
838*d9f75844SAndroid Build Coastguard Worker     int channel_id) {
839*d9f75844SAndroid Build Coastguard Worker   return absl::c_find_if(channels_,
840*d9f75844SAndroid Build Coastguard Worker                          [&](const Channel& c) { return c.id == channel_id; });
841*d9f75844SAndroid Build Coastguard Worker }
842*d9f75844SAndroid Build Coastguard Worker 
FindChannel(const rtc::SocketAddress & addr)843*d9f75844SAndroid Build Coastguard Worker TurnServerAllocation::ChannelList::iterator TurnServerAllocation::FindChannel(
844*d9f75844SAndroid Build Coastguard Worker     const rtc::SocketAddress& addr) {
845*d9f75844SAndroid Build Coastguard Worker   return absl::c_find_if(channels_,
846*d9f75844SAndroid Build Coastguard Worker                          [&](const Channel& c) { return c.peer == addr; });
847*d9f75844SAndroid Build Coastguard Worker }
848*d9f75844SAndroid Build Coastguard Worker 
SendResponse(TurnMessage * msg)849*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::SendResponse(TurnMessage* msg) {
850*d9f75844SAndroid Build Coastguard Worker   // Success responses always have M-I.
851*d9f75844SAndroid Build Coastguard Worker   msg->AddMessageIntegrity(key_);
852*d9f75844SAndroid Build Coastguard Worker   server_->SendStun(&conn_, msg);
853*d9f75844SAndroid Build Coastguard Worker }
854*d9f75844SAndroid Build Coastguard Worker 
SendBadRequestResponse(const TurnMessage * req)855*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::SendBadRequestResponse(const TurnMessage* req) {
856*d9f75844SAndroid Build Coastguard Worker   SendErrorResponse(req, STUN_ERROR_BAD_REQUEST, STUN_ERROR_REASON_BAD_REQUEST);
857*d9f75844SAndroid Build Coastguard Worker }
858*d9f75844SAndroid Build Coastguard Worker 
SendErrorResponse(const TurnMessage * req,int code,absl::string_view reason)859*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::SendErrorResponse(const TurnMessage* req,
860*d9f75844SAndroid Build Coastguard Worker                                              int code,
861*d9f75844SAndroid Build Coastguard Worker                                              absl::string_view reason) {
862*d9f75844SAndroid Build Coastguard Worker   server_->SendErrorResponse(&conn_, req, code, reason);
863*d9f75844SAndroid Build Coastguard Worker }
864*d9f75844SAndroid Build Coastguard Worker 
SendExternal(const void * data,size_t size,const rtc::SocketAddress & peer)865*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::SendExternal(const void* data,
866*d9f75844SAndroid Build Coastguard Worker                                         size_t size,
867*d9f75844SAndroid Build Coastguard Worker                                         const rtc::SocketAddress& peer) {
868*d9f75844SAndroid Build Coastguard Worker   rtc::PacketOptions options;
869*d9f75844SAndroid Build Coastguard Worker   external_socket_->SendTo(data, size, peer, options);
870*d9f75844SAndroid Build Coastguard Worker }
871*d9f75844SAndroid Build Coastguard Worker 
PostDeleteSelf(TimeDelta delay)872*d9f75844SAndroid Build Coastguard Worker void TurnServerAllocation::PostDeleteSelf(TimeDelta delay) {
873*d9f75844SAndroid Build Coastguard Worker   auto delete_self = [this] {
874*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(server_->thread_);
875*d9f75844SAndroid Build Coastguard Worker     server_->DestroyAllocation(this);
876*d9f75844SAndroid Build Coastguard Worker   };
877*d9f75844SAndroid Build Coastguard Worker   thread_->PostDelayedTask(SafeTask(safety_.flag(), std::move(delete_self)),
878*d9f75844SAndroid Build Coastguard Worker                            delay);
879*d9f75844SAndroid Build Coastguard Worker }
880*d9f75844SAndroid Build Coastguard Worker 
881*d9f75844SAndroid Build Coastguard Worker }  // namespace cricket
882