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