added port filter for outgoing connections

This commit is contained in:
Arvid Norberg 2007-06-01 01:05:57 +00:00
parent aea4e503c5
commit d0412a2244
8 changed files with 148 additions and 50 deletions

View File

@ -224,6 +224,7 @@ namespace libtorrent
bool is_aborted() const { return m_abort; } bool is_aborted() const { return m_abort; }
void set_ip_filter(ip_filter const& f); void set_ip_filter(ip_filter const& f);
void set_port_filter(port_filter const& f);
bool listen_on( bool listen_on(
std::pair<int, int> const& port_range std::pair<int, int> const& port_range
@ -351,6 +352,9 @@ namespace libtorrent
// filters incoming connections // filters incoming connections
ip_filter m_ip_filter; 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 // the peer id that is generated at the start of the session
peer_id m_peer_id; peer_id m_peer_id;

View File

@ -71,20 +71,82 @@ struct ip_range
namespace detail namespace detail
{ {
template<class Addr>
Addr zero()
{
typename Addr::bytes_type zero;
std::fill(zero.begin(), zero.end(), 0);
return Addr(zero);
}
template<>
inline boost::uint16_t zero<boost::uint16_t>() { return 0; }
template<class Addr>
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<typename iter::value_type>::max)())
{
*i += 1;
break;
}
*i = 0;
}
return Addr(tmp);
}
inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; }
template<class Addr>
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<typename iter::value_type>::max)();
}
return Addr(tmp);
}
inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; }
template<class Addr>
Addr max_addr()
{
typename Addr::bytes_type tmp;
std::fill(tmp.begin(), tmp.end()
, (std::numeric_limits<typename Addr::bytes_type::value_type>::max)());
return Addr(tmp);
}
template<>
inline boost::uint16_t max_addr<boost::uint16_t>()
{ return std::numeric_limits<boost::uint16_t>::max(); }
// this is the generic implementation of // this is the generic implementation of
// a filter for a specific address type. // a filter for a specific address type.
// it works with IPv4 and IPv6 // it works with IPv4 and IPv6
template<class Addr> template<class Addr>
class TORRENT_EXPORT filter_impl class filter_impl
{ {
public: public:
filter_impl() filter_impl()
{ {
typename Addr::bytes_type zero;
std::fill(zero.begin(), zero.end(), 0);
// make the entire ip-range non-blocked // make the entire ip-range non-blocked
m_access_list.insert(range(Addr(zero), 0)); m_access_list.insert(range(zero<Addr>(), 0));
} }
void add_rule(Addr first, Addr last, int flags) void add_rule(Addr first, Addr last, int flags)
@ -134,7 +196,7 @@ namespace detail
if ((j != m_access_list.end() if ((j != m_access_list.end()
&& minus_one(j->start) != last) && minus_one(j->start) != last)
|| (j == m_access_list.end() || (j == m_access_list.end()
&& last != max_addr())) && last != max_addr<Addr>()))
{ {
assert(j == m_access_list.end() || last < minus_one(j->start)); assert(j == m_access_list.end() || last < minus_one(j->start));
if (last_access != flags) if (last_access != flags)
@ -170,7 +232,7 @@ namespace detail
++i; ++i;
if (i == end) if (i == end)
r.last = max_addr(); r.last = max_addr<Addr>();
else else
r.last = minus_one(i->start); r.last = minus_one(i->start);
@ -181,48 +243,6 @@ namespace detail
private: 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<typename iter::value_type>::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<typename iter::value_type>::max)();
}
return Addr(tmp);
}
Addr max_addr() const
{
typename Addr::bytes_type tmp;
std::fill(tmp.begin(), tmp.end()
, (std::numeric_limits<typename Addr::bytes_type::value_type>::max)());
return Addr(tmp);
}
struct range struct range
{ {
range(Addr addr, int access = 0): start(addr), access(access) {} range(Addr addr, int access = 0): start(addr), access(access) {}
@ -270,6 +290,24 @@ private:
detail::filter_impl<address_v6> m_filter6; detail::filter_impl<address_v6> 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<boost::uint16_t> m_filter;
};
} }
#endif #endif

View File

@ -72,6 +72,7 @@ namespace libtorrent
struct torrent_plugin; struct torrent_plugin;
class torrent; class torrent;
class ip_filter; class ip_filter;
class port_filter;
class connection_queue; class connection_queue;
namespace aux namespace aux
@ -182,6 +183,7 @@ namespace libtorrent
#endif #endif
void set_ip_filter(ip_filter const& f); 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_peer_id(peer_id const& pid);
void set_key(int key); void set_key(int key);

View File

@ -69,6 +69,15 @@ namespace libtorrent
, m_filter6.export_filter()); , 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 void ip_filter::print() const
{ {

View File

@ -524,6 +524,8 @@ namespace libtorrent
int max_failcount = m_torrent->settings().max_failcount; int max_failcount = m_torrent->settings().max_failcount;
int min_reconnect_time = m_torrent->settings().min_reconnect_time; 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) for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
{ {
if (i->connection) continue; if (i->connection) continue;
@ -533,6 +535,8 @@ namespace libtorrent
if (i->failcount >= max_failcount) continue; if (i->failcount >= max_failcount) continue;
if (now - i->connected < seconds(i->failcount * min_reconnect_time)) if (now - i->connected < seconds(i->failcount * min_reconnect_time))
continue; continue;
if (ses.m_port_filter.access(i->ip.port()) & port_filter::blocked)
continue;
assert(i->connected <= now); assert(i->connected <= now);
@ -968,6 +972,19 @@ namespace libtorrent
if(remote.address() == address() || remote.port() == 0) if(remote.address() == address() || remote.port() == 0)
return; 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 try
{ {
iterator i; iterator i;
@ -986,8 +1003,6 @@ namespace libtorrent
if (i == m_peers.end()) if (i == m_peers.end())
{ {
aux::session_impl& ses = m_torrent->session();
// if the IP is blocked, don't add it // if the IP is blocked, don't add it
if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked) if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked)
{ {

View File

@ -143,6 +143,11 @@ namespace libtorrent
m_impl->set_ip_filter(f); 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) void session::set_peer_id(peer_id const& id)
{ {
m_impl->set_peer_id(id); m_impl->set_peer_id(id);

View File

@ -582,6 +582,12 @@ namespace libtorrent { namespace detail
m_checker_impl.m_abort = true; 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) void session_impl::set_ip_filter(ip_filter const& f)
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);

View File

@ -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; return 0;
} }