xref: /aosp_15_r20/external/webrtc/rtc_base/nat_server.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2004 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 "rtc_base/nat_server.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <memory>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
16*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/nat_socket_factory.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/socket_adapters.h"
19*d9f75844SAndroid Build Coastguard Worker 
20*d9f75844SAndroid Build Coastguard Worker namespace rtc {
21*d9f75844SAndroid Build Coastguard Worker 
RouteCmp(NAT * nat)22*d9f75844SAndroid Build Coastguard Worker RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) {}
23*d9f75844SAndroid Build Coastguard Worker 
operator ()(const SocketAddressPair & r) const24*d9f75844SAndroid Build Coastguard Worker size_t RouteCmp::operator()(const SocketAddressPair& r) const {
25*d9f75844SAndroid Build Coastguard Worker   size_t h = r.source().Hash();
26*d9f75844SAndroid Build Coastguard Worker   if (symmetric)
27*d9f75844SAndroid Build Coastguard Worker     h ^= r.destination().Hash();
28*d9f75844SAndroid Build Coastguard Worker   return h;
29*d9f75844SAndroid Build Coastguard Worker }
30*d9f75844SAndroid Build Coastguard Worker 
operator ()(const SocketAddressPair & r1,const SocketAddressPair & r2) const31*d9f75844SAndroid Build Coastguard Worker bool RouteCmp::operator()(const SocketAddressPair& r1,
32*d9f75844SAndroid Build Coastguard Worker                           const SocketAddressPair& r2) const {
33*d9f75844SAndroid Build Coastguard Worker   if (r1.source() < r2.source())
34*d9f75844SAndroid Build Coastguard Worker     return true;
35*d9f75844SAndroid Build Coastguard Worker   if (r2.source() < r1.source())
36*d9f75844SAndroid Build Coastguard Worker     return false;
37*d9f75844SAndroid Build Coastguard Worker   if (symmetric && (r1.destination() < r2.destination()))
38*d9f75844SAndroid Build Coastguard Worker     return true;
39*d9f75844SAndroid Build Coastguard Worker   if (symmetric && (r2.destination() < r1.destination()))
40*d9f75844SAndroid Build Coastguard Worker     return false;
41*d9f75844SAndroid Build Coastguard Worker   return false;
42*d9f75844SAndroid Build Coastguard Worker }
43*d9f75844SAndroid Build Coastguard Worker 
AddrCmp(NAT * nat)44*d9f75844SAndroid Build Coastguard Worker AddrCmp::AddrCmp(NAT* nat)
45*d9f75844SAndroid Build Coastguard Worker     : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) {}
46*d9f75844SAndroid Build Coastguard Worker 
operator ()(const SocketAddress & a) const47*d9f75844SAndroid Build Coastguard Worker size_t AddrCmp::operator()(const SocketAddress& a) const {
48*d9f75844SAndroid Build Coastguard Worker   size_t h = 0;
49*d9f75844SAndroid Build Coastguard Worker   if (use_ip)
50*d9f75844SAndroid Build Coastguard Worker     h ^= HashIP(a.ipaddr());
51*d9f75844SAndroid Build Coastguard Worker   if (use_port)
52*d9f75844SAndroid Build Coastguard Worker     h ^= a.port() | (a.port() << 16);
53*d9f75844SAndroid Build Coastguard Worker   return h;
54*d9f75844SAndroid Build Coastguard Worker }
55*d9f75844SAndroid Build Coastguard Worker 
operator ()(const SocketAddress & a1,const SocketAddress & a2) const56*d9f75844SAndroid Build Coastguard Worker bool AddrCmp::operator()(const SocketAddress& a1,
57*d9f75844SAndroid Build Coastguard Worker                          const SocketAddress& a2) const {
58*d9f75844SAndroid Build Coastguard Worker   if (use_ip && (a1.ipaddr() < a2.ipaddr()))
59*d9f75844SAndroid Build Coastguard Worker     return true;
60*d9f75844SAndroid Build Coastguard Worker   if (use_ip && (a2.ipaddr() < a1.ipaddr()))
61*d9f75844SAndroid Build Coastguard Worker     return false;
62*d9f75844SAndroid Build Coastguard Worker   if (use_port && (a1.port() < a2.port()))
63*d9f75844SAndroid Build Coastguard Worker     return true;
64*d9f75844SAndroid Build Coastguard Worker   if (use_port && (a2.port() < a1.port()))
65*d9f75844SAndroid Build Coastguard Worker     return false;
66*d9f75844SAndroid Build Coastguard Worker   return false;
67*d9f75844SAndroid Build Coastguard Worker }
68*d9f75844SAndroid Build Coastguard Worker 
69*d9f75844SAndroid Build Coastguard Worker // Proxy socket that will capture the external destination address intended for
70*d9f75844SAndroid Build Coastguard Worker // a TCP connection to the NAT server.
71*d9f75844SAndroid Build Coastguard Worker class NATProxyServerSocket : public AsyncProxyServerSocket {
72*d9f75844SAndroid Build Coastguard Worker  public:
NATProxyServerSocket(Socket * socket)73*d9f75844SAndroid Build Coastguard Worker   NATProxyServerSocket(Socket* socket)
74*d9f75844SAndroid Build Coastguard Worker       : AsyncProxyServerSocket(socket, kNATEncodedIPv6AddressSize) {
75*d9f75844SAndroid Build Coastguard Worker     BufferInput(true);
76*d9f75844SAndroid Build Coastguard Worker   }
77*d9f75844SAndroid Build Coastguard Worker 
SendConnectResult(int err,const SocketAddress & addr)78*d9f75844SAndroid Build Coastguard Worker   void SendConnectResult(int err, const SocketAddress& addr) override {
79*d9f75844SAndroid Build Coastguard Worker     char code = err ? 1 : 0;
80*d9f75844SAndroid Build Coastguard Worker     BufferedReadAdapter::DirectSend(&code, sizeof(char));
81*d9f75844SAndroid Build Coastguard Worker   }
82*d9f75844SAndroid Build Coastguard Worker 
83*d9f75844SAndroid Build Coastguard Worker  protected:
ProcessInput(char * data,size_t * len)84*d9f75844SAndroid Build Coastguard Worker   void ProcessInput(char* data, size_t* len) override {
85*d9f75844SAndroid Build Coastguard Worker     if (*len < 2) {
86*d9f75844SAndroid Build Coastguard Worker       return;
87*d9f75844SAndroid Build Coastguard Worker     }
88*d9f75844SAndroid Build Coastguard Worker 
89*d9f75844SAndroid Build Coastguard Worker     int family = data[1];
90*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(family == AF_INET || family == AF_INET6);
91*d9f75844SAndroid Build Coastguard Worker     if ((family == AF_INET && *len < kNATEncodedIPv4AddressSize) ||
92*d9f75844SAndroid Build Coastguard Worker         (family == AF_INET6 && *len < kNATEncodedIPv6AddressSize)) {
93*d9f75844SAndroid Build Coastguard Worker       return;
94*d9f75844SAndroid Build Coastguard Worker     }
95*d9f75844SAndroid Build Coastguard Worker 
96*d9f75844SAndroid Build Coastguard Worker     SocketAddress dest_addr;
97*d9f75844SAndroid Build Coastguard Worker     size_t address_length = UnpackAddressFromNAT(data, *len, &dest_addr);
98*d9f75844SAndroid Build Coastguard Worker 
99*d9f75844SAndroid Build Coastguard Worker     *len -= address_length;
100*d9f75844SAndroid Build Coastguard Worker     if (*len > 0) {
101*d9f75844SAndroid Build Coastguard Worker       memmove(data, data + address_length, *len);
102*d9f75844SAndroid Build Coastguard Worker     }
103*d9f75844SAndroid Build Coastguard Worker 
104*d9f75844SAndroid Build Coastguard Worker     bool remainder = (*len > 0);
105*d9f75844SAndroid Build Coastguard Worker     BufferInput(false);
106*d9f75844SAndroid Build Coastguard Worker     SignalConnectRequest(this, dest_addr);
107*d9f75844SAndroid Build Coastguard Worker     if (remainder) {
108*d9f75844SAndroid Build Coastguard Worker       SignalReadEvent(this);
109*d9f75844SAndroid Build Coastguard Worker     }
110*d9f75844SAndroid Build Coastguard Worker   }
111*d9f75844SAndroid Build Coastguard Worker };
112*d9f75844SAndroid Build Coastguard Worker 
113*d9f75844SAndroid Build Coastguard Worker class NATProxyServer : public ProxyServer {
114*d9f75844SAndroid Build Coastguard Worker  public:
NATProxyServer(SocketFactory * int_factory,const SocketAddress & int_addr,SocketFactory * ext_factory,const SocketAddress & ext_ip)115*d9f75844SAndroid Build Coastguard Worker   NATProxyServer(SocketFactory* int_factory,
116*d9f75844SAndroid Build Coastguard Worker                  const SocketAddress& int_addr,
117*d9f75844SAndroid Build Coastguard Worker                  SocketFactory* ext_factory,
118*d9f75844SAndroid Build Coastguard Worker                  const SocketAddress& ext_ip)
119*d9f75844SAndroid Build Coastguard Worker       : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {}
120*d9f75844SAndroid Build Coastguard Worker 
121*d9f75844SAndroid Build Coastguard Worker  protected:
WrapSocket(Socket * socket)122*d9f75844SAndroid Build Coastguard Worker   AsyncProxyServerSocket* WrapSocket(Socket* socket) override {
123*d9f75844SAndroid Build Coastguard Worker     return new NATProxyServerSocket(socket);
124*d9f75844SAndroid Build Coastguard Worker   }
125*d9f75844SAndroid Build Coastguard Worker };
126*d9f75844SAndroid Build Coastguard Worker 
NATServer(NATType type,SocketFactory * internal,const SocketAddress & internal_udp_addr,const SocketAddress & internal_tcp_addr,SocketFactory * external,const SocketAddress & external_ip)127*d9f75844SAndroid Build Coastguard Worker NATServer::NATServer(NATType type,
128*d9f75844SAndroid Build Coastguard Worker                      SocketFactory* internal,
129*d9f75844SAndroid Build Coastguard Worker                      const SocketAddress& internal_udp_addr,
130*d9f75844SAndroid Build Coastguard Worker                      const SocketAddress& internal_tcp_addr,
131*d9f75844SAndroid Build Coastguard Worker                      SocketFactory* external,
132*d9f75844SAndroid Build Coastguard Worker                      const SocketAddress& external_ip)
133*d9f75844SAndroid Build Coastguard Worker     : external_(external), external_ip_(external_ip.ipaddr(), 0) {
134*d9f75844SAndroid Build Coastguard Worker   nat_ = NAT::Create(type);
135*d9f75844SAndroid Build Coastguard Worker 
136*d9f75844SAndroid Build Coastguard Worker   udp_server_socket_ = AsyncUDPSocket::Create(internal, internal_udp_addr);
137*d9f75844SAndroid Build Coastguard Worker   udp_server_socket_->SignalReadPacket.connect(this,
138*d9f75844SAndroid Build Coastguard Worker                                                &NATServer::OnInternalUDPPacket);
139*d9f75844SAndroid Build Coastguard Worker   tcp_proxy_server_ =
140*d9f75844SAndroid Build Coastguard Worker       new NATProxyServer(internal, internal_tcp_addr, external, external_ip);
141*d9f75844SAndroid Build Coastguard Worker 
142*d9f75844SAndroid Build Coastguard Worker   int_map_ = new InternalMap(RouteCmp(nat_));
143*d9f75844SAndroid Build Coastguard Worker   ext_map_ = new ExternalMap();
144*d9f75844SAndroid Build Coastguard Worker }
145*d9f75844SAndroid Build Coastguard Worker 
~NATServer()146*d9f75844SAndroid Build Coastguard Worker NATServer::~NATServer() {
147*d9f75844SAndroid Build Coastguard Worker   for (InternalMap::iterator iter = int_map_->begin(); iter != int_map_->end();
148*d9f75844SAndroid Build Coastguard Worker        iter++)
149*d9f75844SAndroid Build Coastguard Worker     delete iter->second;
150*d9f75844SAndroid Build Coastguard Worker 
151*d9f75844SAndroid Build Coastguard Worker   delete nat_;
152*d9f75844SAndroid Build Coastguard Worker   delete udp_server_socket_;
153*d9f75844SAndroid Build Coastguard Worker   delete tcp_proxy_server_;
154*d9f75844SAndroid Build Coastguard Worker   delete int_map_;
155*d9f75844SAndroid Build Coastguard Worker   delete ext_map_;
156*d9f75844SAndroid Build Coastguard Worker }
157*d9f75844SAndroid Build Coastguard Worker 
OnInternalUDPPacket(AsyncPacketSocket * socket,const char * buf,size_t size,const SocketAddress & addr,const int64_t &)158*d9f75844SAndroid Build Coastguard Worker void NATServer::OnInternalUDPPacket(AsyncPacketSocket* socket,
159*d9f75844SAndroid Build Coastguard Worker                                     const char* buf,
160*d9f75844SAndroid Build Coastguard Worker                                     size_t size,
161*d9f75844SAndroid Build Coastguard Worker                                     const SocketAddress& addr,
162*d9f75844SAndroid Build Coastguard Worker                                     const int64_t& /* packet_time_us */) {
163*d9f75844SAndroid Build Coastguard Worker   // Read the intended destination from the wire.
164*d9f75844SAndroid Build Coastguard Worker   SocketAddress dest_addr;
165*d9f75844SAndroid Build Coastguard Worker   size_t length = UnpackAddressFromNAT(buf, size, &dest_addr);
166*d9f75844SAndroid Build Coastguard Worker 
167*d9f75844SAndroid Build Coastguard Worker   // Find the translation for these addresses (allocating one if necessary).
168*d9f75844SAndroid Build Coastguard Worker   SocketAddressPair route(addr, dest_addr);
169*d9f75844SAndroid Build Coastguard Worker   InternalMap::iterator iter = int_map_->find(route);
170*d9f75844SAndroid Build Coastguard Worker   if (iter == int_map_->end()) {
171*d9f75844SAndroid Build Coastguard Worker     Translate(route);
172*d9f75844SAndroid Build Coastguard Worker     iter = int_map_->find(route);
173*d9f75844SAndroid Build Coastguard Worker   }
174*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(iter != int_map_->end());
175*d9f75844SAndroid Build Coastguard Worker 
176*d9f75844SAndroid Build Coastguard Worker   // Allow the destination to send packets back to the source.
177*d9f75844SAndroid Build Coastguard Worker   iter->second->AllowlistInsert(dest_addr);
178*d9f75844SAndroid Build Coastguard Worker 
179*d9f75844SAndroid Build Coastguard Worker   // Send the packet to its intended destination.
180*d9f75844SAndroid Build Coastguard Worker   rtc::PacketOptions options;
181*d9f75844SAndroid Build Coastguard Worker   iter->second->socket->SendTo(buf + length, size - length, dest_addr, options);
182*d9f75844SAndroid Build Coastguard Worker }
183*d9f75844SAndroid Build Coastguard Worker 
OnExternalUDPPacket(AsyncPacketSocket * socket,const char * buf,size_t size,const SocketAddress & remote_addr,const int64_t &)184*d9f75844SAndroid Build Coastguard Worker void NATServer::OnExternalUDPPacket(AsyncPacketSocket* socket,
185*d9f75844SAndroid Build Coastguard Worker                                     const char* buf,
186*d9f75844SAndroid Build Coastguard Worker                                     size_t size,
187*d9f75844SAndroid Build Coastguard Worker                                     const SocketAddress& remote_addr,
188*d9f75844SAndroid Build Coastguard Worker                                     const int64_t& /* packet_time_us */) {
189*d9f75844SAndroid Build Coastguard Worker   SocketAddress local_addr = socket->GetLocalAddress();
190*d9f75844SAndroid Build Coastguard Worker 
191*d9f75844SAndroid Build Coastguard Worker   // Find the translation for this addresses.
192*d9f75844SAndroid Build Coastguard Worker   ExternalMap::iterator iter = ext_map_->find(local_addr);
193*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(iter != ext_map_->end());
194*d9f75844SAndroid Build Coastguard Worker 
195*d9f75844SAndroid Build Coastguard Worker   // Allow the NAT to reject this packet.
196*d9f75844SAndroid Build Coastguard Worker   if (ShouldFilterOut(iter->second, remote_addr)) {
197*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Packet from " << remote_addr.ToSensitiveString()
198*d9f75844SAndroid Build Coastguard Worker                      << " was filtered out by the NAT.";
199*d9f75844SAndroid Build Coastguard Worker     return;
200*d9f75844SAndroid Build Coastguard Worker   }
201*d9f75844SAndroid Build Coastguard Worker 
202*d9f75844SAndroid Build Coastguard Worker   // Forward this packet to the internal address.
203*d9f75844SAndroid Build Coastguard Worker   // First prepend the address in a quasi-STUN format.
204*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
205*d9f75844SAndroid Build Coastguard Worker   size_t addrlength = PackAddressForNAT(
206*d9f75844SAndroid Build Coastguard Worker       real_buf.get(), size + kNATEncodedIPv6AddressSize, remote_addr);
207*d9f75844SAndroid Build Coastguard Worker   // Copy the data part after the address.
208*d9f75844SAndroid Build Coastguard Worker   rtc::PacketOptions options;
209*d9f75844SAndroid Build Coastguard Worker   memcpy(real_buf.get() + addrlength, buf, size);
210*d9f75844SAndroid Build Coastguard Worker   udp_server_socket_->SendTo(real_buf.get(), size + addrlength,
211*d9f75844SAndroid Build Coastguard Worker                              iter->second->route.source(), options);
212*d9f75844SAndroid Build Coastguard Worker }
213*d9f75844SAndroid Build Coastguard Worker 
Translate(const SocketAddressPair & route)214*d9f75844SAndroid Build Coastguard Worker void NATServer::Translate(const SocketAddressPair& route) {
215*d9f75844SAndroid Build Coastguard Worker   AsyncUDPSocket* socket = AsyncUDPSocket::Create(external_, external_ip_);
216*d9f75844SAndroid Build Coastguard Worker 
217*d9f75844SAndroid Build Coastguard Worker   if (!socket) {
218*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Couldn't find a free port!";
219*d9f75844SAndroid Build Coastguard Worker     return;
220*d9f75844SAndroid Build Coastguard Worker   }
221*d9f75844SAndroid Build Coastguard Worker 
222*d9f75844SAndroid Build Coastguard Worker   TransEntry* entry = new TransEntry(route, socket, nat_);
223*d9f75844SAndroid Build Coastguard Worker   (*int_map_)[route] = entry;
224*d9f75844SAndroid Build Coastguard Worker   (*ext_map_)[socket->GetLocalAddress()] = entry;
225*d9f75844SAndroid Build Coastguard Worker   socket->SignalReadPacket.connect(this, &NATServer::OnExternalUDPPacket);
226*d9f75844SAndroid Build Coastguard Worker }
227*d9f75844SAndroid Build Coastguard Worker 
ShouldFilterOut(TransEntry * entry,const SocketAddress & ext_addr)228*d9f75844SAndroid Build Coastguard Worker bool NATServer::ShouldFilterOut(TransEntry* entry,
229*d9f75844SAndroid Build Coastguard Worker                                 const SocketAddress& ext_addr) {
230*d9f75844SAndroid Build Coastguard Worker   return entry->AllowlistContains(ext_addr);
231*d9f75844SAndroid Build Coastguard Worker }
232*d9f75844SAndroid Build Coastguard Worker 
TransEntry(const SocketAddressPair & r,AsyncUDPSocket * s,NAT * nat)233*d9f75844SAndroid Build Coastguard Worker NATServer::TransEntry::TransEntry(const SocketAddressPair& r,
234*d9f75844SAndroid Build Coastguard Worker                                   AsyncUDPSocket* s,
235*d9f75844SAndroid Build Coastguard Worker                                   NAT* nat)
236*d9f75844SAndroid Build Coastguard Worker     : route(r), socket(s) {
237*d9f75844SAndroid Build Coastguard Worker   allowlist = new AddressSet(AddrCmp(nat));
238*d9f75844SAndroid Build Coastguard Worker }
239*d9f75844SAndroid Build Coastguard Worker 
~TransEntry()240*d9f75844SAndroid Build Coastguard Worker NATServer::TransEntry::~TransEntry() {
241*d9f75844SAndroid Build Coastguard Worker   delete allowlist;
242*d9f75844SAndroid Build Coastguard Worker   delete socket;
243*d9f75844SAndroid Build Coastguard Worker }
244*d9f75844SAndroid Build Coastguard Worker 
AllowlistInsert(const SocketAddress & addr)245*d9f75844SAndroid Build Coastguard Worker void NATServer::TransEntry::AllowlistInsert(const SocketAddress& addr) {
246*d9f75844SAndroid Build Coastguard Worker   webrtc::MutexLock lock(&mutex_);
247*d9f75844SAndroid Build Coastguard Worker   allowlist->insert(addr);
248*d9f75844SAndroid Build Coastguard Worker }
249*d9f75844SAndroid Build Coastguard Worker 
AllowlistContains(const SocketAddress & ext_addr)250*d9f75844SAndroid Build Coastguard Worker bool NATServer::TransEntry::AllowlistContains(const SocketAddress& ext_addr) {
251*d9f75844SAndroid Build Coastguard Worker   webrtc::MutexLock lock(&mutex_);
252*d9f75844SAndroid Build Coastguard Worker   return allowlist->find(ext_addr) == allowlist->end();
253*d9f75844SAndroid Build Coastguard Worker }
254*d9f75844SAndroid Build Coastguard Worker 
255*d9f75844SAndroid Build Coastguard Worker }  // namespace rtc
256