blob: ec5a85709e6c9ffb02410a287471167096120b15 [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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "rtc_base/firewall_socket_server.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <errno.h>
14#include <stddef.h>
15#include <stdint.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016#include <algorithm>
Yves Gerey3e707812018-11-28 16:47:49 +010017#include <string>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/async_socket.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/checks.h"
21#include "rtc_base/logging.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000022
23namespace rtc {
24
25class FirewallSocket : public AsyncSocketAdapter {
26 public:
27 FirewallSocket(FirewallSocketServer* server, AsyncSocket* socket, int type)
Yves Gerey665174f2018-06-19 15:03:05 +020028 : AsyncSocketAdapter(socket), server_(server), type_(type) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000029
deadbeef1ee21252017-06-13 15:49:45 -070030 int Bind(const SocketAddress& addr) override {
31 if (!server_->IsBindableIp(addr.ipaddr())) {
32 SetError(EINVAL);
33 return SOCKET_ERROR;
34 }
35 return AsyncSocketAdapter::Bind(addr);
36 }
37
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000038 int Connect(const SocketAddress& addr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000039 if (type_ == SOCK_STREAM) {
40 if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010041 RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from "
42 << GetLocalAddress().ToSensitiveString() << " to "
43 << addr.ToSensitiveString() << " denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000044 // TODO: Handle this asynchronously.
45 SetError(EHOSTUNREACH);
46 return SOCKET_ERROR;
47 }
48 }
49 return AsyncSocketAdapter::Connect(addr);
50 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000051 int Send(const void* pv, size_t cb) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000052 return SendTo(pv, cb, GetRemoteAddress());
53 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000054 int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override {
honghaiz7252a002016-11-08 20:04:09 -080055 RTC_DCHECK(type_ == SOCK_DGRAM || type_ == SOCK_STREAM);
56 FirewallProtocol protocol = (type_ == SOCK_DGRAM) ? FP_UDP : FP_TCP;
57 if (!server_->Check(protocol, GetLocalAddress(), addr)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010058 RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound packet with type "
59 << type_ << " from "
60 << GetLocalAddress().ToSensitiveString() << " to "
61 << addr.ToSensitiveString() << " dropped";
honghaiz7252a002016-11-08 20:04:09 -080062 return static_cast<int>(cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000063 }
64 return AsyncSocketAdapter::SendTo(pv, cb, addr);
65 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020066 int Recv(void* pv, size_t cb, int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000067 SocketAddress addr;
Stefan Holmer9131efd2016-05-23 18:19:26 +020068 return RecvFrom(pv, cb, &addr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000069 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020070 int RecvFrom(void* pv,
71 size_t cb,
72 SocketAddress* paddr,
73 int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000074 if (type_ == SOCK_DGRAM) {
75 while (true) {
Stefan Holmer9131efd2016-05-23 18:19:26 +020076 int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000077 if (res <= 0)
78 return res;
79 if (server_->Check(FP_UDP, *paddr, GetLocalAddress()))
80 return res;
Mirko Bonadei675513b2017-11-09 11:09:25 +010081 RTC_LOG(LS_VERBOSE)
82 << "FirewallSocket inbound UDP packet from "
83 << paddr->ToSensitiveString() << " to "
84 << GetLocalAddress().ToSensitiveString() << " dropped";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000085 }
86 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020087 return AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088 }
89
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000090 int Listen(int backlog) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091 if (!server_->tcp_listen_enabled()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010092 RTC_LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000093 return -1;
94 }
95
96 return AsyncSocketAdapter::Listen(backlog);
97 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000098 AsyncSocket* Accept(SocketAddress* paddr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099 SocketAddress addr;
100 while (AsyncSocket* sock = AsyncSocketAdapter::Accept(&addr)) {
101 if (server_->Check(FP_TCP, addr, GetLocalAddress())) {
102 if (paddr)
103 *paddr = addr;
104 return sock;
105 }
106 sock->Close();
107 delete sock;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100108 RTC_LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from "
109 << addr.ToSensitiveString() << " to "
110 << GetLocalAddress().ToSensitiveString() << " denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111 }
112 return 0;
113 }
114
115 private:
116 FirewallSocketServer* server_;
117 int type_;
118};
119
120FirewallSocketServer::FirewallSocketServer(SocketServer* server,
121 FirewallManager* manager,
122 bool should_delete_server)
Yves Gerey665174f2018-06-19 15:03:05 +0200123 : server_(server),
124 manager_(manager),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000125 should_delete_server_(should_delete_server),
Yves Gerey665174f2018-06-19 15:03:05 +0200126 udp_sockets_enabled_(true),
127 tcp_sockets_enabled_(true),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128 tcp_listen_enabled_(true) {
129 if (manager_)
130 manager_->AddServer(this);
131}
132
133FirewallSocketServer::~FirewallSocketServer() {
134 if (manager_)
135 manager_->RemoveServer(this);
136
137 if (server_ && should_delete_server_) {
138 delete server_;
deadbeef37f5ecf2017-02-27 14:06:41 -0800139 server_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000140 }
141}
142
Yves Gerey665174f2018-06-19 15:03:05 +0200143void FirewallSocketServer::AddRule(bool allow,
144 FirewallProtocol p,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000145 FirewallDirection d,
146 const SocketAddress& addr) {
Peter Thatcher1fe120a2015-06-10 11:33:17 -0700147 SocketAddress any;
148 if (d == FD_IN || d == FD_ANY) {
149 AddRule(allow, p, any, addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000150 }
Peter Thatcher1fe120a2015-06-10 11:33:17 -0700151 if (d == FD_OUT || d == FD_ANY) {
152 AddRule(allow, p, addr, any);
153 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154}
155
Yves Gerey665174f2018-06-19 15:03:05 +0200156void FirewallSocketServer::AddRule(bool allow,
157 FirewallProtocol p,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 const SocketAddress& src,
159 const SocketAddress& dst) {
160 Rule r;
161 r.allow = allow;
162 r.p = p;
163 r.src = src;
164 r.dst = dst;
165 CritScope scope(&crit_);
166 rules_.push_back(r);
167}
168
169void FirewallSocketServer::ClearRules() {
170 CritScope scope(&crit_);
171 rules_.clear();
172}
173
174bool FirewallSocketServer::Check(FirewallProtocol p,
175 const SocketAddress& src,
176 const SocketAddress& dst) {
177 CritScope scope(&crit_);
178 for (size_t i = 0; i < rules_.size(); ++i) {
179 const Rule& r = rules_[i];
180 if ((r.p != p) && (r.p != FP_ANY))
181 continue;
182 if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsNil())
183 continue;
184 if ((r.src.port() != src.port()) && (r.src.port() != 0))
185 continue;
186 if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsNil())
187 continue;
188 if ((r.dst.port() != dst.port()) && (r.dst.port() != 0))
189 continue;
190 return r.allow;
191 }
192 return true;
193}
194
deadbeef1ee21252017-06-13 15:49:45 -0700195void FirewallSocketServer::SetUnbindableIps(
196 const std::vector<rtc::IPAddress>& unbindable_ips) {
197 unbindable_ips_ = unbindable_ips;
198}
199
200bool FirewallSocketServer::IsBindableIp(const rtc::IPAddress& ip) {
201 return std::find(unbindable_ips_.begin(), unbindable_ips_.end(), ip) ==
202 unbindable_ips_.end();
203}
204
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000205Socket* FirewallSocketServer::CreateSocket(int family, int type) {
206 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
207}
208
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000209AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) {
210 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
211}
212
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000213void FirewallSocketServer::SetMessageQueue(MessageQueue* queue) {
214 server_->SetMessageQueue(queue);
215}
216
217bool FirewallSocketServer::Wait(int cms, bool process_io) {
218 return server_->Wait(cms, process_io);
219}
220
221void FirewallSocketServer::WakeUp() {
222 return server_->WakeUp();
223}
224
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) {
Yves Gerey665174f2018-06-19 15:03:05 +0200226 if (!sock || (type == SOCK_STREAM && !tcp_sockets_enabled_) ||
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227 (type == SOCK_DGRAM && !udp_sockets_enabled_)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100228 RTC_LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000229 delete sock;
deadbeef37f5ecf2017-02-27 14:06:41 -0800230 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231 }
232 return new FirewallSocket(this, sock, type);
233}
234
Yves Gerey665174f2018-06-19 15:03:05 +0200235FirewallManager::FirewallManager() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236
237FirewallManager::~FirewallManager() {
kwiberg22487b22016-09-13 01:17:10 -0700238 RTC_DCHECK(servers_.empty());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239}
240
241void FirewallManager::AddServer(FirewallSocketServer* server) {
242 CritScope scope(&crit_);
243 servers_.push_back(server);
244}
245
246void FirewallManager::RemoveServer(FirewallSocketServer* server) {
247 CritScope scope(&crit_);
248 servers_.erase(std::remove(servers_.begin(), servers_.end(), server),
249 servers_.end());
250}
251
Yves Gerey665174f2018-06-19 15:03:05 +0200252void FirewallManager::AddRule(bool allow,
253 FirewallProtocol p,
254 FirewallDirection d,
255 const SocketAddress& addr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000256 CritScope scope(&crit_);
Yves Gerey665174f2018-06-19 15:03:05 +0200257 for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin();
258 it != servers_.end(); ++it) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000259 (*it)->AddRule(allow, p, d, addr);
260 }
261}
262
263void FirewallManager::ClearRules() {
264 CritScope scope(&crit_);
Yves Gerey665174f2018-06-19 15:03:05 +0200265 for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin();
266 it != servers_.end(); ++it) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000267 (*it)->ClearRules();
268 }
269}
270
271} // namespace rtc