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; }
void set_ip_filter(ip_filter const& f);
void set_port_filter(port_filter const& f);
bool listen_on(
std::pair<int, int> 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;

View File

@ -71,20 +71,82 @@ struct ip_range
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
// a filter for a specific address type.
// it works with IPv4 and IPv6
template<class Addr>
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<Addr>(), 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<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<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<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
{
range(Addr addr, int access = 0): start(addr), access(access) {}
@ -270,6 +290,24 @@ private:
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

View File

@ -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);

View File

@ -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
{

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

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;
}