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, const PacketTime& packet_time) { 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->WhitelistInsert(dest_addr); 127 128 // Send the packet to its intended destination. 129 iter->second->socket->SendTo(buf + length, size - length, dest_addr, 130 DSCP_NO_CHANGE); 131 } 132 133 void NATServer::OnExternalPacket( 134 AsyncPacketSocket* socket, const char* buf, size_t size, 135 const SocketAddress& remote_addr, const PacketTime& packet_time) { 136 137 SocketAddress local_addr = socket->GetLocalAddress(); 138 139 // Find the translation for this addresses. 140 ExternalMap::iterator iter = ext_map_->find(local_addr); 141 ASSERT(iter != ext_map_->end()); 142 143 // Allow the NAT to reject this packet. 144 if (ShouldFilterOut(iter->second, remote_addr)) { 145 LOG(LS_INFO) << "Packet from " << remote_addr.ToSensitiveString() 146 << " was filtered out by the NAT."; 147 return; 148 } 149 150 // Forward this packet to the internal address. 151 // First prepend the address in a quasi-STUN format. 152 scoped_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]); 153 size_t addrlength = PackAddressForNAT(real_buf.get(), 154 size + kNATEncodedIPv6AddressSize, 155 remote_addr); 156 // Copy the data part after the address. 157 std::memcpy(real_buf.get() + addrlength, buf, size); 158 server_socket_->SendTo(real_buf.get(), size + addrlength, 159 iter->second->route.source(), DSCP_NO_CHANGE); 160 } 161 162 void NATServer::Translate(const SocketAddressPair& route) { 163 AsyncUDPSocket* socket = AsyncUDPSocket::Create(external_, external_ip_); 164 165 if (!socket) { 166 LOG(LS_ERROR) << "Couldn't find a free port!"; 167 return; 168 } 169 170 TransEntry* entry = new TransEntry(route, socket, nat_); 171 (*int_map_)[route] = entry; 172 (*ext_map_)[socket->GetLocalAddress()] = entry; 173 socket->SignalReadPacket.connect(this, &NATServer::OnExternalPacket); 174 } 175 176 bool NATServer::ShouldFilterOut(TransEntry* entry, 177 const SocketAddress& ext_addr) { 178 return entry->WhitelistContains(ext_addr); 179 } 180 181 NATServer::TransEntry::TransEntry( 182 const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat) 183 : route(r), socket(s) { 184 whitelist = new AddressSet(AddrCmp(nat)); 185 } 186 187 NATServer::TransEntry::~TransEntry() { 188 delete whitelist; 189 delete socket; 190 } 191 192 void NATServer::TransEntry::WhitelistInsert(const SocketAddress& addr) { 193 CritScope cs(&crit_); 194 whitelist->insert(addr); 195 } 196 197 bool NATServer::TransEntry::WhitelistContains(const SocketAddress& ext_addr) { 198 CritScope cs(&crit_); 199 return whitelist->find(ext_addr) == whitelist->end(); 200 } 201 202 } // namespace talk_base 203