| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  *  Copyright 2004 The WebRTC Project Authors. All rights reserved. | 
 | 3 |  * | 
 | 4 |  *  Use of this source code is governed by a BSD-style license | 
 | 5 |  *  that can be found in the LICENSE file in the root of the source | 
 | 6 |  *  tree. An additional intellectual property rights grant can be found | 
 | 7 |  *  in the file PATENTS.  All contributing project authors may | 
 | 8 |  *  be found in the AUTHORS file in the root of the source tree. | 
 | 9 |  */ | 
 | 10 |  | 
| Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 11 | #include "rtc_base/firewallsocketserver.h" | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 12 |  | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 13 | #include <algorithm> | 
 | 14 |  | 
| Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 15 | #include "rtc_base/asyncsocket.h" | 
 | 16 | #include "rtc_base/checks.h" | 
 | 17 | #include "rtc_base/logging.h" | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 18 |  | 
 | 19 | namespace rtc { | 
 | 20 |  | 
 | 21 | class FirewallSocket : public AsyncSocketAdapter { | 
 | 22 |  public: | 
 | 23 |   FirewallSocket(FirewallSocketServer* server, AsyncSocket* socket, int type) | 
 | 24 |     : AsyncSocketAdapter(socket), server_(server), type_(type) { | 
 | 25 |   } | 
 | 26 |  | 
| deadbeef | 1ee2125 | 2017-06-13 15:49:45 -0700 | [diff] [blame] | 27 |   int Bind(const SocketAddress& addr) override { | 
 | 28 |     if (!server_->IsBindableIp(addr.ipaddr())) { | 
 | 29 |       SetError(EINVAL); | 
 | 30 |       return SOCKET_ERROR; | 
 | 31 |     } | 
 | 32 |     return AsyncSocketAdapter::Bind(addr); | 
 | 33 |   } | 
 | 34 |  | 
| kwiberg@webrtc.org | 67186fe | 2015-03-09 22:21:53 +0000 | [diff] [blame] | 35 |   int Connect(const SocketAddress& addr) override { | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 36 |     if (type_ == SOCK_STREAM) { | 
 | 37 |       if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) { | 
| Mirko Bonadei | 675513b | 2017-11-09 11:09:25 +0100 | [diff] [blame] | 38 |         RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from " | 
 | 39 |                             << GetLocalAddress().ToSensitiveString() << " to " | 
 | 40 |                             << addr.ToSensitiveString() << " denied"; | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 41 |         // TODO: Handle this asynchronously. | 
 | 42 |         SetError(EHOSTUNREACH); | 
 | 43 |         return SOCKET_ERROR; | 
 | 44 |       } | 
 | 45 |     } | 
 | 46 |     return AsyncSocketAdapter::Connect(addr); | 
 | 47 |   } | 
| kwiberg@webrtc.org | 67186fe | 2015-03-09 22:21:53 +0000 | [diff] [blame] | 48 |   int Send(const void* pv, size_t cb) override { | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 49 |     return SendTo(pv, cb, GetRemoteAddress()); | 
 | 50 |   } | 
| kwiberg@webrtc.org | 67186fe | 2015-03-09 22:21:53 +0000 | [diff] [blame] | 51 |   int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override { | 
| honghaiz | 7252a00 | 2016-11-08 20:04:09 -0800 | [diff] [blame] | 52 |     RTC_DCHECK(type_ == SOCK_DGRAM || type_ == SOCK_STREAM); | 
 | 53 |     FirewallProtocol protocol = (type_ == SOCK_DGRAM) ? FP_UDP : FP_TCP; | 
 | 54 |     if (!server_->Check(protocol, GetLocalAddress(), addr)) { | 
| Mirko Bonadei | 675513b | 2017-11-09 11:09:25 +0100 | [diff] [blame] | 55 |       RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound packet with type " | 
 | 56 |                           << type_ << " from " | 
 | 57 |                           << GetLocalAddress().ToSensitiveString() << " to " | 
 | 58 |                           << addr.ToSensitiveString() << " dropped"; | 
| honghaiz | 7252a00 | 2016-11-08 20:04:09 -0800 | [diff] [blame] | 59 |       return static_cast<int>(cb); | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 60 |     } | 
 | 61 |     return AsyncSocketAdapter::SendTo(pv, cb, addr); | 
 | 62 |   } | 
| Stefan Holmer | 9131efd | 2016-05-23 18:19:26 +0200 | [diff] [blame] | 63 |   int Recv(void* pv, size_t cb, int64_t* timestamp) override { | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 64 |     SocketAddress addr; | 
| Stefan Holmer | 9131efd | 2016-05-23 18:19:26 +0200 | [diff] [blame] | 65 |     return RecvFrom(pv, cb, &addr, timestamp); | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 66 |   } | 
| Stefan Holmer | 9131efd | 2016-05-23 18:19:26 +0200 | [diff] [blame] | 67 |   int RecvFrom(void* pv, | 
 | 68 |                size_t cb, | 
 | 69 |                SocketAddress* paddr, | 
 | 70 |                int64_t* timestamp) override { | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 71 |     if (type_ == SOCK_DGRAM) { | 
 | 72 |       while (true) { | 
| Stefan Holmer | 9131efd | 2016-05-23 18:19:26 +0200 | [diff] [blame] | 73 |         int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp); | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 74 |         if (res <= 0) | 
 | 75 |           return res; | 
 | 76 |         if (server_->Check(FP_UDP, *paddr, GetLocalAddress())) | 
 | 77 |           return res; | 
| Mirko Bonadei | 675513b | 2017-11-09 11:09:25 +0100 | [diff] [blame] | 78 |         RTC_LOG(LS_VERBOSE) | 
 | 79 |             << "FirewallSocket inbound UDP packet from " | 
 | 80 |             << paddr->ToSensitiveString() << " to " | 
 | 81 |             << GetLocalAddress().ToSensitiveString() << " dropped"; | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 82 |       } | 
 | 83 |     } | 
| Stefan Holmer | 9131efd | 2016-05-23 18:19:26 +0200 | [diff] [blame] | 84 |     return AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp); | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 85 |   } | 
 | 86 |  | 
