Skip to content

Commit

Permalink
Refactor blacklist/whitelist filter implementation (#253)
Browse files Browse the repository at this point in the history
* refactored peer black/whitelist implementation

* improved filter loggins

- report line number containing invalid expression
- print warning and do not enable filter when no rules loaded
- report loaded rules count
  • Loading branch information
Kolcha authored May 2, 2021
1 parent 3d996f6 commit de4a8f6
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 87 deletions.
2 changes: 1 addition & 1 deletion src/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ add_library(qbt_base STATIC
bittorrent/peer_blacklist.hpp
bittorrent/peer_filter.hpp
bittorrent/peer_filter_plugin.hpp
bittorrent/peer_filter_session_plugin.hpp
bittorrent/peer_logger.hpp
bittorrent/peer_whitelist.hpp
bittorrent/portforwarderimpl.cpp
bittorrent/resumedatasavingmanager.cpp
bittorrent/session.cpp
Expand Down
34 changes: 0 additions & 34 deletions src/base/bittorrent/peer_blacklist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@

#include <libtorrent/torrent_info.hpp>

#include <QDir>
#include <QHostAddress>

#include "base/logger.h"
#include "base/net/geoipmanager.h"
#include "base/profile.h"

#include "peer_filter_plugin.hpp"
#include "peer_filter.hpp"
#include "peer_logger.hpp"

// bad peer filter
Expand Down Expand Up @@ -100,33 +96,3 @@ std::shared_ptr<lt::torrent_plugin> create_drop_bittorrent_media_player_plugin(l
{
return create_peer_action_plugin(th, wrap_filter(is_bittorrent_media_player, "bittorrent media player"), drop_connection);
}

std::shared_ptr<lt::torrent_plugin> create_peer_blacklist_plugin(lt::torrent_handle const&, client_data)
{
QDir qbt_data_dir(specialFolderLocation(SpecialFolder::Data));

QString filter_file = qbt_data_dir.absoluteFilePath(QStringLiteral("peer_blacklist.txt"));
// do not create plugin if filter file doesn't exists
if (!QFile::exists(filter_file)) {
LogMsg("'peer_blacklist.txt' doesn't exist, do not enabling blacklist plugin", Log::INFO);
return nullptr;
}

// create filter object only once
static peer_filter filter(filter_file);
// do not create plugin if no rules were loaded
if (filter.is_empty()) {
LogMsg("'peer_blacklist.txt' has no valid rules, do not enabling blacklist plugin", Log::WARNING);
return nullptr;
}

auto peer_in_list = [&](const lt::peer_info& info, bool handshake, bool* stop_filtering) {
bool matched = filter.match_peer(info, false);
*stop_filtering = !handshake && !matched;
if (matched)
peer_logger_singleton::instance().log_peer(info, "blacklist");
return matched;
};

return std::make_shared<peer_action_plugin>(std::move(peer_in_list), drop_connection);
}
8 changes: 5 additions & 3 deletions src/base/bittorrent/peer_filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ class peer_filter
QRegularExpression peer_id_re(QString::fromStdString(peer_id));
QRegularExpression client_re(QString::fromStdString(client));

QString msg_tmpl("'%1': invalid %2 matching expression '%3' detected, ignoring rule");
QString msg_tmpl("'%1': invalid %2 matching expression '%3' detected at line %4, ignoring rule");
int line = m_filters.size() + 1;

if (!peer_id_re.isValid())
LogMsg(msg_tmpl.arg(log_tag).arg("peer id").arg(peer_id_re.pattern()), Log::WARNING);
LogMsg(msg_tmpl.arg(log_tag).arg("peer id").arg(peer_id_re.pattern()).arg(line), Log::WARNING);

if (!client_re.isValid())
LogMsg(msg_tmpl.arg(log_tag).arg("client name").arg(client_re.pattern()), Log::WARNING);
LogMsg(msg_tmpl.arg(log_tag).arg("client name").arg(client_re.pattern()).arg(line), Log::WARNING);

if (peer_id_re.isValid() && client_re.isValid())
m_filters.append({peer_id_re, client_re});
Expand All @@ -61,6 +62,7 @@ class peer_filter
}

bool is_empty() const { return m_filters.isEmpty(); }
int rules_count() const { return m_filters.size(); }

private:
QVector<QVector<QRegularExpression>> m_filters;
Expand Down
85 changes: 85 additions & 0 deletions src/base/bittorrent/peer_filter_session_plugin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once

#include <QDir>

#include "base/logger.h"
#include "base/profile.h"

#include "peer_filter_plugin.hpp"
#include "peer_filter.hpp"
#include "peer_logger.hpp"

// filter factory function
std::unique_ptr<peer_filter> create_peer_filter(const QString& filename)
{
QDir qbt_data_dir(specialFolderLocation(SpecialFolder::Data));

QString filter_file = qbt_data_dir.absoluteFilePath(filename);
// do not create plugin if filter file doesn't exists
if (!QFile::exists(filter_file)) {
LogMsg(QString("'%1' doesn't exist, do not enabling filter").arg(filename), Log::NORMAL);
return nullptr;
}

auto filter = std::make_unique<peer_filter>(filter_file);
if (filter->is_empty()) {
LogMsg(QString("'%1' has no valid rules, do not enabling filter").arg(filename), Log::WARNING);
filter.reset();
} else {
LogMsg(QString("'%1' contains %2 valid rules").arg(filename).arg(filter->rules_count()), Log::INFO);
}

return filter;
}


// drop connection action
void drop_peer_connection(lt::peer_connection_handle ph)
{
ph.disconnect(boost::asio::error::connection_refused, lt::operation_t::bittorrent, lt::disconnect_severity_t{0});
}


class peer_filter_session_plugin final : public lt::plugin
{
public:
peer_filter_session_plugin()
: m_blacklist(create_peer_filter(QStringLiteral("peer_blacklist.txt")))
, m_whitelist(create_peer_filter(QStringLiteral("peer_whitelist.txt")))
{
}

std::shared_ptr<lt::torrent_plugin> new_torrent(const lt::torrent_handle&, client_data) override
{
// do not waste CPU and memory for useless objects when no filters are enabled
if (!m_blacklist && !m_whitelist)
return nullptr;
return std::make_shared<peer_action_plugin>([this](auto&&... args) { return filter(args...); }, drop_peer_connection);
}

protected:
bool filter(const lt::peer_info& info, bool handshake, bool* stop_filtering) const
{
if (m_blacklist) {
bool matched = m_blacklist->match_peer(info, false);
*stop_filtering = !handshake && !matched;
if (matched)
peer_logger_singleton::instance().log_peer(info, "blacklist");
return matched;
}

if (m_whitelist) {
bool matched = m_whitelist->match_peer(info, handshake);
*stop_filtering = !handshake && matched;
if (!matched)
peer_logger_singleton::instance().log_peer(info, "whitelist");
return !matched;
}

return false;
}

private:
std::unique_ptr<peer_filter> m_blacklist;
std::unique_ptr<peer_filter> m_whitelist;
};
46 changes: 0 additions & 46 deletions src/base/bittorrent/peer_whitelist.hpp

This file was deleted.

5 changes: 2 additions & 3 deletions src/base/bittorrent/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
#include "magneturi.h"
#include "nativesessionextension.h"
#include "peer_blacklist.hpp"
#include "peer_whitelist.hpp"
#include "peer_filter_session_plugin.hpp"
#include "portforwarderimpl.h"
#include "resumedatasavingmanager.h"
#include "statistics.h"
Expand Down Expand Up @@ -1207,8 +1207,7 @@ void Session::initializeNativeSession()
}
if (isAutoBanBTPlayerPeerEnabled())
m_nativeSession->add_extension(&create_drop_bittorrent_media_player_plugin);
m_nativeSession->add_extension(&create_peer_blacklist_plugin);
m_nativeSession->add_extension(&create_peer_whitelist_plugin);
m_nativeSession->add_extension(std::make_shared<peer_filter_session_plugin>());

m_nativeSession->add_extension(std::make_shared<NativeSessionExtension>());
}
Expand Down

0 comments on commit de4a8f6

Please sign in to comment.