blob: 4a8a66d43e49cf964197958f71640d97b34ed4ea [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/base/firewallsocketserver.h"
29
pbos@webrtc.org371243d2014-03-07 15:22:04 +000030#include <assert.h>
31
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032#include <algorithm>
33
34#include "talk/base/asyncsocket.h"
35#include "talk/base/logging.h"
36
37namespace talk_base {
38
39class FirewallSocket : public AsyncSocketAdapter {
40 public:
41 FirewallSocket(FirewallSocketServer* server, AsyncSocket* socket, int type)
42 : AsyncSocketAdapter(socket), server_(server), type_(type) {
43 }
44
45 virtual int Connect(const SocketAddress& addr) {
46 if (type_ == SOCK_STREAM) {
47 if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) {
48 LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from "
49 << GetLocalAddress().ToSensitiveString() << " to "
50 << addr.ToSensitiveString() << " denied";
51 // TODO: Handle this asynchronously.
52 SetError(EHOSTUNREACH);
53 return SOCKET_ERROR;
54 }
55 }
56 return AsyncSocketAdapter::Connect(addr);
57 }
58 virtual int Send(const void* pv, size_t cb) {
59 return SendTo(pv, cb, GetRemoteAddress());
60 }
61 virtual int SendTo(const void* pv, size_t cb, const SocketAddress& addr) {
62 if (type_ == SOCK_DGRAM) {
63 if (!server_->Check(FP_UDP, GetLocalAddress(), addr)) {
64 LOG(LS_VERBOSE) << "FirewallSocket outbound UDP packet from "
65 << GetLocalAddress().ToSensitiveString() << " to "
66 << addr.ToSensitiveString() << " dropped";
67 return static_cast<int>(cb);
68 }
69 }
70 return AsyncSocketAdapter::SendTo(pv, cb, addr);
71 }
72 virtual int Recv(void* pv, size_t cb) {
73 SocketAddress addr;
74 return RecvFrom(pv, cb, &addr);
75 }
76 virtual int RecvFrom(void* pv, size_t cb, SocketAddress* paddr) {
77 if (type_ == SOCK_DGRAM) {
78 while (true) {
79 int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
80 if (res <= 0)
81 return res;
82 if (server_->Check(FP_UDP, *paddr, GetLocalAddress()))
83 return res;
84 LOG(LS_VERBOSE) << "FirewallSocket inbound UDP packet from "
85 << paddr->ToSensitiveString() << " to "
86 << GetLocalAddress().ToSensitiveString() << " dropped";
87 }
88 }
89 return AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
90 }
91
92 virtual int Listen(int backlog) {
93 if (!server_->tcp_listen_enabled()) {
94 LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied";
95 return -1;
96 }
97
98 return AsyncSocketAdapter::Listen(backlog);
99 }
100 virtual AsyncSocket* Accept(SocketAddress* paddr) {
101 SocketAddress addr;
102 while (AsyncSocket* sock = AsyncSocketAdapter::Accept(&addr)) {
103 if (server_->Check(FP_TCP, addr, GetLocalAddress())) {
104 if (paddr)
105 *paddr = addr;
106 return sock;
107 }
108 sock->Close();
109 delete sock;
110 LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from "
111 << addr.ToSensitiveString() << " to "
112 << GetLocalAddress().ToSensitiveString() << " denied";
113 }
114 return 0;
115 }
116
117 private:
118 FirewallSocketServer* server_;
119 int type_;
120};
121
122FirewallSocketServer::FirewallSocketServer(SocketServer* server,
123 FirewallManager* manager,
124 bool should_delete_server)
125 : server_(server), manager_(manager),
126 should_delete_server_(should_delete_server),
127 udp_sockets_enabled_(true), tcp_sockets_enabled_(true),
128 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_;
139 server_ = NULL;
140 }
141}
142
143void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
144 FirewallDirection d,
145 const SocketAddress& addr) {
146 SocketAddress src, dst;
147 if (d == FD_IN) {
148 dst = addr;
149 } else {
150 src = addr;
151 }
152 AddRule(allow, p, src, dst);
153}
154
155
156void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
157 const SocketAddress& src,
158 const SocketAddress& dst) {
159 Rule r;
160 r.allow = allow;
161 r.p = p;
162 r.src = src;
163 r.dst = dst;
164 CritScope scope(&crit_);
165 rules_.push_back(r);
166}
167
168void FirewallSocketServer::ClearRules() {
169 CritScope scope(&crit_);
170 rules_.clear();
171}
172
173bool FirewallSocketServer::Check(FirewallProtocol p,
174 const SocketAddress& src,
175 const SocketAddress& dst) {
176 CritScope scope(&crit_);
177 for (size_t i = 0; i < rules_.size(); ++i) {
178 const Rule& r = rules_[i];
179 if ((r.p != p) && (r.p != FP_ANY))
180 continue;
181 if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsNil())
182 continue;
183 if ((r.src.port() != src.port()) && (r.src.port() != 0))
184 continue;
185 if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsNil())
186 continue;
187 if ((r.dst.port() != dst.port()) && (r.dst.port() != 0))
188 continue;
189 return r.allow;
190 }
191 return true;
192}
193
194Socket* FirewallSocketServer::CreateSocket(int type) {
195 return CreateSocket(AF_INET, type);
196}
197
198Socket* FirewallSocketServer::CreateSocket(int family, int type) {
199 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
200}
201
202AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) {
203 return CreateAsyncSocket(AF_INET, type);
204}
205
206AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) {
207 return WrapSocket(server_->CreateAsyncSocket(family, type), type);
208}
209
210AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) {
211 if (!sock ||
212 (type == SOCK_STREAM && !tcp_sockets_enabled_) ||
213 (type == SOCK_DGRAM && !udp_sockets_enabled_)) {
214 LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied";
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000215 delete sock;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216 return NULL;
217 }
218 return new FirewallSocket(this, sock, type);
219}
220
221FirewallManager::FirewallManager() {
222}
223
224FirewallManager::~FirewallManager() {
225 assert(servers_.empty());
226}
227
228void FirewallManager::AddServer(FirewallSocketServer* server) {
229 CritScope scope(&crit_);
230 servers_.push_back(server);
231}
232
233void FirewallManager::RemoveServer(FirewallSocketServer* server) {
234 CritScope scope(&crit_);
235 servers_.erase(std::remove(servers_.begin(), servers_.end(), server),
236 servers_.end());
237}
238
239void FirewallManager::AddRule(bool allow, FirewallProtocol p,
240 FirewallDirection d, const SocketAddress& addr) {
241 CritScope scope(&crit_);
242 for (std::vector<FirewallSocketServer*>::const_iterator it =
243 servers_.begin(); it != servers_.end(); ++it) {
244 (*it)->AddRule(allow, p, d, addr);
245 }
246}
247
248void FirewallManager::ClearRules() {
249 CritScope scope(&crit_);
250 for (std::vector<FirewallSocketServer*>::const_iterator it =
251 servers_.begin(); it != servers_.end(); ++it) {
252 (*it)->ClearRules();
253 }
254}
255
256} // namespace talk_base