| kwiberg@webrtc.org | 67186fe | 2015-03-09 22:21:53 +0000 | [diff] [blame] | 87 |   int Listen(int backlog) override { | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 88 |     if (!server_->tcp_listen_enabled()) { | 
| Mirko Bonadei | 675513b | 2017-11-09 11:09:25 +0100 | [diff] [blame] | 89 |       RTC_LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied"; | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 90 |       return -1; | 
 | 91 |     } | 
 | 92 |  | 
 | 93 |     return AsyncSocketAdapter::Listen(backlog); | 
 | 94 |   } | 
| kwiberg@webrtc.org | 67186fe | 2015-03-09 22:21:53 +0000 | [diff] [blame] | 95 |   AsyncSocket* Accept(SocketAddress* paddr) override { | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 96 |     SocketAddress addr; | 
 | 97 |     while (AsyncSocket* sock = AsyncSocketAdapter::Accept(&addr)) { | 
 | 98 |       if (server_->Check(FP_TCP, addr, GetLocalAddress())) { | 
 | 99 |         if (paddr) | 
 | 100 |           *paddr = addr; | 
 | 101 |         return sock; | 
 | 102 |       } | 
 | 103 |       sock->Close(); | 
 | 104 |       delete sock; | 
| Mirko Bonadei | 675513b | 2017-11-09 11:09:25 +0100 | [diff] [blame] | 105 |       RTC_LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from " | 
 | 106 |                           << addr.ToSensitiveString() << " to " | 
 | 107 |                           << GetLocalAddress().ToSensitiveString() << " denied"; | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 108 |     } | 
 | 109 |     return 0; | 
 | 110 |   } | 
 | 111 |  | 
 | 112 |  private: | 
 | 113 |   FirewallSocketServer* server_; | 
 | 114 |   int type_; | 
 | 115 | }; | 
 | 116 |  | 
 | 117 | FirewallSocketServer::FirewallSocketServer(SocketServer* server, | 
 | 118 |                                            FirewallManager* manager, | 
 | 119 |                                            bool should_delete_server) | 
 | 120 |     : server_(server), manager_(manager), | 
 | 121 |       should_delete_server_(should_delete_server), | 
 | 122 |       udp_sockets_enabled_(true), tcp_sockets_enabled_(true), | 
 | 123 |       tcp_listen_enabled_(true) { | 
 | 124 |   if (manager_) | 
 | 125 |     manager_->AddServer(this); | 
 | 126 | } | 
 | 127 |  | 
 | 128 | FirewallSocketServer::~FirewallSocketServer() { | 
 | 129 |   if (manager_) | 
 | 130 |     manager_->RemoveServer(this); | 
 | 131 |  | 
 | 132 |   if (server_ && should_delete_server_) { | 
 | 133 |     delete server_; | 
| deadbeef | 37f5ecf | 2017-02-27 14:06:41 -0800 | [diff] [blame] | 134 |     server_ = nullptr; | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 135 |   } | 
 | 136 | } | 
 | 137 |  | 
 | 138 | void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p, | 
 | 139 |                                    FirewallDirection d, | 
 | 140 |                                    const SocketAddress& addr) { | 
| Peter Thatcher | 1fe120a | 2015-06-10 11:33:17 -0700 | [diff] [blame] | 141 |   SocketAddress any; | 
 | 142 |   if (d == FD_IN || d == FD_ANY) { | 
 | 143 |     AddRule(allow, p, any, addr); | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 144 |   } | 
| Peter Thatcher | 1fe120a | 2015-06-10 11:33:17 -0700 | [diff] [blame] | 145 |   if (d == FD_OUT || d == FD_ANY) { | 
 | 146 |     AddRule(allow, p, addr, any); | 
 | 147 |   } | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 148 | } | 
 | 149 |  | 
 | 150 |  | 
 | 151 | void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p, | 
 | 152 |                                    const SocketAddress& src, | 
 | 153 |                                    const SocketAddress& dst) { | 
 | 154 |   Rule r; | 
 | 155 |   r.allow = allow; | 
 | 156 |   r.p = p; | 
 | 157 |   r.src = src; | 
 | 158 |   r.dst = dst; | 
 | 159 |   CritScope scope(&crit_); | 
 | 160 |   rules_.push_back(r); | 
 | 161 | } | 
 | 162 |  | 
 | 163 | void FirewallSocketServer::ClearRules() { | 
 | 164 |   CritScope scope(&crit_); | 
 | 165 |   rules_.clear(); | 
 | 166 | } | 
 | 167 |  | 
 | 168 | bool FirewallSocketServer::Check(FirewallProtocol p, | 
 | 169 |                                  const SocketAddress& src, | 
 | 170 |                                  const SocketAddress& dst) { | 
 | 171 |   CritScope scope(&crit_); | 
 | 172 |   for (size_t i = 0; i < rules_.size(); ++i) { | 
 | 173 |     const Rule& r = rules_[i]; | 
 | 174 |     if ((r.p != p) && (r.p != FP_ANY)) | 
 | 175 |       continue; | 
 | 176 |     if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsNil()) | 
 | 177 |       continue; | 
 | 178 |     if ((r.src.port() != src.port()) && (r.src.port() != 0)) | 
 | 179 |       continue; | 
 | 180 |     if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsNil()) | 
 | 181 |       continue; | 
 | 182 |     if ((r.dst.port() != dst.port()) && (r.dst.port() != 0)) | 
 | 183 |       continue; | 
 | 184 |     return r.allow; | 
 | 185 |   } | 
 | 186 |   return true; | 
 | 187 | } | 
 | 188 |  | 
