blob: edb0cd239812529f080f35ff0faeb7a92d908d4d [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
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 17:11:0011#include "rtc_base/firewall_socket_server.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2612
Yves Gerey3e707812018-11-28 15:47:4913#include <errno.h>
14#include <stddef.h>
15#include <stdint.h>
Jonas Olssona4d87372019-07-05 17:08:3316
Yves Gerey3e707812018-11-28 15:47:4917#include <string>
henrike@webrtc.orgf0488722014-05-13 18:00:2618
Steve Anton2acd1632019-03-25 20:48:3019#include "absl/algorithm/container.h"
Steve Anton10542f22019-01-11 17:11:0020#include "rtc_base/async_socket.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3121#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2623
24namespace rtc {
25
26class FirewallSocket : public AsyncSocketAdapter {
27 public:
Niels Möllerd0b88792021-08-12 08:32:3028 FirewallSocket(FirewallSocketServer* server, Socket* socket, int type)
Yves Gerey665174f2018-06-19 13:03:0529 : AsyncSocketAdapter(socket), server_(server), type_(type) {}
henrike@webrtc.orgf0488722014-05-13 18:00:2630
deadbeef1ee21252017-06-13 22:49:4531 int Bind(const SocketAddress& addr) override {
32 if (!server_->IsBindableIp(addr.ipaddr())) {
33 SetError(EINVAL);
34 return SOCKET_ERROR;
35 }
36 return AsyncSocketAdapter::Bind(addr);
37 }
38
kwiberg@webrtc.org67186fe2015-03-09 22:21:5339 int Connect(const SocketAddress& addr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:2640 if (type_ == SOCK_STREAM) {
41 if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) {
Mirko Bonadei675513b2017-11-09 10:09:2542 RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from "
43 << GetLocalAddress().ToSensitiveString() << " to "
44 << addr.ToSensitiveString() << " denied";
henrike@webrtc.orgf0488722014-05-13 18:00:2645 // TODO: Handle this asynchronously.
46 SetError(EHOSTUNREACH);
47 return SOCKET_ERROR;
48 }
49 }
50 return AsyncSocketAdapter::Connect(addr);
51 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:5352 int Send(const void* pv, size_t cb) override {
henrike@webrtc.orgf0488722014-05-13 18:00:2653 return SendTo(pv, cb, GetRemoteAddress());
54 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:5355 int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override {
honghaiz7252a002016-11-09 04:04:0956 RTC_DCHECK(type_ == SOCK_DGRAM || type_ == SOCK_STREAM);
57 FirewallProtocol protocol = (type_ == SOCK_DGRAM) ? FP_UDP : FP_TCP;
58 if (!server_->Check(protocol, GetLocalAddress(), addr)) {
Mirko Bonadei675513b2017-11-09 10:09:2559 RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound packet with type "
60 << type_ << " from "
61 << GetLocalAddress().ToSensitiveString() << " to "
62 << addr.ToSensitiveString() << " dropped";
honghaiz7252a002016-11-09 04:04:0963 return static_cast<int>(cb);
henrike@webrtc.orgf0488722014-05-13 18:00:2664 }
65 return AsyncSocketAdapter::SendTo(pv, cb, addr);
66 }
Stefan Holmer9131efd2016-05-23 16:19:2667 int Recv(void* pv, size_t cb, int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:2668 SocketAddress addr;
Stefan Holmer9131efd2016-05-23 16:19:2669 return RecvFrom(pv, cb, &addr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:2670 }
Stefan Holmer9131efd2016-05-23 16:19:2671 int RecvFrom(void* pv,
72 size_t cb,
73 SocketAddress* paddr,
74 int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:2675 if (type_ == SOCK_DGRAM) {
76 while (true) {
Stefan Holmer9131efd2016-05-23 16:19:2677 int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:2678 if (res <= 0)
79 return res;
80 if (server_->Check(FP_UDP, *paddr, GetLocalAddress()))
81 return res;
Mirko Bonadei675513b2017-11-09 10:09:2582 RTC_LOG(LS_VERBOSE)
83 << "FirewallSocket inbound UDP packet from "
84 << paddr->ToSensitiveString() << " to "
85 << GetLocalAddress().ToSensitiveString() << " dropped";
henrike@webrtc.orgf0488722014-05-13 18:00:2686 }
87 }
Stefan Holmer9131efd2016-05-23 16:19:2688 return AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:2689 }
90
kwiberg@webrtc.org67186fe2015-03-09 22:21:5391 int Listen(int backlog) override {
henrike@webrtc.orgf0488722014-05-13 18:00:2692 if (!server_->tcp_listen_enabled()) {
Mirko Bonadei675513b2017-11-09 10:09:2593 RTC_LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied";
henrike@webrtc.orgf0488722014-05-13 18:00:2694 return -1;
95 }
96
97 return AsyncSocketAdapter::Listen(backlog);
98 }
Niels Möllerd0b88792021-08-12 08:32:3099 Socket* Accept(SocketAddress* paddr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26100 SocketAddress addr;
Niels Möllerd0b88792021-08-12 08:32:30101 while (Socket* sock = AsyncSocketAdapter::Accept(&addr)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26102 if (server_->Check(FP_TCP, addr, GetLocalAddress())) {
103 if (paddr)
104 *paddr = addr;
105 return sock;
106 }
107 sock->Close();
108 delete sock;
Mirko Bonadei675513b2017-11-09 10:09:25109 RTC_LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from "
110 << addr.ToSensitiveString() << " to "
111 << GetLocalAddress().ToSensitiveString() << " denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26112 }
113 return 0;
114 }
115
116 private:
117 FirewallSocketServer* server_;
118 int type_;
119};
120
121FirewallSocketServer::FirewallSocketServer(SocketServer* server,
122 FirewallManager* manager,
123 bool should_delete_server)
Yves Gerey665174f2018-06-19 13:03:05124 : server_(server),
125 manager_(manager),
henrike@webrtc.orgf0488722014-05-13 18:00:26126 should_delete_server_(should_delete_server),
Yves Gerey665174f2018-06-19 13:03:05127 udp_sockets_enabled_(true),
128 tcp_sockets_enabled_(true),
henrike@webrtc.orgf0488722014-05-13 18:00:26129 tcp_listen_enabled_(true) {
130 if (manager_)
131 manager_->AddServer(this);
132}
133
134FirewallSocketServer::~FirewallSocketServer() {
135 if (manager_)
136 manager_->RemoveServer(this);
137
138 if (server_ && should_delete_server_) {
139 delete server_;
deadbeef37f5ecf2017-02-27 22:06:41140 server_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26141 }
142}
143
Yves Gerey665174f2018-06-19 13:03:05144void FirewallSocketServer::AddRule(bool allow,
145 FirewallProtocol p,
henrike@webrtc.orgf0488722014-05-13 18:00:26146 FirewallDirection d,
147 const SocketAddress& addr) {
Peter Thatcher1fe120a2015-06-10 18:33:17148 SocketAddress any;
149 if (d == FD_IN || d == FD_ANY) {
150 AddRule(allow, p, any, addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26151 }
Peter Thatcher1fe120a2015-06-10 18:33:17152 if (d == FD_OUT || d == FD_ANY) {
153 AddRule(allow, p, addr, any);
154 }
henrike@webrtc.orgf0488722014-05-13 18:00:26155}
156
Yves Gerey665174f2018-06-19 13:03:05157void FirewallSocketServer::AddRule(bool allow,
158 FirewallProtocol p,
henrike@webrtc.orgf0488722014-05-13 18:00:26159 const SocketAddress& src,
160 const SocketAddress& dst) {
161 Rule r;
162 r.allow = allow;
163 r.p = p;
164 r.src = src;
165 r.dst = dst;
Markus Handell18523c32020-07-08 15:55:58166 webrtc::MutexLock scope(&mutex_);
henrike@webrtc.orgf0488722014-05-13 18:00:26167 rules_.push_back(r);
168}
169
170void FirewallSocketServer::ClearRules() {
Markus Handell18523c32020-07-08 15:55:58171 webrtc::MutexLock scope(&mutex_);
henrike@webrtc.orgf0488722014-05-13 18:00:26172 rules_.clear();
173}
174
175bool FirewallSocketServer::Check(FirewallProtocol p,
176 const SocketAddress& src,
177 const SocketAddress& dst) {
Markus Handell18523c32020-07-08 15:55:58178 webrtc::MutexLock scope(&mutex_);
henrike@webrtc.orgf0488722014-05-13 18:00:26179 for (size_t i = 0; i < rules_.size(); ++i) {
180 const Rule& r = rules_[i];
181 if ((r.p != p) && (r.p != FP_ANY))
182 continue;
183 if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsNil())
184 continue;
185 if ((r.src.port() != src.port()) && (r.src.port() != 0))
186 continue;
187 if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsNil())
188 continue;
189 if ((r.dst.port() != dst.port()) && (r.dst.port() != 0))
190 continue;
191 return r.allow;
192 }
193 return true;
194}
195
deadbeef1ee21252017-06-13 22:49:45196void FirewallSocketServer::SetUnbindableIps(
197 const std::vector<rtc::IPAddress>& unbindable_ips) {
198 unbindable_ips_ = unbindable_ips;
199}
200
201bool FirewallSocketServer::IsBindableIp(const rtc::IPAddress& ip) {
Steve Anton2acd1632019-03-25 20:48:30202 return !absl::c_linear_search(unbindable_ips_, ip);
deadbeef1ee21252017-06-13 22:49:45203}
204
henrike@webrtc.orgf0488722014-05-13 18:00:26205Socket* FirewallSocketServer::CreateSocket(int family, int type) {
Niels Möllerd0b88792021-08-12 08:32:30206 return WrapSocket(server_->CreateSocket(family, type), type);
henrike@webrtc.orgf0488722014-05-13 18:00:26207}
208
Sebastian Jansson290de822020-01-09 13:20:23209void FirewallSocketServer::SetMessageQueue(Thread* queue) {
kwiberg@webrtc.org67186fe2015-03-09 22:21:53210 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
Niels Möllerd0b88792021-08-12 08:32:30221Socket* FirewallSocketServer::WrapSocket(Socket* sock, int type) {
Yves Gerey665174f2018-06-19 13:03:05222 if (!sock || (type == SOCK_STREAM && !tcp_sockets_enabled_) ||
henrike@webrtc.orgf0488722014-05-13 18:00:26223 (type == SOCK_DGRAM && !udp_sockets_enabled_)) {
Mirko Bonadei675513b2017-11-09 10:09:25224 RTC_LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied";
henrike@webrtc.orgf0488722014-05-13 18:00:26225 delete sock;
deadbeef37f5ecf2017-02-27 22:06:41226 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26227 }
228 return new FirewallSocket(this, sock, type);
229}
230
Yves Gerey665174f2018-06-19 13:03:05231FirewallManager::FirewallManager() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26232
233FirewallManager::~FirewallManager() {
kwiberg22487b22016-09-13 08:17:10234 RTC_DCHECK(servers_.empty());
henrike@webrtc.orgf0488722014-05-13 18:00:26235}
236
237void FirewallManager::AddServer(FirewallSocketServer* server) {
Markus Handell18523c32020-07-08 15:55:58238 webrtc::MutexLock scope(&mutex_);
henrike@webrtc.orgf0488722014-05-13 18:00:26239 servers_.push_back(server);
240}
241
242void FirewallManager::RemoveServer(FirewallSocketServer* server) {
Markus Handell18523c32020-07-08 15:55:58243 webrtc::MutexLock scope(&mutex_);
henrike@webrtc.orgf0488722014-05-13 18:00:26244 servers_.erase(std::remove(servers_.begin(), servers_.end(), server),
245 servers_.end());
246}
247
Yves Gerey665174f2018-06-19 13:03:05248void FirewallManager::AddRule(bool allow,
249 FirewallProtocol p,
250 FirewallDirection d,
251 const SocketAddress& addr) {
Markus Handell18523c32020-07-08 15:55:58252 webrtc::MutexLock scope(&mutex_);
Yves Gerey665174f2018-06-19 13:03:05253 for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin();
254 it != servers_.end(); ++it) {
henrike@webrtc.orgf0488722014-05-13 18:00:26255 (*it)->AddRule(allow, p, d, addr);
256 }
257}
258
259void FirewallManager::ClearRules() {
Markus Handell18523c32020-07-08 15:55:58260 webrtc::MutexLock scope(&mutex_);
Yves Gerey665174f2018-06-19 13:03:05261 for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin();
262 it != servers_.end(); ++it) {
henrike@webrtc.orgf0488722014-05-13 18:00:26263 (*it)->ClearRules();
264 }
265}
266
267} // namespace rtc