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