Skip to content

Commit

Permalink
Peer blacklist (#251)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kolcha authored Apr 25, 2021
1 parent 853c535 commit 168f4f8
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 63 deletions.
1 change: 1 addition & 0 deletions src/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ add_library(qbt_base STATIC
bittorrent/peeraddress.cpp
bittorrent/peerinfo.cpp
bittorrent/peer_blacklist.hpp
bittorrent/peer_filter.hpp
bittorrent/peer_filter_plugin.hpp
bittorrent/peer_logger.hpp
bittorrent/peer_whitelist.hpp
Expand Down
34 changes: 34 additions & 0 deletions src/base/bittorrent/peer_blacklist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@

#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 @@ -96,3 +100,33 @@ 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, handshake);
*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);
}
67 changes: 67 additions & 0 deletions src/base/bittorrent/peer_filter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#pragma once

#include <algorithm>
#include <fstream>
#include <string>

#include <QFileInfo>
#include <QRegularExpression>
#include <QString>
#include <QVector>

#include <libtorrent/peer_info.hpp>

#include "base/logger.h"

namespace {

bool qregex_has_match(const QRegularExpression& re, const QString& str)
{
auto m = re.match(str);
return m.hasMatch();
}

}

class peer_filter
{
public:
explicit peer_filter(const QString& filter_file)
{
QString log_tag = QFileInfo(filter_file).fileName();

std::ifstream ifs(filter_file.toStdString());
std::string peer_id, client;
while (ifs >> peer_id >> client) {
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");

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

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

if (peer_id_re.isValid() && client_re.isValid())
m_filters.append({peer_id_re, client_re});
}
}

bool match_peer(const lt::peer_info& info, bool skip_name) const
{
QString peer_id = QString::fromLatin1(info.pid.data(), 8);
QString client = QString::fromStdString(info.client);
return std::any_of(m_filters.begin(), m_filters.end(),
[&](const auto& filter) {
return qregex_has_match(filter[0], peer_id) &&
(skip_name || qregex_has_match(filter[1], client));
});
}

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

private:
QVector<QVector<QRegularExpression>> m_filters;
};
69 changes: 6 additions & 63 deletions src/base/bittorrent/peer_whitelist.hpp
Original file line number Diff line number Diff line change
@@ -1,76 +1,14 @@
#pragma once

#include <algorithm>
#include <fstream>
#include <string>

#include <QDir>
#include <QRegularExpression>
#include <QString>
#include <QVector>

#include <libtorrent/peer_info.hpp>

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

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


namespace {

bool qregex_has_match(const QRegularExpression& re, const QString& str)
{
auto m = re.match(str);
return m.hasMatch();
}

}

class peer_filter
{
public:
explicit peer_filter(const QString& filter_file)
{
std::ifstream ifs(filter_file.toStdString());
std::string peer_id, client;
while (ifs >> peer_id >> client) {
QRegularExpression peer_id_re(QString::fromStdString(peer_id));
QRegularExpression client_re(QString::fromStdString(client));

QString msg_tmpl("whitelist: invalid %1 matching expression '%2' detected, ignoring rule");

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

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

if (peer_id_re.isValid() && client_re.isValid())
m_filters.append({peer_id_re, client_re});
}

if (m_filters.isEmpty())
LogMsg("whitelist: no rules were loaded, any connections will be dropped", Log::CRITICAL);
}

bool match_peer(const lt::peer_info& info, bool skip_name) const
{
QString peer_id = QString::fromLatin1(info.pid.data(), 8);
QString client = QString::fromStdString(info.client);
return std::any_of(m_filters.begin(), m_filters.end(),
[&](const auto& filter) {
return qregex_has_match(filter[0], peer_id) &&
(skip_name || qregex_has_match(filter[1], client));
});
}

private:
QVector<QVector<QRegularExpression>> m_filters;
};


std::shared_ptr<lt::torrent_plugin> create_peer_whitelist_plugin(lt::torrent_handle const&, client_data)
{
QDir qbt_data_dir(specialFolderLocation(SpecialFolder::Data));
Expand All @@ -84,6 +22,11 @@ std::shared_ptr<lt::torrent_plugin> create_peer_whitelist_plugin(lt::torrent_han

// 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_whitelist.txt' has no valid rules, do not enabling whitelist plugin", Log::WARNING);
return nullptr;
}

auto peer_not_in_list = [&](const lt::peer_info& info, bool handshake, bool* stop_filtering) {
bool matched = filter.match_peer(info, handshake);
Expand Down
1 change: 1 addition & 0 deletions src/base/bittorrent/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +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<NativeSessionExtension>());
Expand Down

0 comments on commit 168f4f8

Please sign in to comment.