blob: 36b93274178de78e92de9c8e9c4114d22e880606 [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
11#include <string>
12
13#include "webrtc/base/gunit.h"
14#include "webrtc/base/logging.h"
15#include "webrtc/base/natserver.h"
16#include "webrtc/base/natsocketfactory.h"
17#include "webrtc/base/nethelpers.h"
18#include "webrtc/base/network.h"
19#include "webrtc/base/physicalsocketserver.h"
20#include "webrtc/base/testclient.h"
21#include "webrtc/base/virtualsocketserver.h"
henrike@webrtc.orgfded02c2014-09-19 13:10:10 +000022#include "webrtc/test/testsupport/gtest_disable.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023
24using namespace rtc;
25
26bool CheckReceive(
27 TestClient* client, bool should_receive, const char* buf, size_t size) {
28 return (should_receive) ?
29 client->CheckNextPacket(buf, size, 0) :
30 client->CheckNoPacket();
31}
32
33TestClient* CreateTestClient(
34 SocketFactory* factory, const SocketAddress& local_addr) {
35 AsyncUDPSocket* socket = AsyncUDPSocket::Create(factory, local_addr);
36 return new TestClient(socket);
37}
38
39// Tests that when sending from internal_addr to external_addrs through the
40// NAT type specified by nat_type, all external addrs receive the sent packet
41// and, if exp_same is true, all use the same mapped-address on the NAT.
42void TestSend(
43 SocketServer* internal, const SocketAddress& internal_addr,
44 SocketServer* external, const SocketAddress external_addrs[4],
45 NATType nat_type, bool exp_same) {
46 Thread th_int(internal);
47 Thread th_ext(external);
48
49 SocketAddress server_addr = internal_addr;
50 server_addr.SetPort(0); // Auto-select a port
51 NATServer* nat = new NATServer(
52 nat_type, internal, server_addr, external, external_addrs[0]);
53 NATSocketFactory* natsf = new NATSocketFactory(internal,
54 nat->internal_address());
55
56 TestClient* in = CreateTestClient(natsf, internal_addr);
57 TestClient* out[4];
58 for (int i = 0; i < 4; i++)
59 out[i] = CreateTestClient(external, external_addrs[i]);
60
61 th_int.Start();
62 th_ext.Start();
63
64 const char* buf = "filter_test";
65 size_t len = strlen(buf);
66
67 in->SendTo(buf, len, out[0]->address());
68 SocketAddress trans_addr;
69 EXPECT_TRUE(out[0]->CheckNextPacket(buf, len, &trans_addr));
70
71 for (int i = 1; i < 4; i++) {
72 in->SendTo(buf, len, out[i]->address());
73 SocketAddress trans_addr2;
74 EXPECT_TRUE(out[i]->CheckNextPacket(buf, len, &trans_addr2));
75 bool are_same = (trans_addr == trans_addr2);
76 ASSERT_EQ(are_same, exp_same) << "same translated address";
77 ASSERT_NE(AF_UNSPEC, trans_addr.family());
78 ASSERT_NE(AF_UNSPEC, trans_addr2.family());
79 }
80
81 th_int.Stop();
82 th_ext.Stop();
83
84 delete nat;
85 delete natsf;
86 delete in;
87 for (int i = 0; i < 4; i++)
88 delete out[i];
89}
90
91// Tests that when sending from external_addrs to internal_addr, the packet
92// is delivered according to the specified filter_ip and filter_port rules.
93void TestRecv(
94 SocketServer* internal, const SocketAddress& internal_addr,
95 SocketServer* external, const SocketAddress external_addrs[4],
96 NATType nat_type, bool filter_ip, bool filter_port) {
97 Thread th_int(internal);
98 Thread th_ext(external);
99
100 SocketAddress server_addr = internal_addr;
101 server_addr.SetPort(0); // Auto-select a port
102 NATServer* nat = new NATServer(
103 nat_type, internal, server_addr, external, external_addrs[0]);
104 NATSocketFactory* natsf = new NATSocketFactory(internal,
105 nat->internal_address());
106
107 TestClient* in = CreateTestClient(natsf, internal_addr);
108 TestClient* out[4];
109 for (int i = 0; i < 4; i++)
110 out[i] = CreateTestClient(external, external_addrs[i]);
111
112 th_int.Start();
113 th_ext.Start();
114
115 const char* buf = "filter_test";
116 size_t len = strlen(buf);
117
118 in->SendTo(buf, len, out[0]->address());
119 SocketAddress trans_addr;
120 EXPECT_TRUE(out[0]->CheckNextPacket(buf, len, &trans_addr));
121
122 out[1]->SendTo(buf, len, trans_addr);
123 EXPECT_TRUE(CheckReceive(in, !filter_ip, buf, len));
124
125 out[2]->SendTo(buf, len, trans_addr);
126 EXPECT_TRUE(CheckReceive(in, !filter_port, buf, len));
127
128 out[3]->SendTo(buf, len, trans_addr);
129 EXPECT_TRUE(CheckReceive(in, !filter_ip && !filter_port, buf, len));
130
131 th_int.Stop();
132 th_ext.Stop();
133
134 delete nat;
135 delete natsf;
136 delete in;
137 for (int i = 0; i < 4; i++)
138 delete out[i];
139}
140
141// Tests that NATServer allocates bindings properly.
142void TestBindings(
143 SocketServer* internal, const SocketAddress& internal_addr,
144 SocketServer* external, const SocketAddress external_addrs[4]) {
145 TestSend(internal, internal_addr, external, external_addrs,
146 NAT_OPEN_CONE, true);
147 TestSend(internal, internal_addr, external, external_addrs,
148 NAT_ADDR_RESTRICTED, true);
149 TestSend(internal, internal_addr, external, external_addrs,
150 NAT_PORT_RESTRICTED, true);
151 TestSend(internal, internal_addr, external, external_addrs,
152 NAT_SYMMETRIC, false);
153}
154
155// Tests that NATServer filters packets properly.
156void TestFilters(
157 SocketServer* internal, const SocketAddress& internal_addr,
158 SocketServer* external, const SocketAddress external_addrs[4]) {
159 TestRecv(internal, internal_addr, external, external_addrs,
160 NAT_OPEN_CONE, false, false);
161 TestRecv(internal, internal_addr, external, external_addrs,
162 NAT_ADDR_RESTRICTED, true, false);
163 TestRecv(internal, internal_addr, external, external_addrs,
164 NAT_PORT_RESTRICTED, true, true);
165 TestRecv(internal, internal_addr, external, external_addrs,
166 NAT_SYMMETRIC, true, true);
167}
168
169bool TestConnectivity(const SocketAddress& src, const IPAddress& dst) {
170 // The physical NAT tests require connectivity to the selected ip from the
171 // internal address used for the NAT. Things like firewalls can break that, so
172 // check to see if it's worth even trying with this ip.
173 scoped_ptr<PhysicalSocketServer> pss(new PhysicalSocketServer());
174 scoped_ptr<AsyncSocket> client(pss->CreateAsyncSocket(src.family(),
175 SOCK_DGRAM));
176 scoped_ptr<AsyncSocket> server(pss->CreateAsyncSocket(src.family(),
177 SOCK_DGRAM));
178 if (client->Bind(SocketAddress(src.ipaddr(), 0)) != 0 ||
179 server->Bind(SocketAddress(dst, 0)) != 0) {
180 return false;
181 }
182 const char* buf = "hello other socket";
183 size_t len = strlen(buf);
184 int sent = client->SendTo(buf, len, server->GetLocalAddress());
185 SocketAddress addr;
186 const size_t kRecvBufSize = 64;
187 char recvbuf[kRecvBufSize];
188 Thread::Current()->SleepMs(100);
189 int received = server->RecvFrom(recvbuf, kRecvBufSize, &addr);
190 return received == sent && ::memcmp(buf, recvbuf, len) == 0;
191}
192
193void TestPhysicalInternal(const SocketAddress& int_addr) {
194 BasicNetworkManager network_manager;
195 network_manager.set_ipv6_enabled(true);
196 network_manager.StartUpdating();
197 // Process pending messages so the network list is updated.
198 Thread::Current()->ProcessMessages(0);
199
200 std::vector<Network*> networks;
201 network_manager.GetNetworks(&networks);
202 if (networks.empty()) {
203 LOG(LS_WARNING) << "Not enough network adapters for test.";
204 return;
205 }
206
207 SocketAddress ext_addr1(int_addr);
208 SocketAddress ext_addr2;
209 // Find an available IP with matching family. The test breaks if int_addr
210 // can't talk to ip, so check for connectivity as well.
211 for (std::vector<Network*>::iterator it = networks.begin();
212 it != networks.end(); ++it) {
guoweis@webrtc.org369a6372014-09-17 22:37:29 +0000213 const IPAddress& ip = (*it)->GetBestIP();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000214 if (ip.family() == int_addr.family() && TestConnectivity(int_addr, ip)) {
215 ext_addr2.SetIP(ip);
216 break;
217 }
218 }
219 if (ext_addr2.IsNil()) {
220 LOG(LS_WARNING) << "No available IP of same family as " << int_addr;
221 return;
222 }
223
224 LOG(LS_INFO) << "selected ip " << ext_addr2.ipaddr();
225
226 SocketAddress ext_addrs[4] = {
227 SocketAddress(ext_addr1),
228 SocketAddress(ext_addr2),
229 SocketAddress(ext_addr1),
230 SocketAddress(ext_addr2)
231 };
232
233 scoped_ptr<PhysicalSocketServer> int_pss(new PhysicalSocketServer());
234 scoped_ptr<PhysicalSocketServer> ext_pss(new PhysicalSocketServer());
235
236 TestBindings(int_pss.get(), int_addr, ext_pss.get(), ext_addrs);
237 TestFilters(int_pss.get(), int_addr, ext_pss.get(), ext_addrs);
238}
239
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000240TEST(NatTest, TestPhysicalIPv4) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000241 TestPhysicalInternal(SocketAddress("127.0.0.1", 0));
242}
243
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000244TEST(NatTest, TestPhysicalIPv6) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000245 if (HasIPv6Enabled()) {
246 TestPhysicalInternal(SocketAddress("::1", 0));
247 } else {
248 LOG(LS_WARNING) << "No IPv6, skipping";
249 }
250}
251
Guo-wei Shiehbe508a12015-04-06 12:48:47 -0700252namespace {
253
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000254class TestVirtualSocketServer : public VirtualSocketServer {
255 public:
256 explicit TestVirtualSocketServer(SocketServer* ss)
257 : VirtualSocketServer(ss),
258 ss_(ss) {}
259 // Expose this publicly
260 IPAddress GetNextIP(int af) { return VirtualSocketServer::GetNextIP(af); }
261
262 private:
263 scoped_ptr<SocketServer> ss_;
264};
265
Guo-wei Shiehbe508a12015-04-06 12:48:47 -0700266} // namespace
267
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000268void TestVirtualInternal(int family) {
269 scoped_ptr<TestVirtualSocketServer> int_vss(new TestVirtualSocketServer(
270 new PhysicalSocketServer()));
271 scoped_ptr<TestVirtualSocketServer> ext_vss(new TestVirtualSocketServer(
272 new PhysicalSocketServer()));
273
274 SocketAddress int_addr;
275 SocketAddress ext_addrs[4];
276 int_addr.SetIP(int_vss->GetNextIP(family));
277 ext_addrs[0].SetIP(ext_vss->GetNextIP(int_addr.family()));
278 ext_addrs[1].SetIP(ext_vss->GetNextIP(int_addr.family()));
279 ext_addrs[2].SetIP(ext_addrs[0].ipaddr());
280 ext_addrs[3].SetIP(ext_addrs[1].ipaddr());
281
282 TestBindings(int_vss.get(), int_addr, ext_vss.get(), ext_addrs);
283 TestFilters(int_vss.get(), int_addr, ext_vss.get(), ext_addrs);
284}
285
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000286TEST(NatTest, TestVirtualIPv4) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000287 TestVirtualInternal(AF_INET);
288}
289
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000290TEST(NatTest, TestVirtualIPv6) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000291 if (HasIPv6Enabled()) {
292 TestVirtualInternal(AF_INET6);
293 } else {
294 LOG(LS_WARNING) << "No IPv6, skipping";
295 }
296}
297
298// TODO: Finish this test
299class NatTcpTest : public testing::Test, public sigslot::has_slots<> {
300 public:
301 NatTcpTest() : connected_(false) {}
302 virtual void SetUp() {
303 int_vss_ = new TestVirtualSocketServer(new PhysicalSocketServer());
304 ext_vss_ = new TestVirtualSocketServer(new PhysicalSocketServer());
305 nat_ = new NATServer(NAT_OPEN_CONE, int_vss_, SocketAddress(),
306 ext_vss_, SocketAddress());
307 natsf_ = new NATSocketFactory(int_vss_, nat_->internal_address());
308 }
309 void OnConnectEvent(AsyncSocket* socket) {
310 connected_ = true;
311 }
312 void OnAcceptEvent(AsyncSocket* socket) {
313 accepted_ = server_->Accept(NULL);
314 }
315 void OnCloseEvent(AsyncSocket* socket, int error) {
316 }
317 void ConnectEvents() {
318 server_->SignalReadEvent.connect(this, &NatTcpTest::OnAcceptEvent);
319 client_->SignalConnectEvent.connect(this, &NatTcpTest::OnConnectEvent);
320 }
321 TestVirtualSocketServer* int_vss_;
322 TestVirtualSocketServer* ext_vss_;
323 NATServer* nat_;
324 NATSocketFactory* natsf_;
325 AsyncSocket* client_;
326 AsyncSocket* server_;
327 AsyncSocket* accepted_;
328 bool connected_;
329};
330
331TEST_F(NatTcpTest, DISABLED_TestConnectOut) {
332 server_ = ext_vss_->CreateAsyncSocket(SOCK_STREAM);
333 server_->Bind(SocketAddress());
334 server_->Listen(5);
335
336 client_ = int_vss_->CreateAsyncSocket(SOCK_STREAM);
337 EXPECT_GE(0, client_->Bind(SocketAddress()));
338 EXPECT_GE(0, client_->Connect(server_->GetLocalAddress()));
339
340
341 ConnectEvents();
342
343 EXPECT_TRUE_WAIT(connected_, 1000);
344 EXPECT_EQ(client_->GetRemoteAddress(), server_->GetLocalAddress());
345 EXPECT_EQ(client_->GetRemoteAddress(), accepted_->GetLocalAddress());
346 EXPECT_EQ(client_->GetLocalAddress(), accepted_->GetRemoteAddress());
347
348 client_->Close();
349}
350//#endif