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