| deadbeef | 1ee2125 | 2017-06-13 15:49:45 -0700 | [diff] [blame] | 189 | void FirewallSocketServer::SetUnbindableIps( | 
 | 190 |     const std::vector<rtc::IPAddress>& unbindable_ips) { | 
 | 191 |   unbindable_ips_ = unbindable_ips; | 
 | 192 | } | 
 | 193 |  | 
 | 194 | bool FirewallSocketServer::IsBindableIp(const rtc::IPAddress& ip) { | 
 | 195 |   return std::find(unbindable_ips_.begin(), unbindable_ips_.end(), ip) == | 
 | 196 |          unbindable_ips_.end(); | 
 | 197 | } | 
 | 198 |  | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 199 | Socket* FirewallSocketServer::CreateSocket(int type) { | 
 | 200 |   return CreateSocket(AF_INET, type); | 
 | 201 | } | 
 | 202 |  | 
 | 203 | Socket* FirewallSocketServer::CreateSocket(int family, int type) { | 
 | 204 |   return WrapSocket(server_->CreateAsyncSocket(family, type), type); | 
 | 205 | } | 
 | 206 |  | 
 | 207 | AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) { | 
 | 208 |   return CreateAsyncSocket(AF_INET, type); | 
 | 209 | } | 
 | 210 |  | 
 | 211 | AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) { | 
 | 212 |   return WrapSocket(server_->CreateAsyncSocket(family, type), type); | 
 | 213 | } | 
 | 214 |  | 
