1 /* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/base/natsocketfactory.h" 29 #include "talk/base/natserver.h" 30 #include "talk/base/logging.h" 31 32 namespace talk_base { 33 34 RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) { 35 } 36 37 size_t RouteCmp::operator()(const SocketAddressPair& r) const { 38 size_t h = r.source().Hash(); 39 if (symmetric) 40 h ^= r.destination().Hash(); 41 return h; 42 } 43 44 bool RouteCmp::operator()( 45 const SocketAddressPair& r1, const SocketAddressPair& r2) const { 46 if (r1.source() < r2.source()) 47 return true; 48 if (r2.source() < r1.source()) 49 return false; 50 if (symmetric && (r1.destination() < r2.destination())) 51 return true; 52 if (symmetric && (r2.destination() < r1.destination())) 53 return false; 54 return false; 55 } 56 57 AddrCmp::AddrCmp(NAT* nat) 58 : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) { 59 } 60 61 size_t AddrCmp::operator()(const SocketAddress& a) const { 62 size_t h = 0; 63 if (use_ip) 64 h ^= HashIP(a.ipaddr()); 65 if (use_port) 66 h ^= a.port() | (a.port() << 16); 67 return h; 68 } 69 70 bool AddrCmp::operator()( 71 const SocketAddress& a1, const SocketAddress& a2) const { 72 if (use_ip && (a1.ipaddr() < a2.ipaddr())) 73 return true; 74 if (use_ip && (a2.ipaddr() < a1.ipaddr())) 75 return false; 76 if (use_port && (a1.port() < a2.port())) 77 return true; 78 if (use_port && (a2.port() < a1.port())) 79 return false; 80 return false; 81 } 82 83 NATServer::NATServer( 84 NATType type, SocketFactory* internal, const SocketAddress& internal_addr, 85 SocketFactory* external, const SocketAddress& external_ip) 86 : external_(external), external_ip_(external_ip.ipaddr(), 0) { 87 nat_ = NAT::Create(type); 88 89 server_socket_ = AsyncUDPSocket::Create(internal, internal_addr); 90 server_socket_->SignalReadPacket.connect(this, &NATServer::OnInternalPacket); 91 92 int_map_ = new InternalMap(RouteCmp(nat_)); 93 ext_map_ = new ExternalMap(); 94 } 95 96 NATServer::~NATServer() { 97 for (InternalMap::iterator iter = int_map_->begin(); 98 iter != int_map_->end(); 99 iter++) 100 delete iter->second; 101 102 delete nat_; 103 delete server_socket_; 104 delete int_map_; 105 delete ext_map_; 106 } 107 108 void NATServer::OnInternalPacket( 109 AsyncPacketSocket* socket, const char* buf, size_t size, 110 const SocketAddress& addr) { 111 112 // Read the intended destination from the wire. 113 SocketAddress dest_addr; 114 size_t length = UnpackAddressFromNAT(buf, size, &dest_addr); 115 116 // Find the translation for these addresses (allocating one if necessary). 117 SocketAddressPair route(addr, dest_addr); 118 InternalMap::iterator iter = int_map_->find(route); 119 if (iter == int_map_->end()) { 120 Translate(route); 121 iter = int_map_->find(route); 122 } 123 ASSERT(iter != int_map_->end()); 124 125 // Allow the destination to send packets back to the source. 126 iter->second->whitelist->insert(dest_addr); 127 128 // Send the packet to its intended destination. 129 iter->second->socket->SendTo(buf + length, size - length, dest_addr); 130 } 131 132 void NATServer::OnExternalPacket( 133 AsyncPacketSocket* socket, const char* buf, size_t size, 134 const SocketAddress& remote_addr) { 135 136 SocketAddress local_addr = socket->GetLocalAddress(); 137 138 // Find the translation for this addresses. 139 ExternalMap::iterator iter = ext_map_->find(local_addr); 140 ASSERT(iter != ext_map_->end()); 141 142 // Allow the NAT to reject this packet. 143 if (Filter(iter->second, remote_addr)) { 144 LOG(LS_INFO) << "Packet from " << remote_addr.ToSensitiveString() 145 << " was filtered out by the NAT."; 146 return; 147 } 148 149 // Forward this packet to the internal address. 150 // First prepend the address in a quasi-STUN format. 151 scoped_array<char> real_buf(new char[size + kNATEncodedIPv6AddressSize]); 152 size_t addrlength = PackAddressForNAT(real_buf.get(), 153 size + kNATEncodedIPv6AddressSize, 154 remote_addr); 155 // Copy the data part after the address. 156 std::memcpy(real_buf.get() + addrlength, buf, size); 157 server_socket_->SendTo(real_buf.get(), size + addrlength, 158 iter->second->route.source()); 159 } 160 161 void NATServer::Translate(const SocketAddressPair& route) { 162 AsyncUDPSocket* socket = AsyncUDPSocket::Create(external_, external_ip_); 163 164 if (!socket) { 165 LOG(LS_ERROR) << "Couldn't find a free port!"; 166 return; 167 } 168 169 TransEntry* entry = new TransEntry(route, socket, nat_); 170 (*int_map_)[route] = entry; 171 (*ext_map_)[socket->GetLocalAddress()] = entry; 172 socket->SignalReadPacket.connect(this, &NATServer::OnExternalPacket); 173 } 174 175 bool NATServer::Filter(TransEntry* entry, const SocketAddress& ext_addr) { 176 return entry->whitelist->find(ext_addr) == entry->whitelist->end(); 177 } 178 179 NATServer::TransEntry::TransEntry( 180 const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat) 181 : route(r), socket(s) { 182 whitelist = new AddressSet(AddrCmp(nat)); 183 } 184 185 NATServer::TransEntry::~TransEntry() { 186 delete whitelist; 187 delete socket; 188 } 189 190 } // namespace talk_base 191