blob: 323a787ee038adc7f8e5fd3ba90c6600c37740ec [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "rtc_base/nat_server.h"
12
jbauch555604a2016-04-26 03:13:22 -070013#include <memory>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "rtc_base/checks.h"
16#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "rtc_base/nat_socket_factory.h"
18#include "rtc_base/socket_adapters.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019
20namespace rtc {
21
Yves Gerey665174f2018-06-19 15:03:05 +020022RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023
24size_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
Yves Gerey665174f2018-06-19 15:03:05 +020031bool RouteCmp::operator()(const SocketAddressPair& r1,
32 const SocketAddressPair& r2) const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000033 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
44AddrCmp::AddrCmp(NAT* nat)
Yves Gerey665174f2018-06-19 15:03:05 +020045 : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000046
47size_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
Yves Gerey665174f2018-06-19 15:03:05 +020056bool AddrCmp::operator()(const SocketAddress& a1,
57 const SocketAddress& a2) const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000058 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
deadbeefc5d0d952015-07-16 10:22:21 -070069// Proxy socket that will capture the external destination address intended for
70// a TCP connection to the NAT server.
71class NATProxyServerSocket : public AsyncProxyServerSocket {
72 public:
73 NATProxyServerSocket(AsyncSocket* socket)
74 : AsyncProxyServerSocket(socket, kNATEncodedIPv6AddressSize) {
75 BufferInput(true);
76 }
77
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:
84 void ProcessInput(char* data, size_t* len) override {
85 if (*len < 2) {
86 return;
87 }
88
89 int family = data[1];
nisseede5da42017-01-12 05:15:36 -080090 RTC_DCHECK(family == AF_INET || family == AF_INET6);
deadbeefc5d0d952015-07-16 10:22:21 -070091 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 }
deadbeefc5d0d952015-07-16 10:22:21 -0700111};
112
113class NATProxyServer : public ProxyServer {
114 public:
Yves Gerey665174f2018-06-19 15:03:05 +0200115 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) {}
deadbeefc5d0d952015-07-16 10:22:21 -0700120
121 protected:
122 AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) override {
123 return new NATProxyServerSocket(socket);
124 }
125};
126
Yves Gerey665174f2018-06-19 15:03:05 +0200127NATServer::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)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000133 : external_(external), external_ip_(external_ip.ipaddr(), 0) {
134 nat_ = NAT::Create(type);
135
deadbeefc5d0d952015-07-16 10:22:21 -0700136 udp_server_socket_ = AsyncUDPSocket::Create(internal, internal_udp_addr);
137 udp_server_socket_->SignalReadPacket.connect(this,
138 &NATServer::OnInternalUDPPacket);
Yves Gerey665174f2018-06-19 15:03:05 +0200139 tcp_proxy_server_ =
140 new NATProxyServer(internal, internal_tcp_addr, external, external_ip);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141
142 int_map_ = new InternalMap(RouteCmp(nat_));
143 ext_map_ = new ExternalMap();
144}
145
146NATServer::~NATServer() {
Yves Gerey665174f2018-06-19 15:03:05 +0200147 for (InternalMap::iterator iter = int_map_->begin(); iter != int_map_->end();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148 iter++)
149 delete iter->second;
150
151 delete nat_;
deadbeefc5d0d952015-07-16 10:22:21 -0700152 delete udp_server_socket_;
153 delete tcp_proxy_server_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154 delete int_map_;
155 delete ext_map_;
156}
157
Yves Gerey665174f2018-06-19 15:03:05 +0200158void NATServer::OnInternalUDPPacket(AsyncPacketSocket* socket,
159 const char* buf,
160 size_t size,
161 const SocketAddress& addr,
Niels Möllere6933812018-11-05 13:01:41 +0100162 const int64_t& /* packet_time_us */) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000163 // 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 }
nisseede5da42017-01-12 05:15:36 -0800174 RTC_DCHECK(iter != int_map_->end());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000175
176 // Allow the destination to send packets back to the source.
177 iter->second->WhitelistInsert(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
Yves Gerey665174f2018-06-19 15:03:05 +0200184void NATServer::OnExternalUDPPacket(AsyncPacketSocket* socket,
185 const char* buf,
186 size_t size,
187 const SocketAddress& remote_addr,
Niels Möllere6933812018-11-05 13:01:41 +0100188 const int64_t& /* packet_time_us */) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000189 SocketAddress local_addr = socket->GetLocalAddress();
190
191 // Find the translation for this addresses.
192 ExternalMap::iterator iter = ext_map_->find(local_addr);
nisseede5da42017-01-12 05:15:36 -0800193 RTC_DCHECK(iter != ext_map_->end());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000194
195 // Allow the NAT to reject this packet.
196 if (ShouldFilterOut(iter->second, remote_addr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100197 RTC_LOG(LS_INFO) << "Packet from " << remote_addr.ToSensitiveString()
198 << " was filtered out by the NAT.";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000199 return;
200 }
201
202 // Forward this packet to the internal address.
203 // First prepend the address in a quasi-STUN format.
jbauch555604a2016-04-26 03:13:22 -0700204 std::unique_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
Yves Gerey665174f2018-06-19 15:03:05 +0200205 size_t addrlength = PackAddressForNAT(
206 real_buf.get(), size + kNATEncodedIPv6AddressSize, remote_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000207 // Copy the data part after the address.
208 rtc::PacketOptions options;
209 memcpy(real_buf.get() + addrlength, buf, size);
deadbeefc5d0d952015-07-16 10:22:21 -0700210 udp_server_socket_->SendTo(real_buf.get(), size + addrlength,
211 iter->second->route.source(), options);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000212}
213
214void NATServer::Translate(const SocketAddressPair& route) {
215 AsyncUDPSocket* socket = AsyncUDPSocket::Create(external_, external_ip_);
216
217 if (!socket) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100218 RTC_LOG(LS_ERROR) << "Couldn't find a free port!";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000219 return;
220 }
221
222 TransEntry* entry = new TransEntry(route, socket, nat_);
223 (*int_map_)[route] = entry;
224 (*ext_map_)[socket->GetLocalAddress()] = entry;
deadbeefc5d0d952015-07-16 10:22:21 -0700225 socket->SignalReadPacket.connect(this, &NATServer::OnExternalUDPPacket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000226}
227
228bool NATServer::ShouldFilterOut(TransEntry* entry,
229 const SocketAddress& ext_addr) {
230 return entry->WhitelistContains(ext_addr);
231}
232
Yves Gerey665174f2018-06-19 15:03:05 +0200233NATServer::TransEntry::TransEntry(const SocketAddressPair& r,
234 AsyncUDPSocket* s,
235 NAT* nat)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236 : route(r), socket(s) {
237 whitelist = new AddressSet(AddrCmp(nat));
238}
239
240NATServer::TransEntry::~TransEntry() {
241 delete whitelist;
242 delete socket;
243}
244
245void NATServer::TransEntry::WhitelistInsert(const SocketAddress& addr) {
246 CritScope cs(&crit_);
247 whitelist->insert(addr);
248}
249
250bool NATServer::TransEntry::WhitelistContains(const SocketAddress& ext_addr) {
251 CritScope cs(&crit_);
252 return whitelist->find(ext_addr) == whitelist->end();
253}
254
255} // namespace rtc