blob: 2a28124d2366a83d06ed358fbd3591e30b84ccba [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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 Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/firewallsocketserver.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#include <algorithm>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "rtc_base/asyncsocket.h"
16#include "rtc_base/checks.h"
17#include "rtc_base/logging.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018
19namespace rtc {
20
21class FirewallSocket : public AsyncSocketAdapter {
22 public:
23 FirewallSocket(FirewallSocketServer* server, AsyncSocket* socket, int type)
Yves Gerey665174f2018-06-19 15:03:05 +020024 : AsyncSocketAdapter(socket), server_(server), type_(type) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025
deadbeef1ee21252017-06-13 15:49:45 -070026 int Bind(const SocketAddress& addr) override {
27 if (!server_->IsBindableIp(addr.ipaddr())) {
28 SetError(EINVAL);
29 return SOCKET_ERROR;
30 }
31 return AsyncSocketAdapter::Bind(addr);
32 }
33
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000034 int Connect(const SocketAddress& addr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000035 if (type_ == SOCK_STREAM) {
36 if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010037 RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from "
38 << GetLocalAddress().ToSensitiveString() << " to "
39 << addr.ToSensitiveString() << " denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000040 // TODO: Handle this asynchronously.
41 SetError(EHOSTUNREACH);
42 return SOCKET_ERROR;
43 }
44 }
45 return AsyncSocketAdapter::Connect(addr);
46 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000047 int Send(const void* pv, size_t cb) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000048 return SendTo(pv, cb, GetRemoteAddress());
49 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000050 int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override {
honghaiz7252a002016-11-08 20:04:09 -080051 RTC_DCHECK(type_ == SOCK_DGRAM || type_ == SOCK_STREAM);
52 FirewallProtocol protocol = (type_ == SOCK_DGRAM) ? FP_UDP : FP_TCP;
53 if (!server_->Check(protocol, GetLocalAddress(), addr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010054 RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound packet with type "
55 << type_ << " from "
56 << GetLocalAddress().ToSensitiveString() << " to "
57 << addr.ToSensitiveString() << " dropped";
honghaiz7252a002016-11-08 20:04:09 -080058 return static_cast<int>(cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059 }
60 return AsyncSocketAdapter::SendTo(pv, cb, addr);
61 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020062 int Recv(void* pv, size_t cb, int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000063 SocketAddress addr;
Stefan Holmer9131efd2016-05-23 18:19:26 +020064 return RecvFrom(pv, cb, &addr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020066 int RecvFrom(void* pv,
67 size_t cb,
68 SocketAddress* paddr,
69 int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000070 if (type_ == SOCK_DGRAM) {
71 while (true) {
Stefan Holmer9131efd2016-05-23 18:19:26 +020072 int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000073 if (res <= 0)
74 return res;
75 if (server_->Check(FP_UDP, *paddr, GetLocalAddress()))
76 return res;
Mirko Bonadei675513b2017-11-09 11:09:25 +010077 RTC_LOG(LS_VERBOSE)
78 << "FirewallSocket inbound UDP packet from "
79 << paddr->ToSensitiveString() << " to "
80 << GetLocalAddress().ToSensitiveString() << " dropped";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000081 }
82 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020083 return AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000084 }
85
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000086 int Listen(int backlog) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000087 if (!server_->tcp_listen_enabled()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010088 RTC_LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000089 return -1;
90 }
91
92 return AsyncSocketAdapter::Listen(backlog);
93 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000094 AsyncSocket* Accept(SocketAddress* paddr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095 SocketAddress addr;
96 while (AsyncSocket* sock = AsyncSocketAdapter::Accept(&addr)) {
97 if (server_->Check(FP_TCP, addr, GetLocalAddress())) {
98 if (paddr)
99 *paddr = addr;
100 return sock;
101 }
102 sock->Close();
103 delete sock;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100104 RTC_LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from "
105 << addr.ToSensitiveString() << " to "
106 << GetLocalAddress().ToSensitiveString() << " denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000107 }
108 return 0;
109 }
110
111 private:
112 FirewallSocketServer* server_;
113 int type_;
114};
115
116FirewallSocketServer::FirewallSocketServer(SocketServer* server,
117 FirewallManager* manager,
118 bool should_delete_server)
Yves Gerey665174f2018-06-19 15:03:05 +0200119 : server_(server),
120 manager_(manager),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000121 should_delete_server_(should_delete_server),
Yves Gerey665174f2018-06-19 15:03:05 +0200122 udp_sockets_enabled_(true),
123 tcp_sockets_enabled_(true),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000124 tcp_listen_enabled_(true) {
125 if (manager_)
126 manager_->AddServer(this);
127}
128
129FirewallSocketServer::~FirewallSocketServer() {
130 if (manager_)
131 manager_->RemoveServer(this);
132
133 if (server_ && should_delete_server_) {
134 delete server_;
deadbeef37f5ecf2017-02-27 14:06:41 -0800135 server_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000136 }
137}
138
Yves Gerey665174f2018-06-19 15:03:05 +0200139void FirewallSocketServer::AddRule(bool allow,
140 FirewallProtocol p,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141 FirewallDirection d,
142 const SocketAddress& addr) {
Peter Thatcher1fe120a2015-06-10 11:33:17 -0700143 SocketAddress any;
144 if (d == FD_IN || d == FD_ANY) {
145 AddRule(allow, p, any, addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146 }
Peter Thatcher1fe120a2015-06-10 11:33:17 -0700147 if (d == FD_OUT || d == FD_ANY) {
148 AddRule(allow, p, addr, any);
149 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000150}
151
Yves Gerey665174f2018-06-19 15:03:05 +0200152void FirewallSocketServer::AddRule(bool allow,
153 FirewallProtocol p,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154 const SocketAddress& src,
155 const SocketAddress& dst) {
156 Rule r;
157 r.allow = allow;
158 r.p = p;
159 r.src = src;
160 r.dst = dst;
161 CritScope scope(&crit_);
162 rules_.push_back(r);
163}
164
165void FirewallSocketServer::ClearRules() {
166 CritScope scope(&crit_);
167 rules_.clear();
168}
169
170bool FirewallSocketServer::Check(FirewallProtocol p,
171 const SocketAddress& src,
172 const SocketAddress& dst) {
173 CritScope scope(&crit_);
174 for (size_t i = 0; i < rules_.size(); ++i) {
175 const Rule& r = rules_[i];
176 if ((r.p != p) && (r.p != FP_ANY))
177 continue;
178 if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsNil())
179 continue;
180 if ((r.src.port() != src.port()) && (r.src.port() != 0))
181 continue;
182 if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsNil())
183 continue;
184 if ((r.dst.port() != dst.port()) && (r.dst.port() != 0))
185 continue;
186 return r.allow;
187 }
188 return true;
189}
190
deadbeef1ee21252017-06-13 15:49:45 -0700191void FirewallSocketServer::SetUnbindableIps(
192 const std::vector<rtc::IPAddress>& unbindable_ips) {
193 unbindable_ips_ = unbindable_ips;
194}
195
196bool FirewallSocketServer::IsBindableIp(const rtc::IPAddress& ip) {
197 return std::find(unbindable_ips_.begin(), unbindable_ips_.end(), ip) ==
198 unbindable_ips_.end();
199}
200
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000201Socket* FirewallSocketServer::CreateSocket(int family, int type) {
202 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
203}
204
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000205AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) {
206 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
207}
208
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000209void FirewallSocketServer::SetMessageQueue(MessageQueue* queue) {
210 server_->SetMessageQueue(queue);
211}
212
213bool FirewallSocketServer::Wait(int cms, bool process_io) {
214 return server_->Wait(cms, process_io);
215}
216
217void FirewallSocketServer::WakeUp() {
218 return server_->WakeUp();
219}
220
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000221AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200222 if (!sock || (type == SOCK_STREAM && !tcp_sockets_enabled_) ||
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000223 (type == SOCK_DGRAM && !udp_sockets_enabled_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100224 RTC_LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225 delete sock;
deadbeef37f5ecf2017-02-27 14:06:41 -0800226 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227 }
228 return new FirewallSocket(this, sock, type);
229}
230
Yves Gerey665174f2018-06-19 15:03:05 +0200231FirewallManager::FirewallManager() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000232
233FirewallManager::~FirewallManager() {
kwiberg22487b22016-09-13 01:17:10 -0700234 RTC_DCHECK(servers_.empty());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000235}
236
237void FirewallManager::AddServer(FirewallSocketServer* server) {
238 CritScope scope(&crit_);
239 servers_.push_back(server);
240}
241
242void FirewallManager::RemoveServer(FirewallSocketServer* server) {
243 CritScope scope(&crit_);
244 servers_.erase(std::remove(servers_.begin(), servers_.end(), server),
245 servers_.end());
246}
247
Yves Gerey665174f2018-06-19 15:03:05 +0200248void FirewallManager::AddRule(bool allow,
249 FirewallProtocol p,
250 FirewallDirection d,
251 const SocketAddress& addr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000252 CritScope scope(&crit_);
Yves Gerey665174f2018-06-19 15:03:05 +0200253 for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin();
254 it != servers_.end(); ++it) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000255 (*it)->AddRule(allow, p, d, addr);
256 }
257}
258
259void FirewallManager::ClearRules() {
260 CritScope scope(&crit_);
Yves Gerey665174f2018-06-19 15:03:05 +0200261 for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin();
262 it != servers_.end(); ++it) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000263 (*it)->ClearRules();
264 }
265}
266
267} // namespace rtc