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/firewallsocketserver.h" 29 30 #include <cassert> 31 #include <algorithm> 32 33 #include "talk/base/asyncsocket.h" 34 #include "talk/base/logging.h" 35 36 namespace talk_base { 37 38 class FirewallSocket : public AsyncSocketAdapter { 39 public: 40 FirewallSocket(FirewallSocketServer* server, AsyncSocket* socket, int type) 41 : AsyncSocketAdapter(socket), server_(server), type_(type) { 42 } 43 44 virtual int Connect(const SocketAddress& addr) { 45 if (type_ == SOCK_STREAM) { 46 if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) { 47 LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from " 48 << GetLocalAddress().ToString() << " to " 49 << addr.ToString() << " denied"; 50 // TODO: Handle this asynchronously. 51 SetError(EHOSTUNREACH); 52 return SOCKET_ERROR; 53 } 54 } 55 return AsyncSocketAdapter::Connect(addr); 56 } 57 virtual int Send(const void* pv, size_t cb) { 58 return SendTo(pv, cb, GetRemoteAddress()); 59 } 60 virtual int SendTo(const void* pv, size_t cb, const SocketAddress& addr) { 61 if (type_ == SOCK_DGRAM) { 62 if (!server_->Check(FP_UDP, GetLocalAddress(), addr)) { 63 LOG(LS_VERBOSE) << "FirewallSocket outbound UDP packet from " 64 << GetLocalAddress().ToString() << " to " 65 << addr.ToString() << " dropped"; 66 return static_cast<int>(cb); 67 } 68 } 69 return AsyncSocketAdapter::SendTo(pv, cb, addr); 70 } 71 virtual int Recv(void* pv, size_t cb) { 72 SocketAddress addr; 73 return RecvFrom(pv, cb, &addr); 74 } 75 virtual int RecvFrom(void* pv, size_t cb, SocketAddress* paddr) { 76 if (type_ == SOCK_DGRAM) { 77 while (true) { 78 int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr); 79 if (res <= 0) 80 return res; 81 if (server_->Check(FP_UDP, *paddr, GetLocalAddress())) 82 return res; 83 LOG(LS_VERBOSE) << "FirewallSocket inbound UDP packet from " 84 << paddr->ToString() << " to " 85 << GetLocalAddress().ToString() << " dropped"; 86 } 87 } 88 return AsyncSocketAdapter::RecvFrom(pv, cb, paddr); 89 } 90 91 virtual int Listen(int backlog) { 92 if (!server_->tcp_listen_enabled()) { 93 LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied"; 94 return -1; 95 } 96 97 return AsyncSocketAdapter::Listen(backlog); 98 } 99 virtual AsyncSocket* Accept(SocketAddress* paddr) { 100 SocketAddress addr; 101 while (AsyncSocket* sock = AsyncSocketAdapter::Accept(&addr)) { 102 if (server_->Check(FP_TCP, addr, GetLocalAddress())) { 103 if (paddr) 104 *paddr = addr; 105 return sock; 106 } 107 sock->Close(); 108 delete sock; 109 LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from " 110 << addr.ToString() << " to " 111 << GetLocalAddress().ToString() << " denied"; 112 } 113 return 0; 114 } 115 116 private: 117 FirewallSocketServer* server_; 118 int type_; 119 }; 120 121 FirewallSocketServer::FirewallSocketServer(SocketServer* server, 122 FirewallManager* manager, 123 bool should_delete_server) 124 : server_(server), manager_(manager), 125 should_delete_server_(should_delete_server), 126 udp_sockets_enabled_(true), tcp_sockets_enabled_(true), 127 tcp_listen_enabled_(true) { 128 if (manager_) 129 manager_->AddServer(this); 130 } 131 132 FirewallSocketServer::~FirewallSocketServer() { 133 if (manager_) 134 manager_->RemoveServer(this); 135 136 if (server_ && should_delete_server_) { 137 delete server_; 138 server_ = NULL; 139 } 140 } 141 142 void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p, 143 FirewallDirection d, 144 const SocketAddress& addr) { 145 SocketAddress src, dst; 146 if (d == FD_IN) { 147 dst = addr; 148 } else { 149 src = addr; 150 } 151 AddRule(allow, p, src, dst); 152 } 153 154 155 void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p, 156 const SocketAddress& src, 157 const SocketAddress& dst) { 158 Rule r; 159 r.allow = allow; 160 r.p = p; 161 r.src = src; 162 r.dst = dst; 163 CritScope scope(&crit_); 164 rules_.push_back(r); 165 } 166 167 void FirewallSocketServer::ClearRules() { 168 CritScope scope(&crit_); 169 rules_.clear(); 170 } 171 172 bool FirewallSocketServer::Check(FirewallProtocol p, 173 const SocketAddress& src, 174 const SocketAddress& dst) { 175 CritScope scope(&crit_); 176 for (size_t i = 0; i < rules_.size(); ++i) { 177 const Rule& r = rules_[i]; 178 if ((r.p != p) && (r.p != FP_ANY)) 179 continue; 180 if ((r.src.ip() != src.ip()) && !r.src.IsAny()) 181 continue; 182 if ((r.src.port() != src.port()) && (r.src.port() != 0)) 183 continue; 184 if ((r.dst.ip() != dst.ip()) && !r.dst.IsAny()) 185 continue; 186 if ((r.dst.port() != dst.port()) && (r.dst.port() != 0)) 187 continue; 188 return r.allow; 189 } 190 return true; 191 } 192 193 Socket* FirewallSocketServer::CreateSocket(int type) { 194 return WrapSocket(server_->CreateAsyncSocket(type), type); 195 } 196 197 AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) { 198 return WrapSocket(server_->CreateAsyncSocket(type), type); 199 } 200 201 AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) { 202 if (!sock || 203 (type == SOCK_STREAM && !tcp_sockets_enabled_) || 204 (type == SOCK_DGRAM && !udp_sockets_enabled_)) { 205 LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied"; 206 return NULL; 207 } 208 return new FirewallSocket(this, sock, type); 209 } 210 211 FirewallManager::FirewallManager() { 212 } 213 214 FirewallManager::~FirewallManager() { 215 assert(servers_.empty()); 216 } 217 218 void FirewallManager::AddServer(FirewallSocketServer* server) { 219 CritScope scope(&crit_); 220 servers_.push_back(server); 221 } 222 223 void FirewallManager::RemoveServer(FirewallSocketServer* server) { 224 CritScope scope(&crit_); 225 servers_.erase(std::remove(servers_.begin(), servers_.end(), server), 226 servers_.end()); 227 } 228 229 void FirewallManager::AddRule(bool allow, FirewallProtocol p, 230 FirewallDirection d, const SocketAddress& addr) { 231 CritScope scope(&crit_); 232 for (std::vector<FirewallSocketServer*>::const_iterator it = 233 servers_.begin(); it != servers_.end(); ++it) { 234 (*it)->AddRule(allow, p, d, addr); 235 } 236 } 237 238 void FirewallManager::ClearRules() { 239 CritScope scope(&crit_); 240 for (std::vector<FirewallSocketServer*>::const_iterator it = 241 servers_.begin(); it != servers_.end(); ++it) { 242 (*it)->ClearRules(); 243 } 244 } 245 246 } // namespace talk_base 247