blob: d6d03df3ada87ff4edf16b89b0363387bb84ca28 [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
11#include "webrtc/base/firewallsocketserver.h"
12
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#include <algorithm>
14
15#include "webrtc/base/asyncsocket.h"
kwiberg22487b22016-09-13 01:17:10 -070016#include "webrtc/base/checks.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000017#include "webrtc/base/logging.h"
18
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
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000027 int Connect(const SocketAddress& addr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000028 if (type_ == SOCK_STREAM) {
29 if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) {
30 LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from "
31 << GetLocalAddress().ToSensitiveString() << " to "
32 << addr.ToSensitiveString() << " denied";
33 // TODO: Handle this asynchronously.
34 SetError(EHOSTUNREACH);
35 return SOCKET_ERROR;
36 }
37 }
38 return AsyncSocketAdapter::Connect(addr);
39 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000040 int Send(const void* pv, size_t cb) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041 return SendTo(pv, cb, GetRemoteAddress());
42 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000043 int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000044 if (type_ == SOCK_DGRAM) {
45 if (!server_->Check(FP_UDP, GetLocalAddress(), addr)) {
46 LOG(LS_VERBOSE) << "FirewallSocket outbound UDP packet from "
47 << GetLocalAddress().ToSensitiveString() << " to "
48 << addr.ToSensitiveString() << " dropped";
49 return static_cast<int>(cb);
50 }
51 }
52 return AsyncSocketAdapter::SendTo(pv, cb, addr);
53 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020054 int Recv(void* pv, size_t cb, int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000055 SocketAddress addr;
Stefan Holmer9131efd2016-05-23 18:19:26 +020056 return RecvFrom(pv, cb, &addr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020058 int RecvFrom(void* pv,
59 size_t cb,
60 SocketAddress* paddr,
61 int64_t* timestamp) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000062 if (type_ == SOCK_DGRAM) {
63 while (true) {
Stefan Holmer9131efd2016-05-23 18:19:26 +020064 int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065 if (res <= 0)
66 return res;
67 if (server_->Check(FP_UDP, *paddr, GetLocalAddress()))
68 return res;
69 LOG(LS_VERBOSE) << "FirewallSocket inbound UDP packet from "
70 << paddr->ToSensitiveString() << " to "
71 << GetLocalAddress().ToSensitiveString() << " dropped";
72 }
73 }
Stefan Holmer9131efd2016-05-23 18:19:26 +020074 return AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000075 }
76
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000077 int Listen(int backlog) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000078 if (!server_->tcp_listen_enabled()) {
79 LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied";
80 return -1;
81 }
82
83 return AsyncSocketAdapter::Listen(backlog);
84 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000085 AsyncSocket* Accept(SocketAddress* paddr) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000086 SocketAddress addr;
87 while (AsyncSocket* sock = AsyncSocketAdapter::Accept(&addr)) {
88 if (server_->Check(FP_TCP, addr, GetLocalAddress())) {
89 if (paddr)
90 *paddr = addr;
91 return sock;
92 }
93 sock->Close();
94 delete sock;
95 LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from "
96 << addr.ToSensitiveString() << " to "
97 << GetLocalAddress().ToSensitiveString() << " denied";
98 }
99 return 0;
100 }
101
102 private:
103 FirewallSocketServer* server_;
104 int type_;
105};
106
107FirewallSocketServer::FirewallSocketServer(SocketServer* server,
108 FirewallManager* manager,
109 bool should_delete_server)
110 : server_(server), manager_(manager),
111 should_delete_server_(should_delete_server),
112 udp_sockets_enabled_(true), tcp_sockets_enabled_(true),
113 tcp_listen_enabled_(true) {
114 if (manager_)
115 manager_->AddServer(this);
116}
117
118FirewallSocketServer::~FirewallSocketServer() {
119 if (manager_)
120 manager_->RemoveServer(this);
121
122 if (server_ && should_delete_server_) {
123 delete server_;
124 server_ = NULL;
125 }
126}
127
128void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
129 FirewallDirection d,
130 const SocketAddress& addr) {
Peter Thatcher1fe120a2015-06-10 11:33:17 -0700131 SocketAddress any;
132 if (d == FD_IN || d == FD_ANY) {
133 AddRule(allow, p, any, addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000134 }
Peter Thatcher1fe120a2015-06-10 11:33:17 -0700135 if (d == FD_OUT || d == FD_ANY) {
136 AddRule(allow, p, addr, any);
137 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000138}
139
140
141void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
142 const SocketAddress& src,
143 const SocketAddress& dst) {
144 Rule r;
145 r.allow = allow;
146 r.p = p;
147 r.src = src;
148 r.dst = dst;
149 CritScope scope(&crit_);
150 rules_.push_back(r);
151}
152
153void FirewallSocketServer::ClearRules() {
154 CritScope scope(&crit_);
155 rules_.clear();
156}
157
158bool FirewallSocketServer::Check(FirewallProtocol p,
159 const SocketAddress& src,
160 const SocketAddress& dst) {
161 CritScope scope(&crit_);
162 for (size_t i = 0; i < rules_.size(); ++i) {
163 const Rule& r = rules_[i];
164 if ((r.p != p) && (r.p != FP_ANY))
165 continue;
166 if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsNil())
167 continue;
168 if ((r.src.port() != src.port()) && (r.src.port() != 0))
169 continue;
170 if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsNil())
171 continue;
172 if ((r.dst.port() != dst.port()) && (r.dst.port() != 0))
173 continue;
174 return r.allow;
175 }
176 return true;
177}
178
179Socket* FirewallSocketServer::CreateSocket(int type) {
180 return CreateSocket(AF_INET, type);
181}
182
183Socket* FirewallSocketServer::CreateSocket(int family, int type) {
184 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
185}
186
187AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) {
188 return CreateAsyncSocket(AF_INET, type);
189}
190
191AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) {
192 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
193}
194
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000195void FirewallSocketServer::SetMessageQueue(MessageQueue* queue) {
196 server_->SetMessageQueue(queue);
197}
198
199bool FirewallSocketServer::Wait(int cms, bool process_io) {
200 return server_->Wait(cms, process_io);
201}
202
203void FirewallSocketServer::WakeUp() {
204 return server_->WakeUp();
205}
206
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000207AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) {
208 if (!sock ||
209 (type == SOCK_STREAM && !tcp_sockets_enabled_) ||
210 (type == SOCK_DGRAM && !udp_sockets_enabled_)) {
211 LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied";
212 delete sock;
213 return NULL;
214 }
215 return new FirewallSocket(this, sock, type);
216}
217
218FirewallManager::FirewallManager() {
219}
220
221FirewallManager::~FirewallManager() {
kwiberg22487b22016-09-13 01:17:10 -0700222 RTC_DCHECK(servers_.empty());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000223}
224
225void FirewallManager::AddServer(FirewallSocketServer* server) {
226 CritScope scope(&crit_);
227 servers_.push_back(server);
228}
229
230void FirewallManager::RemoveServer(FirewallSocketServer* server) {
231 CritScope scope(&crit_);
232 servers_.erase(std::remove(servers_.begin(), servers_.end(), server),
233 servers_.end());
234}
235
236void FirewallManager::AddRule(bool allow, FirewallProtocol p,
237 FirewallDirection d, const SocketAddress& addr) {
238 CritScope scope(&crit_);
239 for (std::vector<FirewallSocketServer*>::const_iterator it =
240 servers_.begin(); it != servers_.end(); ++it) {
241 (*it)->AddRule(allow, p, d, addr);
242 }
243}
244
245void FirewallManager::ClearRules() {
246 CritScope scope(&crit_);
247 for (std::vector<FirewallSocketServer*>::const_iterator it =
248 servers_.begin(); it != servers_.end(); ++it) {
249 (*it)->ClearRules();
250 }
251}
252
253} // namespace rtc