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