OLD | NEW |
| (Empty) |
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 <memory> | |
12 | |
13 #include "webrtc/base/checks.h" | |
14 #include "webrtc/base/natsocketfactory.h" | |
15 #include "webrtc/base/natserver.h" | |
16 #include "webrtc/base/logging.h" | |
17 #include "webrtc/base/socketadapters.h" | |
18 | |
19 namespace rtc { | |
20 | |
21 RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) { | |
22 } | |
23 | |
24 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 | |
31 bool RouteCmp::operator()( | |
32 const SocketAddressPair& r1, 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 | |
44 AddrCmp::AddrCmp(NAT* nat) | |
45 : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) { | |
46 } | |
47 | |
48 size_t AddrCmp::operator()(const SocketAddress& a) const { | |
49 size_t h = 0; | |
50 if (use_ip) | |
51 h ^= HashIP(a.ipaddr()); | |
52 if (use_port) | |
53 h ^= a.port() | (a.port() << 16); | |
54 return h; | |
55 } | |
56 | |
57 bool AddrCmp::operator()( | |
58 const SocketAddress& a1, const SocketAddress& a2) const { | |
59 if (use_ip && (a1.ipaddr() < a2.ipaddr())) | |
60 return true; | |
61 if (use_ip && (a2.ipaddr() < a1.ipaddr())) | |
62 return false; | |
63 if (use_port && (a1.port() < a2.port())) | |
64 return true; | |
65 if (use_port && (a2.port() < a1.port())) | |
66 return false; | |
67 return false; | |
68 } | |
69 | |
70 // Proxy socket that will capture the external destination address intended for | |
71 // a TCP connection to the NAT server. | |
72 class NATProxyServerSocket : public AsyncProxyServerSocket { | |
73 public: | |
74 NATProxyServerSocket(AsyncSocket* socket) | |
75 : AsyncProxyServerSocket(socket, kNATEncodedIPv6AddressSize) { | |
76 BufferInput(true); | |
77 } | |
78 | |
79 void SendConnectResult(int err, const SocketAddress& addr) override { | |
80 char code = err ? 1 : 0; | |
81 BufferedReadAdapter::DirectSend(&code, sizeof(char)); | |
82 } | |
83 | |
84 protected: | |
85 void ProcessInput(char* data, size_t* len) override { | |
86 if (*len < 2) { | |
87 return; | |
88 } | |
89 | |
90 int family = data[1]; | |
91 RTC_DCHECK(family == AF_INET || family == AF_INET6); | |
92 if ((family == AF_INET && *len < kNATEncodedIPv4AddressSize) || | |
93 (family == AF_INET6 && *len < kNATEncodedIPv6AddressSize)) { | |
94 return; | |
95 } | |
96 | |
97 SocketAddress dest_addr; | |
98 size_t address_length = UnpackAddressFromNAT(data, *len, &dest_addr); | |
99 | |
100 *len -= address_length; | |
101 if (*len > 0) { | |
102 memmove(data, data + address_length, *len); | |
103 } | |
104 | |
105 bool remainder = (*len > 0); | |
106 BufferInput(false); | |
107 SignalConnectRequest(this, dest_addr); | |
108 if (remainder) { | |
109 SignalReadEvent(this); | |
110 } | |
111 } | |
112 | |
113 }; | |
114 | |
115 class NATProxyServer : public ProxyServer { | |
116 public: | |
117 NATProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr, | |
118 SocketFactory* ext_factory, const SocketAddress& ext_ip) | |
119 : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) { | |
120 } | |
121 | |
122 protected: | |
123 AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) override { | |
124 return new NATProxyServerSocket(socket); | |
125 } | |
126 }; | |
127 | |
128 NATServer::NATServer( | |
129 NATType type, SocketFactory* internal, | |
130 const SocketAddress& internal_udp_addr, | |
131 const SocketAddress& internal_tcp_addr, | |
132 SocketFactory* external, 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_ = new NATProxyServer(internal, internal_tcp_addr, external, | |
140 external_ip); | |
141 | |
142 int_map_ = new InternalMap(RouteCmp(nat_)); | |
143 ext_map_ = new ExternalMap(); | |
144 } | |
145 | |
146 NATServer::~NATServer() { | |
147 for (InternalMap::iterator iter = int_map_->begin(); | |
148 iter != int_map_->end(); | |
149 iter++) | |
150 delete iter->second; | |
151 | |
152 delete nat_; | |
153 delete udp_server_socket_; | |
154 delete tcp_proxy_server_; | |
155 delete int_map_; | |
156 delete ext_map_; | |
157 } | |
158 | |
159 void NATServer::OnInternalUDPPacket( | |
160 AsyncPacketSocket* socket, const char* buf, size_t size, | |
161 const SocketAddress& addr, const PacketTime& packet_time) { | |
162 // 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 } | |
173 RTC_DCHECK(iter != int_map_->end()); | |
174 | |
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 | |
183 void NATServer::OnExternalUDPPacket( | |
184 AsyncPacketSocket* socket, const char* buf, size_t size, | |
185 const SocketAddress& remote_addr, const PacketTime& packet_time) { | |
186 SocketAddress local_addr = socket->GetLocalAddress(); | |
187 | |
188 // Find the translation for this addresses. | |
189 ExternalMap::iterator iter = ext_map_->find(local_addr); | |
190 RTC_DCHECK(iter != ext_map_->end()); | |
191 | |
192 // Allow the NAT to reject this packet. | |
193 if (ShouldFilterOut(iter->second, remote_addr)) { | |
194 LOG(LS_INFO) << "Packet from " << remote_addr.ToSensitiveString() | |
195 << " was filtered out by the NAT."; | |
196 return; | |
197 } | |
198 | |
199 // Forward this packet to the internal address. | |
200 // First prepend the address in a quasi-STUN format. | |
201 std::unique_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]); | |
202 size_t addrlength = PackAddressForNAT(real_buf.get(), | |
203 size + kNATEncodedIPv6AddressSize, | |
204 remote_addr); | |
205 // Copy the data part after the address. | |
206 rtc::PacketOptions options; | |
207 memcpy(real_buf.get() + addrlength, buf, size); | |
208 udp_server_socket_->SendTo(real_buf.get(), size + addrlength, | |
209 iter->second->route.source(), options); | |
210 } | |
211 | |
212 void NATServer::Translate(const SocketAddressPair& route) { | |
213 AsyncUDPSocket* socket = AsyncUDPSocket::Create(external_, external_ip_); | |
214 | |
215 if (!socket) { | |
216 LOG(LS_ERROR) << "Couldn't find a free port!"; | |
217 return; | |
218 } | |
219 | |
220 TransEntry* entry = new TransEntry(route, socket, nat_); | |
221 (*int_map_)[route] = entry; | |
222 (*ext_map_)[socket->GetLocalAddress()] = entry; | |
223 socket->SignalReadPacket.connect(this, &NATServer::OnExternalUDPPacket); | |
224 } | |
225 | |
226 bool NATServer::ShouldFilterOut(TransEntry* entry, | |
227 const SocketAddress& ext_addr) { | |
228 return entry->WhitelistContains(ext_addr); | |
229 } | |
230 | |
231 NATServer::TransEntry::TransEntry( | |
232 const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat) | |
233 : route(r), socket(s) { | |
234 whitelist = new AddressSet(AddrCmp(nat)); | |
235 } | |
236 | |
237 NATServer::TransEntry::~TransEntry() { | |
238 delete whitelist; | |
239 delete socket; | |
240 } | |
241 | |
242 void NATServer::TransEntry::WhitelistInsert(const SocketAddress& addr) { | |
243 CritScope cs(&crit_); | |
244 whitelist->insert(addr); | |
245 } | |
246 | |
247 bool NATServer::TransEntry::WhitelistContains(const SocketAddress& ext_addr) { | |
248 CritScope cs(&crit_); | |
249 return whitelist->find(ext_addr) == whitelist->end(); | |
250 } | |
251 | |
252 } // namespace rtc | |
OLD | NEW |