| kwiberg@webrtc.org | 67186fe | 2015-03-09 22:21:53 +0000 | [diff] [blame] | 215 | void FirewallSocketServer::SetMessageQueue(MessageQueue* queue) { | 
 | 216 |   server_->SetMessageQueue(queue); | 
 | 217 | } | 
 | 218 |  | 
 | 219 | bool FirewallSocketServer::Wait(int cms, bool process_io) { | 
 | 220 |   return server_->Wait(cms, process_io); | 
 | 221 | } | 
 | 222 |  | 
 | 223 | void FirewallSocketServer::WakeUp() { | 
 | 224 |   return server_->WakeUp(); | 
 | 225 | } | 
 | 226 |  | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 227 | AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) { | 
 | 228 |   if (!sock || | 
 | 229 |       (type == SOCK_STREAM && !tcp_sockets_enabled_) || | 
 | 230 |       (type == SOCK_DGRAM && !udp_sockets_enabled_)) { | 
| Mirko Bonadei | 675513b | 2017-11-09 11:09:25 +0100 | [diff] [blame] | 231 |     RTC_LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied"; | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 232 |     delete sock; | 
| deadbeef | 37f5ecf | 2017-02-27 14:06:41 -0800 | [diff] [blame] | 233 |     return nullptr; | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 234 |   } | 
 | 235 |   return new FirewallSocket(this, sock, type); | 
 | 236 | } | 
 | 237 |  | 
 | 238 | FirewallManager::FirewallManager() { | 
 | 239 | } | 
 | 240 |  | 
 | 241 | FirewallManager::~FirewallManager() { | 
| kwiberg | 22487b2 | 2016-09-13 01:17:10 -0700 | [diff] [blame] | 242 |   RTC_DCHECK(servers_.empty()); | 
| henrike@webrtc.org | f048872 | 2014-05-13 18:00:26 +0000 | [diff] [blame] | 243 | } | 
 | 244 |  | 
 | 245 | void FirewallManager::AddServer(FirewallSocketServer* server) { | 
 | 246 |   CritScope scope(&crit_); | 
 | 247 |   servers_.push_back(server); | 
 | 248 | } | 
 | 249 |  | 
 | 250 | void FirewallManager::RemoveServer(FirewallSocketServer* server) { | 
 | 251 |   CritScope scope(&crit_); | 
 | 252 |   servers_.erase(std::remove(servers_.begin(), servers_.end(), server), | 
 | 253 |                  servers_.end()); | 
 | 254 | } | 
 | 255 |  | 
 | 256 | void FirewallManager::AddRule(bool allow, FirewallProtocol p, | 
 | 257 |                               FirewallDirection d, const SocketAddress& addr) { | 
 | 258 |   CritScope scope(&crit_); | 
 | 259 |   for (std::vector<FirewallSocketServer*>::const_iterator it = | 
 | 260 |       servers_.begin(); it != servers_.end(); ++it) { | 
 | 261 |     (*it)->AddRule(allow, p, d, addr); | 
 | 262 |   } | 
 | 263 | } | 
 | 264 |  | 
 | 265 | void FirewallManager::ClearRules() { | 
 | 266 |   CritScope scope(&crit_); | 
 | 267 |   for (std::vector<FirewallSocketServer*>::const_iterator it = | 
 | 268 |       servers_.begin(); it != servers_.end(); ++it) { | 
 | 269 |     (*it)->ClearRules(); | 
 | 270 |   } | 
 | 271 | } | 
 | 272 |  | 
 | 273 | }  // namespace rtc |