From d0412a2244abfb292f48f9c0071b712838810bbe Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Fri, 1 Jun 2007 01:05:57 +0000 Subject: [PATCH] added port filter for outgoing connections --- include/libtorrent/aux_/session_impl.hpp | 4 + include/libtorrent/ip_filter.hpp | 134 +++++++++++++++-------- include/libtorrent/session.hpp | 2 + src/ip_filter.cpp | 9 ++ src/policy.cpp | 19 +++- src/session.cpp | 5 + src/session_impl.cpp | 6 + test/test_ip_filter.cpp | 19 ++++ 8 files changed, 148 insertions(+), 50 deletions(-) diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 6914d1455..589fcc1d6 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -224,6 +224,7 @@ namespace libtorrent bool is_aborted() const { return m_abort; } void set_ip_filter(ip_filter const& f); + void set_port_filter(port_filter const& f); bool listen_on( std::pair const& port_range @@ -351,6 +352,9 @@ namespace libtorrent // filters incoming connections ip_filter m_ip_filter; + + // filters outgoing connections + port_filter m_port_filter; // the peer id that is generated at the start of the session peer_id m_peer_id; diff --git a/include/libtorrent/ip_filter.hpp b/include/libtorrent/ip_filter.hpp index 1c62c553b..e89c3578a 100644 --- a/include/libtorrent/ip_filter.hpp +++ b/include/libtorrent/ip_filter.hpp @@ -71,20 +71,82 @@ struct ip_range namespace detail { + template + Addr zero() + { + typename Addr::bytes_type zero; + std::fill(zero.begin(), zero.end(), 0); + return Addr(zero); + } + + template<> + inline boost::uint16_t zero() { return 0; } + + template + Addr plus_one(Addr const& a) + { + typename Addr::bytes_type tmp(a.to_bytes()); + typedef typename Addr::bytes_type::reverse_iterator iter; + for (iter i = tmp.rbegin() + , end(tmp.rend()); i != end; ++i) + { + if (*i < (std::numeric_limits::max)()) + { + *i += 1; + break; + } + *i = 0; + } + return Addr(tmp); + } + + inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; } + + template + Addr minus_one(Addr const& a) + { + typename Addr::bytes_type tmp(a.to_bytes()); + typedef typename Addr::bytes_type::reverse_iterator iter; + for (iter i = tmp.rbegin() + , end(tmp.rend()); i != end; ++i) + { + if (*i > 0) + { + *i -= 1; + break; + } + *i = (std::numeric_limits::max)(); + } + return Addr(tmp); + } + + inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; } + + template + Addr max_addr() + { + typename Addr::bytes_type tmp; + std::fill(tmp.begin(), tmp.end() + , (std::numeric_limits::max)()); + return Addr(tmp); + } + + template<> + inline boost::uint16_t max_addr() + { return std::numeric_limits::max(); } + // this is the generic implementation of // a filter for a specific address type. // it works with IPv4 and IPv6 template - class TORRENT_EXPORT filter_impl + class filter_impl { public: filter_impl() { - typename Addr::bytes_type zero; - std::fill(zero.begin(), zero.end(), 0); // make the entire ip-range non-blocked - m_access_list.insert(range(Addr(zero), 0)); + m_access_list.insert(range(zero(), 0)); } void add_rule(Addr first, Addr last, int flags) @@ -134,7 +196,7 @@ namespace detail if ((j != m_access_list.end() && minus_one(j->start) != last) || (j == m_access_list.end() - && last != max_addr())) + && last != max_addr())) { assert(j == m_access_list.end() || last < minus_one(j->start)); if (last_access != flags) @@ -170,7 +232,7 @@ namespace detail ++i; if (i == end) - r.last = max_addr(); + r.last = max_addr(); else r.last = minus_one(i->start); @@ -181,48 +243,6 @@ namespace detail private: - Addr plus_one(Addr const& a) const - { - typename Addr::bytes_type tmp(a.to_bytes()); - typedef typename Addr::bytes_type::reverse_iterator iter; - for (iter i = tmp.rbegin() - , end(tmp.rend()); i != end; ++i) - { - if (*i < (std::numeric_limits::max)()) - { - *i += 1; - break; - } - *i = 0; - } - return Addr(tmp); - } - - Addr minus_one(Addr const& a) const - { - typename Addr::bytes_type tmp(a.to_bytes()); - typedef typename Addr::bytes_type::reverse_iterator iter; - for (iter i = tmp.rbegin() - , end(tmp.rend()); i != end; ++i) - { - if (*i > 0) - { - *i -= 1; - break; - } - *i = (std::numeric_limits::max)(); - } - return Addr(tmp); - } - - Addr max_addr() const - { - typename Addr::bytes_type tmp; - std::fill(tmp.begin(), tmp.end() - , (std::numeric_limits::max)()); - return Addr(tmp); - } - struct range { range(Addr addr, int access = 0): start(addr), access(access) {} @@ -270,6 +290,24 @@ private: detail::filter_impl m_filter6; }; +class TORRENT_EXPORT port_filter +{ +public: + + enum access_flags + { + blocked = 1 + }; + + void add_rule(boost::uint16_t first, boost::uint16_t last, int flags); + int access(boost::uint16_t port) const; + +private: + + detail::filter_impl m_filter; + +}; + } #endif diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 0c34f46f8..b209257a8 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -72,6 +72,7 @@ namespace libtorrent struct torrent_plugin; class torrent; class ip_filter; + class port_filter; class connection_queue; namespace aux @@ -182,6 +183,7 @@ namespace libtorrent #endif void set_ip_filter(ip_filter const& f); + void set_port_filter(port_filter const& f); void set_peer_id(peer_id const& pid); void set_key(int key); diff --git a/src/ip_filter.cpp b/src/ip_filter.cpp index 92ea711c7..cf368c4d1 100644 --- a/src/ip_filter.cpp +++ b/src/ip_filter.cpp @@ -69,6 +69,15 @@ namespace libtorrent , m_filter6.export_filter()); } + void port_filter::add_rule(boost::uint16_t first, boost::uint16_t last, int flags) + { + m_filter.add_rule(first, last, flags); + } + + int port_filter::access(boost::uint16_t port) const + { + return m_filter.access(port); + } /* void ip_filter::print() const { diff --git a/src/policy.cpp b/src/policy.cpp index 7f7f42008..b864e4d82 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -524,6 +524,8 @@ namespace libtorrent int max_failcount = m_torrent->settings().max_failcount; int min_reconnect_time = m_torrent->settings().min_reconnect_time; + aux::session_impl& ses = m_torrent->session(); + for (iterator i = m_peers.begin(); i != m_peers.end(); ++i) { if (i->connection) continue; @@ -533,6 +535,8 @@ namespace libtorrent if (i->failcount >= max_failcount) continue; if (now - i->connected < seconds(i->failcount * min_reconnect_time)) continue; + if (ses.m_port_filter.access(i->ip.port()) & port_filter::blocked) + continue; assert(i->connected <= now); @@ -968,6 +972,19 @@ namespace libtorrent if(remote.address() == address() || remote.port() == 0) return; + aux::session_impl& ses = m_torrent->session(); + + port_filter const& pf = ses.m_port_filter; + if (pf.access(remote.port()) & port_filter::blocked) + { + if (ses.m_alerts.should_post(alert::info)) + { + ses.m_alerts.post_alert(peer_blocked_alert(remote.address() + , "outgoing port blocked, peer not added to peer list")); + } + return; + } + try { iterator i; @@ -986,8 +1003,6 @@ namespace libtorrent if (i == m_peers.end()) { - aux::session_impl& ses = m_torrent->session(); - // if the IP is blocked, don't add it if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked) { diff --git a/src/session.cpp b/src/session.cpp index 650654dbf..c527f5234 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -143,6 +143,11 @@ namespace libtorrent m_impl->set_ip_filter(f); } + void session::set_port_filter(port_filter const& f) + { + m_impl->set_port_filter(f); + } + void session::set_peer_id(peer_id const& id) { m_impl->set_peer_id(id); diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 1e4cc0960..0a349a97e 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -582,6 +582,12 @@ namespace libtorrent { namespace detail m_checker_impl.m_abort = true; } + void session_impl::set_port_filter(port_filter const& f) + { + mutex_t::scoped_lock l(m_mutex); + m_port_filter = f; + } + void session_impl::set_ip_filter(ip_filter const& f) { mutex_t::scoped_lock l(m_mutex); diff --git a/test/test_ip_filter.cpp b/test/test_ip_filter.cpp index 1d701ce2c..f38ca6c52 100644 --- a/test/test_ip_filter.cpp +++ b/test/test_ip_filter.cpp @@ -171,6 +171,25 @@ int test_main() } + port_filter pf; + + // default contructed port filter should allow any port + TEST_CHECK(pf.access(0) == 0); + TEST_CHECK(pf.access(65535) == 0); + TEST_CHECK(pf.access(6881) == 0); + + // block port 100 - 300 + pf.add_rule(100, 300, port_filter::blocked); + + TEST_CHECK(pf.access(0) == 0); + TEST_CHECK(pf.access(99) == 0); + TEST_CHECK(pf.access(100) == port_filter::blocked); + TEST_CHECK(pf.access(150) == port_filter::blocked); + TEST_CHECK(pf.access(300) == port_filter::blocked); + TEST_CHECK(pf.access(301) == 0); + TEST_CHECK(pf.access(6881) == 0); + TEST_CHECK(pf.access(65535) == 0); + return 0; }