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