blob: b005ecae7a0d1a5bf6a0a6a4582d10a1c78d9a68 [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
jbauch555604a2016-04-26 03:13:22 -070011#include <memory>
12
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "rtc_base/checks.h"
14#include "rtc_base/logging.h"
15#include "rtc_base/natserver.h"
16#include "rtc_base/natsocketfactory.h"
17#include "rtc_base/socketadapters.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018
19namespace rtc {
20
Yves Gerey665174f2018-06-19 15:03:05 +020021RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000022
23size_t RouteCmp::operator()(const SocketAddressPair& r) const {
24 size_t h = r.source().Hash();
25 if (symmetric)
26 h ^= r.destination().Hash();
27 return h;
28}
29
Yves Gerey665174f2018-06-19 15:03:05 +020030bool RouteCmp::operator()(const SocketAddressPair& r1,
31 const SocketAddressPair& r2) const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000032 if (r1.source() < r2.source())
33 return true;
34 if (r2.source() < r1.source())
35 return false;
36 if (symmetric && (r1.destination() < r2.destination()))
37 return true;
38 if (symmetric && (r2.destination() < r1.destination()))
39 return false;
40 return false;
41}
42
43AddrCmp::AddrCmp(NAT* nat)
Yves Gerey665174f2018-06-19 15:03:05 +020044 : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000045
46size_t AddrCmp::operator()(const SocketAddress& a) const {
47 size_t h = 0;
48 if (use_ip)
49 h ^= HashIP(a.ipaddr());
50 if (use_port)
51 h ^= a.port() | (a.port() << 16);
52 return h;
53}
54
Yves Gerey665174f2018-06-19 15:03:05 +020055bool AddrCmp::operator()(const SocketAddress& a1,
56 const SocketAddress& a2) const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057 if (use_ip && (a1.ipaddr() < a2.ipaddr()))
58 return true;
59 if (use_ip && (a2.ipaddr() < a1.ipaddr()))
60 return false;
61 if (use_port && (a1.port() < a2.port()))
62 return true;
63 if (use_port && (a2.port() < a1.port()))
64 return false;
65 return false;
66}
67
deadbeefc5d0d952015-07-16 10:22:21 -070068// Proxy socket that will capture the external destination address intended for
69// a TCP connection to the NAT server.
70class NATProxyServerSocket : public AsyncProxyServerSocket {
71 public:
72 NATProxyServerSocket(AsyncSocket* socket)
73 : AsyncProxyServerSocket(socket, kNATEncodedIPv6AddressSize) {
74 BufferInput(true);
75 }
76
77 void SendConnectResult(int err, const SocketAddress& addr) override {
78 char code = err ? 1 : 0;
79 BufferedReadAdapter::DirectSend(&code, sizeof(char));
80 }
81
82 protected:
83 void ProcessInput(char* data, size_t* len) override {
84 if (*len < 2) {
85 return;
86 }
87
88 int family = data[1];
nisseede5da42017-01-12 05:15:36 -080089 RTC_DCHECK(family == AF_INET || family == AF_INET6);
deadbeefc5d0d952015-07-16 10:22:21 -070090 if ((family == AF_INET && *len < kNATEncodedIPv4AddressSize) ||
91 (family == AF_INET6 && *len < kNATEncodedIPv6AddressSize)) {
92 return;
93 }
94
95 SocketAddress dest_addr;
96 size_t address_length = UnpackAddressFromNAT(data, *len, &dest_addr);
97
98 *len -= address_length;
99 if (*len > 0) {
100 memmove(data, data + address_length, *len);
101 }
102
103 bool remainder = (*len > 0);
104 BufferInput(false);
105 SignalConnectRequest(this, dest_addr);
106 if (remainder) {
107 SignalReadEvent(this);
108 }
109 }
deadbeefc5d0d952015-07-16 10:22:21 -0700110};
111
112class NATProxyServer : public ProxyServer {
113 public:
Yves Gerey665174f2018-06-19 15:03:05 +0200114 NATProxyServer(SocketFactory* int_factory,
115 const SocketAddress& int_addr,
116 SocketFactory* ext_factory,
117 const SocketAddress& ext_ip)
118 : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {}
deadbeefc5d0d952015-07-16 10:22:21 -0700119
120 protected:
121 AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) override {
122 return new NATProxyServerSocket(socket);
123 }
124};
125
Yves Gerey665174f2018-06-19 15:03:05 +0200126NATServer::NATServer(NATType type,
127 SocketFactory* internal,
128 const SocketAddress& internal_udp_addr,
129 const SocketAddress& internal_tcp_addr,
130 SocketFactory* external,
131 const SocketAddress& external_ip)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000132 : external_(external), external_ip_(external_ip.ipaddr(), 0) {
133 nat_ = NAT::Create(type);
134
deadbeefc5d0d952015-07-16 10:22:21 -0700135 udp_server_socket_ = AsyncUDPSocket::Create(internal, internal_udp_addr);
136 udp_server_socket_->SignalReadPacket.connect(this,
137 &NATServer::OnInternalUDPPacket);
Yves Gerey665174f2018-06-19 15:03:05 +0200138 tcp_proxy_server_ =
139 new NATProxyServer(internal, internal_tcp_addr, external, external_ip);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000140
141 int_map_ = new InternalMap(RouteCmp(nat_));
142 ext_map_ = new ExternalMap();
143}
144
145NATServer::~NATServer() {
Yves Gerey665174f2018-06-19 15:03:05 +0200146 for (InternalMap::iterator iter = int_map_->begin(); iter != int_map_->end();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000147 iter++)
148 delete iter->second;
149
150 delete nat_;
deadbeefc5d0d952015-07-16 10:22:21 -0700151 delete udp_server_socket_;
152 delete tcp_proxy_server_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153 delete int_map_;
154 delete ext_map_;
155}
156
Yves Gerey665174f2018-06-19 15:03:05 +0200157void NATServer::OnInternalUDPPacket(AsyncPacketSocket* socket,
158 const char* buf,
159 size_t size,
160 const SocketAddress& addr,
Niels Möllere6933812018-11-05 13:01:41 +0100161 const int64_t& /* packet_time_us */) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000162 // Read the intended destination from the wire.
163 SocketAddress dest_addr;
164 size_t length = UnpackAddressFromNAT(buf, size, &dest_addr);
165
166 // Find the translation for these addresses (allocating one if necessary).
167 SocketAddressPair route(addr, dest_addr);
168 InternalMap::iterator iter = int_map_->find(route);
169 if (iter == int_map_->end()) {
170 Translate(route);
171 iter = int_map_->find(route);
172 }
nisseede5da42017-01-12 05:15:36 -0800173 RTC_DCHECK(iter != int_map_->end());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000174
175 // Allow the destination to send packets back to the source.
176 iter->second->WhitelistInsert(dest_addr);
177
178 // Send the packet to its intended destination.
179 rtc::PacketOptions options;
180 iter->second->socket->SendTo(buf + length, size - length, dest_addr, options);
181}
182
Yves Gerey665174f2018-06-19 15:03:05 +0200183void NATServer::OnExternalUDPPacket(AsyncPacketSocket* socket,
184 const char* buf,
185 size_t size,
186 const SocketAddress& remote_addr,
Niels Möllere6933812018-11-05 13:01:41 +0100187 const int64_t& /* packet_time_us */) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188 SocketAddress local_addr = socket->GetLocalAddress();
189
190 // Find the translation for this addresses.
191 ExternalMap::iterator iter = ext_map_->find(local_addr);
nisseede5da42017-01-12 05:15:36 -0800192 RTC_DCHECK(iter != ext_map_->end());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000193
194 // Allow the NAT to reject this packet.
195 if (ShouldFilterOut(iter->second, remote_addr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100196 RTC_LOG(LS_INFO) << "Packet from " << remote_addr.ToSensitiveString()
197 << " was filtered out by the NAT.";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000198 return;
199 }
200
201 // Forward this packet to the internal address.
202 // First prepend the address in a quasi-STUN format.
jbauch555604a2016-04-26 03:13:22 -0700203 std::unique_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
Yves Gerey665174f2018-06-19 15:03:05 +0200204 size_t addrlength = PackAddressForNAT(
205 real_buf.get(), size + kNATEncodedIPv6AddressSize, remote_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000206 // Copy the data part after the address.
207 rtc::PacketOptions options;
208 memcpy(real_buf.get() + addrlength, buf, size);
deadbeefc5d0d952015-07-16 10:22:21 -0700209 udp_server_socket_->SendTo(real_buf.get(), size + addrlength,
210 iter->second->route.source(), options);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211}
212
213void NATServer::Translate(const SocketAddressPair& route) {
214 AsyncUDPSocket* socket = AsyncUDPSocket::Create(external_, external_ip_);
215
216 if (!socket) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100217 RTC_LOG(LS_ERROR) << "Couldn't find a free port!";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000218 return;
219 }
220
221 TransEntry* entry = new TransEntry(route, socket, nat_);
222 (*int_map_)[route] = entry;
223 (*ext_map_)[socket->GetLocalAddress()] = entry;
deadbeefc5d0d952015-07-16 10:22:21 -0700224 socket->SignalReadPacket.connect(this, &NATServer::OnExternalUDPPacket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225}
226
227bool NATServer::ShouldFilterOut(TransEntry* entry,
228 const SocketAddress& ext_addr) {
229 return entry->WhitelistContains(ext_addr);
230}
231
Yves Gerey665174f2018-06-19 15:03:05 +0200232NATServer::TransEntry::TransEntry(const SocketAddressPair& r,
233 AsyncUDPSocket* s,
234 NAT* nat)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000235 : route(r), socket(s) {
236 whitelist = new AddressSet(AddrCmp(nat));
237}
238
239NATServer::TransEntry::~TransEntry() {
240 delete whitelist;
241 delete socket;
242}
243
244void NATServer::TransEntry::WhitelistInsert(const SocketAddress& addr) {
245 CritScope cs(&crit_);
246 whitelist->insert(addr);
247}
248
249bool NATServer::TransEntry::WhitelistContains(const SocketAddress& ext_addr) {
250 CritScope cs(&crit_);
251 return whitelist->find(ext_addr) == whitelist->end();
252}
253
254} // namespace rtc