| /* | 
 |  *  Copyright 2004 The WebRTC Project Authors. All rights reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include <algorithm> | 
 | #include <memory> | 
 | #include <string> | 
 |  | 
 | #include "rtc_base/asynctcpsocket.h" | 
 | #include "rtc_base/gunit.h" | 
 | #include "rtc_base/logging.h" | 
 | #include "rtc_base/natserver.h" | 
 | #include "rtc_base/natsocketfactory.h" | 
 | #include "rtc_base/nethelpers.h" | 
 | #include "rtc_base/network.h" | 
 | #include "rtc_base/physicalsocketserver.h" | 
 | #include "rtc_base/ptr_util.h" | 
 | #include "rtc_base/testclient.h" | 
 | #include "rtc_base/virtualsocketserver.h" | 
 |  | 
 | using namespace rtc; | 
 |  | 
 | bool CheckReceive( | 
 |     TestClient* client, bool should_receive, const char* buf, size_t size) { | 
 |   return (should_receive) ? | 
 |       client->CheckNextPacket(buf, size, 0) : | 
 |       client->CheckNoPacket(); | 
 | } | 
 |  | 
 | TestClient* CreateTestClient( | 
 |       SocketFactory* factory, const SocketAddress& local_addr) { | 
 |   return new TestClient( | 
 |       WrapUnique(AsyncUDPSocket::Create(factory, local_addr))); | 
 | } | 
 |  | 
 | TestClient* CreateTCPTestClient(AsyncSocket* socket) { | 
 |   return new TestClient(MakeUnique<AsyncTCPSocket>(socket, false)); | 
 | } | 
 |  | 
 | // Tests that when sending from internal_addr to external_addrs through the | 
 | // NAT type specified by nat_type, all external addrs receive the sent packet | 
 | // and, if exp_same is true, all use the same mapped-address on the NAT. | 
 | void TestSend( | 
 |       SocketServer* internal, const SocketAddress& internal_addr, | 
 |       SocketServer* external, const SocketAddress external_addrs[4], | 
 |       NATType nat_type, bool exp_same) { | 
 |   Thread th_int(internal); | 
 |   Thread th_ext(external); | 
 |  | 
 |   SocketAddress server_addr = internal_addr; | 
 |   server_addr.SetPort(0);  // Auto-select a port | 
 |   NATServer* nat = new NATServer(nat_type, internal, server_addr, server_addr, | 
 |                                  external, external_addrs[0]); | 
 |   NATSocketFactory* natsf = new NATSocketFactory(internal, | 
 |                                                  nat->internal_udp_address(), | 
 |                                                  nat->internal_tcp_address()); | 
 |  | 
 |   TestClient* in = CreateTestClient(natsf, internal_addr); | 
 |   TestClient* out[4]; | 
 |   for (int i = 0; i < 4; i++) | 
 |     out[i] = CreateTestClient(external, external_addrs[i]); | 
 |  | 
 |   th_int.Start(); | 
 |   th_ext.Start(); | 
 |  | 
 |   const char* buf = "filter_test"; | 
 |   size_t len = strlen(buf); | 
 |  | 
 |   in->SendTo(buf, len, out[0]->address()); | 
 |   SocketAddress trans_addr; | 
 |   EXPECT_TRUE(out[0]->CheckNextPacket(buf, len, &trans_addr)); | 
 |  | 
 |   for (int i = 1; i < 4; i++) { | 
 |     in->SendTo(buf, len, out[i]->address()); | 
 |     SocketAddress trans_addr2; | 
 |     EXPECT_TRUE(out[i]->CheckNextPacket(buf, len, &trans_addr2)); | 
 |     bool are_same = (trans_addr == trans_addr2); | 
 |     ASSERT_EQ(are_same, exp_same) << "same translated address"; | 
 |     ASSERT_NE(AF_UNSPEC, trans_addr.family()); | 
 |     ASSERT_NE(AF_UNSPEC, trans_addr2.family()); | 
 |   } | 
 |  | 
 |   th_int.Stop(); | 
 |   th_ext.Stop(); | 
 |  | 
 |   delete nat; | 
 |   delete natsf; | 
 |   delete in; | 
 |   for (int i = 0; i < 4; i++) | 
 |     delete out[i]; | 
 | } | 
 |  | 
 | // Tests that when sending from external_addrs to internal_addr, the packet | 
 | // is delivered according to the specified filter_ip and filter_port rules. | 
 | void TestRecv( | 
 |       SocketServer* internal, const SocketAddress& internal_addr, | 
 |       SocketServer* external, const SocketAddress external_addrs[4], | 
 |       NATType nat_type, bool filter_ip, bool filter_port) { | 
 |   Thread th_int(internal); | 
 |   Thread th_ext(external); | 
 |  | 
 |   SocketAddress server_addr = internal_addr; | 
 |   server_addr.SetPort(0);  // Auto-select a port | 
 |   NATServer* nat = new NATServer(nat_type, internal, server_addr, server_addr, | 
 |                                  external, external_addrs[0]); | 
 |   NATSocketFactory* natsf = new NATSocketFactory(internal, | 
 |                                                  nat->internal_udp_address(), | 
 |                                                  nat->internal_tcp_address()); | 
 |  | 
 |   TestClient* in = CreateTestClient(natsf, internal_addr); | 
 |   TestClient* out[4]; | 
 |   for (int i = 0; i < 4; i++) | 
 |     out[i] = CreateTestClient(external, external_addrs[i]); | 
 |  | 
 |   th_int.Start(); | 
 |   th_ext.Start(); | 
 |  | 
 |   const char* buf = "filter_test"; | 
 |   size_t len = strlen(buf); | 
 |  | 
 |   in->SendTo(buf, len, out[0]->address()); | 
 |   SocketAddress trans_addr; | 
 |   EXPECT_TRUE(out[0]->CheckNextPacket(buf, len, &trans_addr)); | 
 |  | 
 |   out[1]->SendTo(buf, len, trans_addr); | 
 |   EXPECT_TRUE(CheckReceive(in, !filter_ip, buf, len)); | 
 |  | 
 |   out[2]->SendTo(buf, len, trans_addr); | 
 |   EXPECT_TRUE(CheckReceive(in, !filter_port, buf, len)); | 
 |  | 
 |   out[3]->SendTo(buf, len, trans_addr); | 
 |   EXPECT_TRUE(CheckReceive(in, !filter_ip && !filter_port, buf, len)); | 
 |  | 
 |   th_int.Stop(); | 
 |   th_ext.Stop(); | 
 |  | 
 |   delete nat; | 
 |   delete natsf; | 
 |   delete in; | 
 |   for (int i = 0; i < 4; i++) | 
 |     delete out[i]; | 
 | } | 
 |  | 
 | // Tests that NATServer allocates bindings properly. | 
 | void TestBindings( | 
 |     SocketServer* internal, const SocketAddress& internal_addr, | 
 |     SocketServer* external, const SocketAddress external_addrs[4]) { | 
 |   TestSend(internal, internal_addr, external, external_addrs, | 
 |            NAT_OPEN_CONE, true); | 
 |   TestSend(internal, internal_addr, external, external_addrs, | 
 |            NAT_ADDR_RESTRICTED, true); | 
 |   TestSend(internal, internal_addr, external, external_addrs, | 
 |            NAT_PORT_RESTRICTED, true); | 
 |   TestSend(internal, internal_addr, external, external_addrs, | 
 |            NAT_SYMMETRIC, false); | 
 | } | 
 |  | 
 | // Tests that NATServer filters packets properly. | 
 | void TestFilters( | 
 |     SocketServer* internal, const SocketAddress& internal_addr, | 
 |     SocketServer* external, const SocketAddress external_addrs[4]) { | 
 |   TestRecv(internal, internal_addr, external, external_addrs, | 
 |            NAT_OPEN_CONE, false, false); | 
 |   TestRecv(internal, internal_addr, external, external_addrs, | 
 |            NAT_ADDR_RESTRICTED, true, false); | 
 |   TestRecv(internal, internal_addr, external, external_addrs, | 
 |            NAT_PORT_RESTRICTED, true, true); | 
 |   TestRecv(internal, internal_addr, external, external_addrs, | 
 |            NAT_SYMMETRIC, true, true); | 
 | } | 
 |  | 
 | bool TestConnectivity(const SocketAddress& src, const IPAddress& dst) { | 
 |   // The physical NAT tests require connectivity to the selected ip from the | 
 |   // internal address used for the NAT. Things like firewalls can break that, so | 
 |   // check to see if it's worth even trying with this ip. | 
 |   std::unique_ptr<PhysicalSocketServer> pss(new PhysicalSocketServer()); | 
 |   std::unique_ptr<AsyncSocket> client( | 
 |       pss->CreateAsyncSocket(src.family(), SOCK_DGRAM)); | 
 |   std::unique_ptr<AsyncSocket> server( | 
 |       pss->CreateAsyncSocket(src.family(), SOCK_DGRAM)); | 
 |   if (client->Bind(SocketAddress(src.ipaddr(), 0)) != 0 || | 
 |       server->Bind(SocketAddress(dst, 0)) != 0) { | 
 |     return false; | 
 |   } | 
 |   const char* buf = "hello other socket"; | 
 |   size_t len = strlen(buf); | 
 |   int sent = client->SendTo(buf, len, server->GetLocalAddress()); | 
 |   SocketAddress addr; | 
 |   const size_t kRecvBufSize = 64; | 
 |   char recvbuf[kRecvBufSize]; | 
 |   Thread::Current()->SleepMs(100); | 
 |   int received = server->RecvFrom(recvbuf, kRecvBufSize, &addr, nullptr); | 
 |   return received == sent && ::memcmp(buf, recvbuf, len) == 0; | 
 | } | 
 |  | 
 | void TestPhysicalInternal(const SocketAddress& int_addr) { | 
 |   BasicNetworkManager network_manager; | 
 |   network_manager.set_ipv6_enabled(true); | 
 |   network_manager.StartUpdating(); | 
 |   // Process pending messages so the network list is updated. | 
 |   Thread::Current()->ProcessMessages(0); | 
 |  | 
 |   std::vector<Network*> networks; | 
 |   network_manager.GetNetworks(&networks); | 
 |   networks.erase(std::remove_if(networks.begin(), networks.end(), | 
 |                                 [](rtc::Network* network) { | 
 |                                   return rtc::kDefaultNetworkIgnoreMask & | 
 |                                          network->type(); | 
 |                                 }), | 
 |                  networks.end()); | 
 |   if (networks.empty()) { | 
 |     RTC_LOG(LS_WARNING) << "Not enough network adapters for test."; | 
 |     return; | 
 |   } | 
 |  | 
 |   SocketAddress ext_addr1(int_addr); | 
 |   SocketAddress ext_addr2; | 
 |   // Find an available IP with matching family. The test breaks if int_addr | 
 |   // can't talk to ip, so check for connectivity as well. | 
 |   for (std::vector<Network*>::iterator it = networks.begin(); | 
 |       it != networks.end(); ++it) { | 
 |     const IPAddress& ip = (*it)->GetBestIP(); | 
 |     if (ip.family() == int_addr.family() && TestConnectivity(int_addr, ip)) { | 
 |       ext_addr2.SetIP(ip); | 
 |       break; | 
 |     } | 
 |   } | 
 |   if (ext_addr2.IsNil()) { | 
 |     RTC_LOG(LS_WARNING) << "No available IP of same family as " << int_addr; | 
 |     return; | 
 |   } | 
 |  | 
 |   RTC_LOG(LS_INFO) << "selected ip " << ext_addr2.ipaddr(); | 
 |  | 
 |   SocketAddress ext_addrs[4] = { | 
 |       SocketAddress(ext_addr1), | 
 |       SocketAddress(ext_addr2), | 
 |       SocketAddress(ext_addr1), | 
 |       SocketAddress(ext_addr2) | 
 |   }; | 
 |  | 
 |   std::unique_ptr<PhysicalSocketServer> int_pss(new PhysicalSocketServer()); | 
 |   std::unique_ptr<PhysicalSocketServer> ext_pss(new PhysicalSocketServer()); | 
 |  | 
 |   TestBindings(int_pss.get(), int_addr, ext_pss.get(), ext_addrs); | 
 |   TestFilters(int_pss.get(), int_addr, ext_pss.get(), ext_addrs); | 
 | } | 
 |  | 
 | TEST(NatTest, TestPhysicalIPv4) { | 
 |   TestPhysicalInternal(SocketAddress("127.0.0.1", 0)); | 
 | } | 
 |  | 
 | TEST(NatTest, TestPhysicalIPv6) { | 
 |   if (HasIPv6Enabled()) { | 
 |     TestPhysicalInternal(SocketAddress("::1", 0)); | 
 |   } else { | 
 |     RTC_LOG(LS_WARNING) << "No IPv6, skipping"; | 
 |   } | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | class TestVirtualSocketServer : public VirtualSocketServer { | 
 |  public: | 
 |   // Expose this publicly | 
 |   IPAddress GetNextIP(int af) { return VirtualSocketServer::GetNextIP(af); } | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | void TestVirtualInternal(int family) { | 
 |   std::unique_ptr<TestVirtualSocketServer> int_vss( | 
 |       new TestVirtualSocketServer()); | 
 |   std::unique_ptr<TestVirtualSocketServer> ext_vss( | 
 |       new TestVirtualSocketServer()); | 
 |  | 
 |   SocketAddress int_addr; | 
 |   SocketAddress ext_addrs[4]; | 
 |   int_addr.SetIP(int_vss->GetNextIP(family)); | 
 |   ext_addrs[0].SetIP(ext_vss->GetNextIP(int_addr.family())); | 
 |   ext_addrs[1].SetIP(ext_vss->GetNextIP(int_addr.family())); | 
 |   ext_addrs[2].SetIP(ext_addrs[0].ipaddr()); | 
 |   ext_addrs[3].SetIP(ext_addrs[1].ipaddr()); | 
 |  | 
 |   TestBindings(int_vss.get(), int_addr, ext_vss.get(), ext_addrs); | 
 |   TestFilters(int_vss.get(), int_addr, ext_vss.get(), ext_addrs); | 
 | } | 
 |  | 
 | TEST(NatTest, TestVirtualIPv4) { | 
 |   TestVirtualInternal(AF_INET); | 
 | } | 
 |  | 
 | TEST(NatTest, TestVirtualIPv6) { | 
 |   if (HasIPv6Enabled()) { | 
 |     TestVirtualInternal(AF_INET6); | 
 |   } else { | 
 |     RTC_LOG(LS_WARNING) << "No IPv6, skipping"; | 
 |   } | 
 | } | 
 |  | 
 | class NatTcpTest : public testing::Test, public sigslot::has_slots<> { | 
 |  public: | 
 |   NatTcpTest() | 
 |       : int_addr_("192.168.0.1", 0), | 
 |         ext_addr_("10.0.0.1", 0), | 
 |         connected_(false), | 
 |         int_vss_(new TestVirtualSocketServer()), | 
 |         ext_vss_(new TestVirtualSocketServer()), | 
 |         int_thread_(new Thread(int_vss_.get())), | 
 |         ext_thread_(new Thread(ext_vss_.get())), | 
 |         nat_(new NATServer(NAT_OPEN_CONE, | 
 |                            int_vss_.get(), | 
 |                            int_addr_, | 
 |                            int_addr_, | 
 |                            ext_vss_.get(), | 
 |                            ext_addr_)), | 
 |         natsf_(new NATSocketFactory(int_vss_.get(), | 
 |                                     nat_->internal_udp_address(), | 
 |                                     nat_->internal_tcp_address())) { | 
 |     int_thread_->Start(); | 
 |     ext_thread_->Start(); | 
 |   } | 
 |  | 
 |   void OnConnectEvent(AsyncSocket* socket) { | 
 |     connected_ = true; | 
 |   } | 
 |  | 
 |   void OnAcceptEvent(AsyncSocket* socket) { | 
 |     accepted_.reset(server_->Accept(nullptr)); | 
 |   } | 
 |  | 
 |   void OnCloseEvent(AsyncSocket* socket, int error) { | 
 |   } | 
 |  | 
 |   void ConnectEvents() { | 
 |     server_->SignalReadEvent.connect(this, &NatTcpTest::OnAcceptEvent); | 
 |     client_->SignalConnectEvent.connect(this, &NatTcpTest::OnConnectEvent); | 
 |   } | 
 |  | 
 |   SocketAddress int_addr_; | 
 |   SocketAddress ext_addr_; | 
 |   bool connected_; | 
 |   std::unique_ptr<TestVirtualSocketServer> int_vss_; | 
 |   std::unique_ptr<TestVirtualSocketServer> ext_vss_; | 
 |   std::unique_ptr<Thread> int_thread_; | 
 |   std::unique_ptr<Thread> ext_thread_; | 
 |   std::unique_ptr<NATServer> nat_; | 
 |   std::unique_ptr<NATSocketFactory> natsf_; | 
 |   std::unique_ptr<AsyncSocket> client_; | 
 |   std::unique_ptr<AsyncSocket> server_; | 
 |   std::unique_ptr<AsyncSocket> accepted_; | 
 | }; | 
 |  | 
 | TEST_F(NatTcpTest, DISABLED_TestConnectOut) { | 
 |   server_.reset(ext_vss_->CreateAsyncSocket(SOCK_STREAM)); | 
 |   server_->Bind(ext_addr_); | 
 |   server_->Listen(5); | 
 |  | 
 |   client_.reset(natsf_->CreateAsyncSocket(SOCK_STREAM)); | 
 |   EXPECT_GE(0, client_->Bind(int_addr_)); | 
 |   EXPECT_GE(0, client_->Connect(server_->GetLocalAddress())); | 
 |  | 
 |   ConnectEvents(); | 
 |  | 
 |   EXPECT_TRUE_WAIT(connected_, 1000); | 
 |   EXPECT_EQ(client_->GetRemoteAddress(), server_->GetLocalAddress()); | 
 |   EXPECT_EQ(accepted_->GetRemoteAddress().ipaddr(), ext_addr_.ipaddr()); | 
 |  | 
 |   std::unique_ptr<rtc::TestClient> in(CreateTCPTestClient(client_.release())); | 
 |   std::unique_ptr<rtc::TestClient> out( | 
 |       CreateTCPTestClient(accepted_.release())); | 
 |  | 
 |   const char* buf = "test_packet"; | 
 |   size_t len = strlen(buf); | 
 |  | 
 |   in->Send(buf, len); | 
 |   SocketAddress trans_addr; | 
 |   EXPECT_TRUE(out->CheckNextPacket(buf, len, &trans_addr)); | 
 |  | 
 |   out->Send(buf, len); | 
 |   EXPECT_TRUE(in->CheckNextPacket(buf, len, &trans_addr)); | 
 | } | 
 | // #endif |