Home | History | Annotate | Download | only in base
      1 /*
      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 
     30 #include <assert.h>
     31 
     32 #include <algorithm>
     33 
     34 #include "talk/base/asyncsocket.h"
     35 #include "talk/base/logging.h"
     36 
     37 namespace talk_base {
     38 
     39 class 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 
    122 FirewallSocketServer::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 
    133 FirewallSocketServer::~FirewallSocketServer() {
    134   if (manager_)
    135     manager_->RemoveServer(this);
    136 
    137   if (server_ && should_delete_server_) {
    138     delete server_;
    139     server_ = NULL;
    140   }
    141 }
    142 
    143 void 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 
    156 void 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 
    168 void FirewallSocketServer::ClearRules() {
    169   CritScope scope(&crit_);
    170   rules_.clear();
    171 }
    172 
    173 bool 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 
    194 Socket* FirewallSocketServer::CreateSocket(int type) {
    195   return CreateSocket(AF_INET, type);
    196 }
    197 
    198 Socket* FirewallSocketServer::CreateSocket(int family, int type) {
    199   return WrapSocket(server_->CreateAsyncSocket(family, type), type);
    200 }
    201 
    202 AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) {
    203   return CreateAsyncSocket(AF_INET, type);
    204 }
    205 
    206 AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) {
    207   return WrapSocket(server_->CreateAsyncSocket(family, type), type);
    208 }
    209 
    210 AsyncSocket* 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";
    215     delete sock;
    216     return NULL;
    217   }
    218   return new FirewallSocket(this, sock, type);
    219 }
    220 
    221 FirewallManager::FirewallManager() {
    222 }
    223 
    224 FirewallManager::~FirewallManager() {
    225   assert(servers_.empty());
    226 }
    227 
    228 void FirewallManager::AddServer(FirewallSocketServer* server) {
    229   CritScope scope(&crit_);
    230   servers_.push_back(server);
    231 }
    232 
    233 void FirewallManager::RemoveServer(FirewallSocketServer* server) {
    234   CritScope scope(&crit_);
    235   servers_.erase(std::remove(servers_.begin(), servers_.end(), server),
    236                  servers_.end());
    237 }
    238 
    239 void 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 
    248 void 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
    257