blob: 60f45ed9d214ced7112532ff0951cf637560d258 [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)
24 : AsyncSocketAdapter(socket), server_(server), type_(type) {
25 }
26
deadbeef1ee21252017-06-13 15:49:45 -070027 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.org67186fe2015-03-09 22:21:53 +000035 int Connect(const SocketAddress& addr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036 if (type_ == SOCK_STREAM) {
37 if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010038 RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from "
39 << GetLocalAddress().ToSensitiveString() << " to "
40 << addr.ToSensitiveString() << " denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041 // TODO: Handle this asynchronously.
42 SetError(EHOSTUNREACH);
43 return SOCKET_ERROR;
44 }
45 }
46 return AsyncSocketAdapter::Connect(addr);
47 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000048 int Send(const void* pv, size_t cb) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049 return SendTo(pv, cb, GetRemoteAddress());
50 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000051 int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override {
honghaiz7252a002016-11-08 20:04:09 -080052 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 Bonadei675513b2017-11-09 11:09:25 +010055 RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound packet with type "
56 << type_ << " from "
57 << GetLocalAddress().ToSensitiveString() << " to "
58 << addr.ToSensitiveString() << " dropped";
honghaiz7252a002016-11-08 20:04:09 -080059 return static_cast<int>(cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000060 }
61 return AsyncSocketAdapter::SendTo(pv, cb, addr);
62 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020063 int Recv(void* pv, size_t cb, int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000064 SocketAddress addr;
Stefan Holmer9131efd2016-05-23 18:19:26 +020065 return RecvFrom(pv, cb, &addr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020067 int RecvFrom(void* pv,
68 size_t cb,
69 SocketAddress* paddr,
70 int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000071 if (type_ == SOCK_DGRAM) {
72 while (true) {
Stefan Holmer9131efd2016-05-23 18:19:26 +020073 int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000074 if (res <= 0)
75 return res;
76 if (server_->Check(FP_UDP, *paddr, GetLocalAddress()))
77 return res;
Mirko Bonadei675513b2017-11-09 11:09:25 +010078 RTC_LOG(LS_VERBOSE)
79 << "FirewallSocket inbound UDP packet from "
80 << paddr->ToSensitiveString() << " to "
81 << GetLocalAddress().ToSensitiveString() << " dropped";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000082 }
83 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020084 return AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000085 }
86
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000087 int Listen(int backlog) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088 if (!server_->tcp_listen_enabled()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010089 RTC_LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000090 return -1;
91 }
92
93 return AsyncSocketAdapter::Listen(backlog);
94 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000095 AsyncSocket* Accept(SocketAddress* paddr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000096 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 Bonadei675513b2017-11-09 11:09:25 +0100105 RTC_LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from "
106 << addr.ToSensitiveString() << " to "
107 << GetLocalAddress().ToSensitiveString() << " denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000108 }
109 return 0;
110 }
111
112 private:
113 FirewallSocketServer* server_;
114 int type_;
115};
116
117FirewallSocketServer::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
128FirewallSocketServer::~FirewallSocketServer() {
129 if (manager_)
130 manager_->RemoveServer(this);
131
132 if (server_ && should_delete_server_) {
133 delete server_;
deadbeef37f5ecf2017-02-27 14:06:41 -0800134 server_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000135 }
136}
137
138void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
139 FirewallDirection d,
140 const SocketAddress& addr) {
Peter Thatcher1fe120a2015-06-10 11:33:17 -0700141 SocketAddress any;
142 if (d == FD_IN || d == FD_ANY) {
143 AddRule(allow, p, any, addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144 }
Peter Thatcher1fe120a2015-06-10 11:33:17 -0700145 if (d == FD_OUT || d == FD_ANY) {
146 AddRule(allow, p, addr, any);
147 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148}
149
150
151void 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
163void FirewallSocketServer::ClearRules() {
164 CritScope scope(&crit_);
165 rules_.clear();
166}
167
168bool 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
deadbeef1ee21252017-06-13 15:49:45 -0700189void FirewallSocketServer::SetUnbindableIps(
190 const std::vector<rtc::IPAddress>& unbindable_ips) {
191 unbindable_ips_ = unbindable_ips;
192}
193
194bool 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.orgf0488722014-05-13 18:00:26 +0000199Socket* FirewallSocketServer::CreateSocket(int type) {
200 return CreateSocket(AF_INET, type);
201}
202
203Socket* FirewallSocketServer::CreateSocket(int family, int type) {
204 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
205}
206
207AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) {
208 return CreateAsyncSocket(AF_INET, type);
209}
210
211AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) {
212 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
213}
214
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000215void FirewallSocketServer::SetMessageQueue(MessageQueue* queue) {
216 server_->SetMessageQueue(queue);
217}
218
219bool FirewallSocketServer::Wait(int cms, bool process_io) {
220 return server_->Wait(cms, process_io);
221}
222
223void FirewallSocketServer::WakeUp() {
224 return server_->WakeUp();
225}
226
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) {
228 if (!sock ||
229 (type == SOCK_STREAM && !tcp_sockets_enabled_) ||
230 (type == SOCK_DGRAM && !udp_sockets_enabled_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100231 RTC_LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000232 delete sock;
deadbeef37f5ecf2017-02-27 14:06:41 -0800233 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000234 }
235 return new FirewallSocket(this, sock, type);
236}
237
238FirewallManager::FirewallManager() {
239}
240
241FirewallManager::~FirewallManager() {
kwiberg22487b22016-09-13 01:17:10 -0700242 RTC_DCHECK(servers_.empty());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000243}
244
245void FirewallManager::AddServer(FirewallSocketServer* server) {
246 CritScope scope(&crit_);
247 servers_.push_back(server);
248}
249
250void FirewallManager::RemoveServer(FirewallSocketServer* server) {
251 CritScope scope(&crit_);
252 servers_.erase(std::remove(servers_.begin(), servers_.end(), server),
253 servers_.end());
254}
255
256void 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
265void 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