808 lines
31 KiB
Diff
808 lines
31 KiB
Diff
--- a/src/base/bittorrent/peerinfo.cpp
|
|
+++ b/src/base/bittorrent/peerinfo.cpp
|
|
@@ -186,11 +186,26 @@ PeerAddress PeerInfo::address() const
|
|
m_nativeInfo.ip.port());
|
|
}
|
|
|
|
+int PeerInfo::port() const
|
|
+{
|
|
+ return m_nativeInfo.ip.port();
|
|
+}
|
|
+
|
|
QString PeerInfo::client() const
|
|
{
|
|
return QString::fromStdString(m_nativeInfo.client);
|
|
}
|
|
|
|
+QString PeerInfo::pid() const
|
|
+{
|
|
+ return QString::fromStdString(m_nativeInfo.pid.to_string());
|
|
+}
|
|
+
|
|
+QString PeerInfo::pidtoclient() const
|
|
+{
|
|
+ return QString::fromStdString(libt::identify_client(m_nativeInfo.pid));
|
|
+}
|
|
+
|
|
qreal PeerInfo::progress() const
|
|
{
|
|
return m_nativeInfo.progress;
|
|
--- a/src/base/bittorrent/peerinfo.h
|
|
+++ b/src/base/bittorrent/peerinfo.h
|
|
@@ -34,6 +34,7 @@
|
|
#include <QHostAddress>
|
|
|
|
#include <libtorrent/peer_info.hpp>
|
|
+#include <libtorrent/identify_client.hpp>
|
|
|
|
namespace BitTorrent
|
|
{
|
|
@@ -85,7 +86,10 @@ namespace BitTorrent
|
|
bool isPlaintextEncrypted() const;
|
|
|
|
PeerAddress address() const;
|
|
+ int port() const;
|
|
QString client() const;
|
|
+ QString pid() const;
|
|
+ QString pidtoclient() const;
|
|
qreal progress() const;
|
|
int payloadUpSpeed() const;
|
|
int payloadDownSpeed() const;
|
|
--- a/src/base/bittorrent/session.cpp
|
|
+++ b/src/base/bittorrent/session.cpp
|
|
@@ -69,6 +69,7 @@
|
|
#endif
|
|
|
|
#include "base/algorithm.h"
|
|
+#include "base/bittorrent/peerinfo.h"
|
|
#include "base/exceptions.h"
|
|
#include "base/global.h"
|
|
#include "base/logger.h"
|
|
@@ -335,6 +336,8 @@ Session::Session(QObject *parent)
|
|
, m_isAltGlobalSpeedLimitEnabled(BITTORRENT_SESSION_KEY("UseAlternativeGlobalSpeedLimit"), false)
|
|
, m_isBandwidthSchedulerEnabled(BITTORRENT_SESSION_KEY("BandwidthSchedulerEnabled"), false)
|
|
, m_saveResumeDataInterval(BITTORRENT_SESSION_KEY("SaveResumeDataInterval"), 60)
|
|
+ , m_autoBanUnknownPeer(BITTORRENT_SESSION_KEY("AutoBanUnknownPeer"), true)
|
|
+ , m_showTrackerAuthWindow(BITTORRENT_SESSION_KEY("ShowTrackerAuthWindow"), true)
|
|
, m_port(BITTORRENT_SESSION_KEY("Port"), 8999)
|
|
, m_useRandomPort(BITTORRENT_SESSION_KEY("UseRandomPort"), false)
|
|
, m_networkInterface(BITTORRENT_SESSION_KEY("Interface"))
|
|
@@ -502,6 +505,7 @@ Session::Session(QObject *parent)
|
|
libt::ip_filter filter;
|
|
processBannedIPs(filter);
|
|
m_nativeSession->set_ip_filter(filter);
|
|
+ loadOfflineFilter();
|
|
}
|
|
|
|
m_categories = map_cast(m_storedCategories);
|
|
@@ -518,6 +522,17 @@ Session::Session(QObject *parent)
|
|
connect(m_refreshTimer, &QTimer::timeout, this, &Session::refresh);
|
|
m_refreshTimer->start();
|
|
|
|
+ // Unban Timer
|
|
+ m_unbanTimer = new QTimer(this);
|
|
+ m_unbanTimer->setInterval(500);
|
|
+ connect(m_unbanTimer, &QTimer::timeout, this, &Session::processUnbanRequest);
|
|
+
|
|
+ // Ban Timer
|
|
+ m_banTimer = new QTimer(this);
|
|
+ m_banTimer->setInterval(500);
|
|
+ connect(m_banTimer, &QTimer::timeout, this, &Session::autoBanBadClient);
|
|
+ m_banTimer->start();
|
|
+
|
|
m_statistics = new Statistics(this);
|
|
|
|
updateSeedingLimitTimer();
|
|
@@ -1077,6 +1092,7 @@ void Session::configure()
|
|
enableIPFilter();
|
|
else
|
|
disableIPFilter();
|
|
+ loadOfflineFilter();
|
|
m_IPFilteringChanged = false;
|
|
}
|
|
|
|
@@ -1905,6 +1921,95 @@ void Session::banIP(const QString &ip)
|
|
}
|
|
}
|
|
|
|
+bool Session::checkAccessFlags(const QString &ip)
|
|
+{
|
|
+ libt::ip_filter filter = m_nativeSession->get_ip_filter();
|
|
+ boost::system::error_code ec;
|
|
+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec);
|
|
+ Q_ASSERT(!ec);
|
|
+ if (ec) return false;
|
|
+ return filter.access(addr);
|
|
+}
|
|
+
|
|
+void Session::tempblockIP(const QString &ip)
|
|
+{
|
|
+ libt::ip_filter filter = m_nativeSession->get_ip_filter();
|
|
+ boost::system::error_code ec;
|
|
+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec);
|
|
+ Q_ASSERT(!ec);
|
|
+ if (ec) return;
|
|
+ filter.add_rule(addr, addr, libt::ip_filter::blocked);
|
|
+ m_nativeSession->set_ip_filter(filter);
|
|
+ insertQueue(ip);
|
|
+}
|
|
+
|
|
+void Session::removeBlockedIP(const QString &ip)
|
|
+{
|
|
+ libt::ip_filter filter = m_nativeSession->get_ip_filter();
|
|
+ boost::system::error_code ec;
|
|
+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec);
|
|
+ Q_ASSERT(!ec);
|
|
+ if (ec) return;
|
|
+ filter.add_rule(addr, addr, 0);
|
|
+ m_nativeSession->set_ip_filter(filter);
|
|
+}
|
|
+
|
|
+void Session::eraseIPFilter()
|
|
+{
|
|
+ q_bannedIPs.clear();
|
|
+ q_unbanTime.clear();
|
|
+ if (isIPFilteringEnabled()) {
|
|
+ enableIPFilter();
|
|
+ } else {
|
|
+ disableIPFilter();
|
|
+ loadOfflineFilter();
|
|
+ }
|
|
+}
|
|
+
|
|
+void Session::autoBanBadClient()
|
|
+{
|
|
+ const BitTorrent::SessionStatus tStatus = BitTorrent::Session::instance()->status();
|
|
+ if (tStatus.peersCount > 0) {
|
|
+ bool m_AutoBan = BitTorrent::Session::instance()->isAutoBanUnknownPeerEnabled();
|
|
+ foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents()) {
|
|
+ QList<BitTorrent::PeerInfo> peers = torrent->peers();
|
|
+ foreach (const BitTorrent::PeerInfo &peer, peers) {
|
|
+ BitTorrent::PeerAddress addr = peer.address();
|
|
+ if (addr.ip.isNull()) continue;
|
|
+ QString ip = addr.ip.toString();
|
|
+ int port = peer.port();
|
|
+ QString client = peer.client();
|
|
+ QString ptoc = peer.pidtoclient();
|
|
+ QString pid = peer.pid().left(8);
|
|
+ QString country = peer.country();
|
|
+
|
|
+ QRegExp IDFilter("-(XL|SD|XF|QD|BN|DL)(\\d+)-");
|
|
+ QRegExp UAFilter("\\d+.\\d+.\\d+.\\d+");
|
|
+ if (IDFilter.exactMatch(pid) || UAFilter.exactMatch(client)) {
|
|
+ qDebug("Auto Banning bad Peer %s...", ip.toLocal8Bit().data());
|
|
+ Logger::instance()->addMessage(tr("Auto banning bad Peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(pid).arg(ptoc).arg(country));
|
|
+ tempblockIP(ip);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if(m_AutoBan) {
|
|
+ if (client.contains("Unknown") && country == "CN") {
|
|
+ qDebug("Auto Banning Unknown Peer %s...", ip.toLocal8Bit().data());
|
|
+ Logger::instance()->addMessage(tr("Auto banning Unknown Peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(pid).arg(ptoc).arg(country));
|
|
+ tempblockIP(ip);
|
|
+ continue;
|
|
+ }
|
|
+ if (port >= 65000 && country == "CN" && client.contains("Transmission")) {
|
|
+ qDebug("Auto Banning Offline Downloader %s...", ip.toLocal8Bit().data());
|
|
+ Logger::instance()->addMessage(tr("Auto banning Offline Downloader '%1:%2'...'%3'...'%4'...'%5'").arg(ip).arg(port).arg(pid).arg(ptoc).arg(country));
|
|
+ tempblockIP(ip);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
// Delete a torrent from the session, given its hash
|
|
// deleteLocalFiles = true means that the torrent will be removed from the hard-drive too
|
|
bool Session::deleteTorrent(const QString &hash, bool deleteLocalFiles)
|
|
@@ -2787,6 +2892,30 @@ void Session::setSaveResumeDataInterval(
|
|
}
|
|
}
|
|
|
|
+bool Session::isAutoBanUnknownPeerEnabled() const
|
|
+{
|
|
+ return m_autoBanUnknownPeer;
|
|
+}
|
|
+
|
|
+void Session::setAutoBanUnknownPeer(bool value)
|
|
+{
|
|
+ if (value != isAutoBanUnknownPeerEnabled()) {
|
|
+ m_autoBanUnknownPeer = value;
|
|
+ }
|
|
+}
|
|
+
|
|
+bool Session::isShowTrackerAuthWindow() const
|
|
+{
|
|
+ return m_showTrackerAuthWindow;
|
|
+}
|
|
+
|
|
+void Session::setShowTrackerAuthWindow(bool value)
|
|
+{
|
|
+ if (value != isShowTrackerAuthWindow()) {
|
|
+ m_showTrackerAuthWindow = value;
|
|
+ }
|
|
+}
|
|
+
|
|
int Session::port() const
|
|
{
|
|
static int randomPort = Utils::Random::rand(1024, 65535);
|
|
@@ -3877,6 +4006,220 @@ void Session::disableIPFilter()
|
|
m_nativeSession->set_ip_filter(filter);
|
|
}
|
|
|
|
+// Insert banned IP to Queue
|
|
+void Session::insertQueue(QString ip)
|
|
+{
|
|
+ q_bannedIPs.enqueue(ip);
|
|
+ q_unbanTime.enqueue(QDateTime::currentMSecsSinceEpoch() + 60 * 60 * 1000);
|
|
+
|
|
+ if (!m_unbanTimer->isActive()) {
|
|
+ m_unbanTimer->start();
|
|
+ }
|
|
+}
|
|
+
|
|
+// Process Unban Queue
|
|
+void Session::processUnbanRequest()
|
|
+{
|
|
+ if (q_bannedIPs.isEmpty() && q_unbanTime.isEmpty()) {
|
|
+ m_unbanTimer->stop();
|
|
+ }
|
|
+ else if (m_isActive) {
|
|
+ return;
|
|
+ }
|
|
+ else {
|
|
+ m_isActive = true;
|
|
+ int64_t currentTime = QDateTime::currentMSecsSinceEpoch();
|
|
+ int64_t nextTime = q_unbanTime.dequeue();
|
|
+ int delayTime = int(nextTime - currentTime);
|
|
+ QString nextIP = q_bannedIPs.dequeue();
|
|
+ if (delayTime < 0) {
|
|
+ QTimer::singleShot(0, [=] { BitTorrent::Session::instance()->removeBlockedIP(nextIP); m_isActive = false; });
|
|
+ }
|
|
+ else {
|
|
+ QTimer::singleShot(delayTime, [=] { BitTorrent::Session::instance()->removeBlockedIP(nextIP); m_isActive = false; });
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+// Handle ipfilter.dat
|
|
+int trim(char* const data, int start, int end)
|
|
+{
|
|
+ if (start >= end) return start;
|
|
+ int newStart = start;
|
|
+
|
|
+ for (int i = start; i <= end; ++i) {
|
|
+ if (isspace(data[i]) != 0) {
|
|
+ data[i] = '\0';
|
|
+ }
|
|
+ else {
|
|
+ newStart = i;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (int i = end; i >= start; --i) {
|
|
+ if (isspace(data[i]) != 0)
|
|
+ data[i] = '\0';
|
|
+ else
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return newStart;
|
|
+}
|
|
+
|
|
+int findAndNullDelimiter(char *const data, char delimiter, int start, int end)
|
|
+{
|
|
+ for (int i = start; i <= end; ++i) {
|
|
+ if (data[i] == delimiter) {
|
|
+ data[i] = '\0';
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int Session::parseOfflineFilterFile(QString ipDat, libt::ip_filter &filter)
|
|
+{
|
|
+ int ruleCount = 0;
|
|
+ QFile file(ipDat);
|
|
+ if (!file.exists()) return ruleCount;
|
|
+
|
|
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
+ LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL);
|
|
+ return ruleCount;
|
|
+ }
|
|
+
|
|
+ std::vector<char> buffer(2 * 1024 * 1024, 0); // seems a bit faster than QVector
|
|
+ qint64 bytesRead = 0;
|
|
+ int offset = 0;
|
|
+ int start = 0;
|
|
+ int endOfLine = -1;
|
|
+ int nbLine = 0;
|
|
+
|
|
+ while (true) {
|
|
+ bytesRead = file.read(buffer.data() + offset, 2 * 1024 * 1024 - offset - 1);
|
|
+ if (bytesRead < 0)
|
|
+ break;
|
|
+ int dataSize = bytesRead + offset;
|
|
+ if (bytesRead == 0 && dataSize == 0)
|
|
+ break;
|
|
+
|
|
+ for (start = 0; start < dataSize; ++start) {
|
|
+ endOfLine = -1;
|
|
+ // The file might have ended without the last line having a newline
|
|
+ if (!(bytesRead == 0 && dataSize > 0)) {
|
|
+ for (int i = start; i < dataSize; ++i) {
|
|
+ if (buffer[i] == '\n') {
|
|
+ endOfLine = i;
|
|
+ // We need to NULL the newline in case the line has only an IP range.
|
|
+ // In that case the parser won't work for the end IP, because it ends
|
|
+ // with the newline and not with a number.
|
|
+ buffer[i] = '\0';
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else {
|
|
+ endOfLine = dataSize;
|
|
+ buffer[dataSize] = '\0';
|
|
+ }
|
|
+
|
|
+ if (endOfLine == -1) {
|
|
+ // read the next chunk from file
|
|
+ // but first move(copy) the leftover data to the front of the buffer
|
|
+ offset = dataSize - start;
|
|
+ memmove(buffer.data(), buffer.data() + start, offset);
|
|
+ break;
|
|
+ }
|
|
+ else {
|
|
+ ++nbLine;
|
|
+ }
|
|
+
|
|
+ if ((buffer[start] == '#')
|
|
+ || ((buffer[start] == '/') && ((start + 1 < dataSize) && (buffer[start + 1] == '/')))) {
|
|
+ start = endOfLine;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // Each line should follow this format:
|
|
+ // 001.009.096.105 - 001.009.096.105 , 000 , Some organization
|
|
+ // The 3rd entry is access level and if above 127 the IP range isn't blocked.
|
|
+ int firstComma = findAndNullDelimiter(buffer.data(), ',', start, endOfLine);
|
|
+ if (firstComma != -1)
|
|
+ findAndNullDelimiter(buffer.data(), ',', firstComma + 1, endOfLine);
|
|
+
|
|
+ // Check if there is an access value (apparently not mandatory)
|
|
+ if (firstComma != -1) {
|
|
+ // There is possibly one
|
|
+ const long int nbAccess = strtol(buffer.data() + firstComma + 1, nullptr, 10);
|
|
+ // Ignoring this rule because access value is too high
|
|
+ if (nbAccess > 127L) {
|
|
+ start = endOfLine;
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // IP Range should be split by a dash
|
|
+ int endOfIPRange = ((firstComma == -1) ? (endOfLine - 1) : (firstComma - 1));
|
|
+ int delimIP = findAndNullDelimiter(buffer.data(), '-', start, endOfIPRange);
|
|
+ if (delimIP == -1) {
|
|
+ start = endOfLine;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ boost::system::error_code ec;
|
|
+ int newStart = trim(buffer.data(), start, delimIP - 1);
|
|
+ libt::address startAddr = libt::address::from_string(buffer.data() + newStart, ec);
|
|
+ Q_ASSERT(!ec);
|
|
+ if (ec) {
|
|
+ start = endOfLine;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ newStart = trim(buffer.data(), delimIP + 1, endOfIPRange);
|
|
+ libt::address endAddr = libt::address::from_string(buffer.data() + newStart, ec);
|
|
+ Q_ASSERT(!ec);
|
|
+ if (ec) {
|
|
+ start = endOfLine;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if ((startAddr.is_v4() != endAddr.is_v4())
|
|
+ || (startAddr.is_v6() != endAddr.is_v6())) {
|
|
+ start = endOfLine;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ start = endOfLine;
|
|
+
|
|
+ filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked);
|
|
+ ++ruleCount;
|
|
+ }
|
|
+
|
|
+ if (start >= dataSize)
|
|
+ offset = 0;
|
|
+ }
|
|
+
|
|
+ return ruleCount;
|
|
+}
|
|
+
|
|
+void Session::loadOfflineFilter() {
|
|
+ int Count = 0;
|
|
+ libt::ip_filter offlineFilter = m_nativeSession->get_ip_filter();
|
|
+
|
|
+#if defined(Q_OS_WIN)
|
|
+ Count = parseOfflineFilterFile("./ipfilter.dat", offlineFilter);
|
|
+#endif
|
|
+
|
|
+#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
|
+ Count = parseOfflineFilterFile(QDir::home().absoluteFilePath(".config")+"/qBittorrent/ipfilter.dat", offlineFilter);
|
|
+#endif
|
|
+
|
|
+ m_nativeSession->set_ip_filter(offlineFilter);
|
|
+ Logger::instance()->addMessage(tr("Successfully parsed the offline downloader IP filter: %1 rules were applied.", "%1 is a number").arg(Count));
|
|
+}
|
|
+
|
|
void Session::recursiveTorrentDownload(const InfoHash &hash)
|
|
{
|
|
TorrentHandle *const torrent = m_torrents.value(hash);
|
|
@@ -4063,6 +4406,7 @@ void Session::handleIPFilterParsed(int r
|
|
}
|
|
Logger::instance()->addMessage(tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount));
|
|
emit IPFilterParsed(false, ruleCount);
|
|
+ loadOfflineFilter();
|
|
}
|
|
|
|
void Session::handleIPFilterError()
|
|
--- a/src/base/bittorrent/session.h
|
|
+++ b/src/base/bittorrent/session.h
|
|
@@ -40,8 +40,10 @@
|
|
#include <QMap>
|
|
#include <QNetworkConfigurationManager>
|
|
#include <QPointer>
|
|
+#include <QQueue>
|
|
#include <QSet>
|
|
#include <QStringList>
|
|
+#include <QTimer>
|
|
#include <QVector>
|
|
#include <QWaitCondition>
|
|
|
|
@@ -341,6 +343,10 @@ namespace BitTorrent
|
|
|
|
uint saveResumeDataInterval() const;
|
|
void setSaveResumeDataInterval(uint value);
|
|
+ bool isAutoBanUnknownPeerEnabled() const;
|
|
+ void setAutoBanUnknownPeer(bool value);
|
|
+ bool isShowTrackerAuthWindow() const;
|
|
+ void setShowTrackerAuthWindow(bool value);
|
|
int port() const;
|
|
void setPort(int port);
|
|
bool useRandomPort() const;
|
|
@@ -467,6 +473,19 @@ namespace BitTorrent
|
|
void setMaxRatioAction(MaxRatioAction act);
|
|
|
|
void banIP(const QString &ip);
|
|
+ bool checkAccessFlags(const QString &ip);
|
|
+ void tempblockIP(const QString &ip);
|
|
+ void removeBlockedIP(const QString &ip);
|
|
+ void eraseIPFilter();
|
|
+ void autoBanBadClient();
|
|
+
|
|
+ // Unban Timer
|
|
+ bool m_isActive = false;
|
|
+ QQueue<QString> q_bannedIPs;
|
|
+ QQueue<int64_t> q_unbanTime;
|
|
+ QTimer *m_unbanTimer;
|
|
+ QTimer *m_banTimer;
|
|
+ void insertQueue(QString ip);
|
|
|
|
bool isKnownTorrent(const InfoHash &hash) const;
|
|
bool addTorrent(QString source, const AddTorrentParams ¶ms = AddTorrentParams());
|
|
@@ -546,6 +565,9 @@ namespace BitTorrent
|
|
void tagAdded(const QString &tag);
|
|
void tagRemoved(const QString &tag);
|
|
|
|
+ public slots:
|
|
+ void processUnbanRequest();
|
|
+
|
|
private slots:
|
|
void configureDeferred();
|
|
void readAlerts();
|
|
@@ -601,6 +623,8 @@ namespace BitTorrent
|
|
void populateAdditionalTrackers();
|
|
void enableIPFilter();
|
|
void disableIPFilter();
|
|
+ int parseOfflineFilterFile(QString ipDat, libtorrent::ip_filter &filter);
|
|
+ void loadOfflineFilter();
|
|
|
|
bool addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri,
|
|
TorrentInfo torrentInfo = TorrentInfo(),
|
|
@@ -713,6 +737,8 @@ namespace BitTorrent
|
|
CachedSettingValue<bool> m_isAltGlobalSpeedLimitEnabled;
|
|
CachedSettingValue<bool> m_isBandwidthSchedulerEnabled;
|
|
CachedSettingValue<uint> m_saveResumeDataInterval;
|
|
+ CachedSettingValue<bool> m_autoBanUnknownPeer;
|
|
+ CachedSettingValue<bool> m_showTrackerAuthWindow;
|
|
CachedSettingValue<int> m_port;
|
|
CachedSettingValue<bool> m_useRandomPort;
|
|
CachedSettingValue<QString> m_networkInterface;
|
|
--- a/src/base/bittorrent/torrenthandle.cpp
|
|
+++ b/src/base/bittorrent/torrenthandle.cpp
|
|
@@ -1561,7 +1561,8 @@ void TorrentHandle::handleTrackerErrorAl
|
|
m_trackerInfos[trackerUrl].lastMessage = message;
|
|
|
|
if (p->status_code == 401)
|
|
- m_session->handleTorrentTrackerAuthenticationRequired(this, trackerUrl);
|
|
+ if (Preferences::instance()->getShowTrackerAuthWindow())
|
|
+ m_session->handleTorrentTrackerAuthenticationRequired(this, trackerUrl);
|
|
|
|
m_session->handleTorrentTrackerError(this, trackerUrl);
|
|
}
|
|
--- a/src/base/preferences.cpp
|
|
+++ b/src/base/preferences.cpp
|
|
@@ -1090,6 +1090,26 @@ void Preferences::setTrayIconStyle(TrayI
|
|
}
|
|
#endif
|
|
|
|
+bool Preferences::getAutoBanUnknownPeer() const
|
|
+{
|
|
+ return value("Preferences/Advanced/AutoBanUnknownPeer", false).toBool();
|
|
+}
|
|
+
|
|
+void Preferences::setAutoBanUnknownPeer(const bool checked)
|
|
+{
|
|
+ setValue("Preferences/Advanced/AutoBanUnknownPeer", checked);
|
|
+}
|
|
+
|
|
+bool Preferences::getShowTrackerAuthWindow() const
|
|
+{
|
|
+ return value("Preferences/Advanced/ShowTrackerAuthWindow", true).toBool();
|
|
+}
|
|
+
|
|
+void Preferences::setShowTrackerAuthWindow(const bool checked)
|
|
+{
|
|
+ setValue("Preferences/Advanced/ShowTrackerAuthWindow", checked);
|
|
+}
|
|
+
|
|
// Stuff that don't appear in the Options GUI but are saved
|
|
// in the same file.
|
|
|
|
--- a/src/base/preferences.h
|
|
+++ b/src/base/preferences.h
|
|
@@ -300,6 +300,10 @@ public:
|
|
TrayIcon::Style trayIconStyle() const;
|
|
void setTrayIconStyle(TrayIcon::Style style);
|
|
#endif // Q_OS_MAC
|
|
+ bool getAutoBanUnknownPeer() const;
|
|
+ void setAutoBanUnknownPeer(const bool checked);
|
|
+ bool getShowTrackerAuthWindow() const;
|
|
+ void setShowTrackerAuthWindow(const bool checked);
|
|
|
|
// Stuff that don't appear in the Options GUI but are saved
|
|
// in the same file.
|
|
--- a/src/base/settingsstorage.cpp
|
|
+++ b/src/base/settingsstorage.cpp
|
|
@@ -91,6 +91,8 @@ namespace
|
|
{"BitTorrent/Session/InterfaceName", "Preferences/Connection/InterfaceName"},
|
|
{"BitTorrent/Session/InterfaceAddress", "Preferences/Connection/InterfaceAddress"},
|
|
{"BitTorrent/Session/SaveResumeDataInterval", "Preferences/Downloads/SaveResumeDataInterval"},
|
|
+ {"BitTorrent/Session/AutoBanUnknownPeer", "Preferences/Advanced/AutoBanUnknownPeer"},
|
|
+ {"BitTorrent/Session/ShowTrackerAuthWindow", "Preferences/Advanced/ShowTrackerAuthWindow"},
|
|
{"BitTorrent/Session/Encryption", "Preferences/Bittorrent/Encryption"},
|
|
{"BitTorrent/Session/ForceProxy", "Preferences/Connection/ProxyForce"},
|
|
{"BitTorrent/Session/ProxyPeerConnections", "Preferences/Connection/ProxyPeerConnections"},
|
|
--- a/src/gui/advancedsettings.cpp
|
|
+++ b/src/gui/advancedsettings.cpp
|
|
@@ -60,6 +60,8 @@ enum AdvSettingsRows
|
|
NETWORK_LISTEN_IPV6,
|
|
// behavior
|
|
SAVE_RESUME_DATA_INTERVAL,
|
|
+ CONFIRM_AUTO_BAN,
|
|
+ SHOW_TRACKER_AUTH_WINDOW,
|
|
CONFIRM_RECHECK_TORRENT,
|
|
RECHECK_COMPLETED,
|
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
|
@@ -215,6 +217,10 @@ void AdvancedSettings::saveAdvancedSetti
|
|
// Announce IP
|
|
QHostAddress addr(lineEditAnnounceIP.text().trimmed());
|
|
session->setAnnounceIP(addr.isNull() ? "" : addr.toString());
|
|
+ // Auto ban Unknown Peer
|
|
+ session->setAutoBanUnknownPeer(cb_auto_ban_unknown_peer.isChecked());
|
|
+ // Show Tracker Authenticaion Window
|
|
+ session->setShowTrackerAuthWindow(cb_show_tracker_auth_window.isChecked());
|
|
|
|
// Program notification
|
|
MainWindow *const mainWindow = static_cast<Application*>(QCoreApplication::instance())->mainWindow();
|
|
@@ -465,6 +471,12 @@ void AdvancedSettings::loadAdvancedSetti
|
|
// Announce IP
|
|
lineEditAnnounceIP.setText(session->announceIP());
|
|
addRow(ANNOUNCE_IP, tr("IP Address to report to trackers (requires restart)"), &lineEditAnnounceIP);
|
|
+ // Auto Ban Unknown Peer from China
|
|
+ cb_auto_ban_unknown_peer.setChecked(session->isAutoBanUnknownPeerEnabled());
|
|
+ addRow(CONFIRM_AUTO_BAN, tr("Auto Ban Unknown Peer from China"), &cb_auto_ban_unknown_peer);
|
|
+ // Show Tracker Authenticaion Window
|
|
+ cb_show_tracker_auth_window.setChecked(session->isShowTrackerAuthWindow());
|
|
+ addRow(SHOW_TRACKER_AUTH_WINDOW, tr("Show Tracker Authenticaion Window"), &cb_show_tracker_auth_window);
|
|
|
|
// Program notifications
|
|
const MainWindow *const mainWindow = static_cast<Application*>(QCoreApplication::instance())->mainWindow();
|
|
--- a/src/gui/advancedsettings.h
|
|
+++ b/src/gui/advancedsettings.h
|
|
@@ -65,7 +65,8 @@ private:
|
|
QCheckBox checkBoxOsCache, checkBoxRecheckCompleted, checkBoxResolveCountries, checkBoxResolveHosts, checkBoxSuperSeeding,
|
|
checkBoxProgramNotifications, checkBoxTorrentAddedNotifications, checkBoxTrackerFavicon, checkBoxTrackerStatus,
|
|
checkBoxConfirmTorrentRecheck, checkBoxConfirmRemoveAllTags, checkBoxListenIPv6, checkBoxAnnounceAllTrackers, checkBoxAnnounceAllTiers,
|
|
- checkBoxGuidedReadCache, checkBoxMultiConnectionsPerIp, checkBoxSuggestMode, checkBoxCoalesceRW, checkBoxSpeedWidgetEnabled;
|
|
+ checkBoxGuidedReadCache, checkBoxMultiConnectionsPerIp, checkBoxSuggestMode, checkBoxCoalesceRW, checkBoxSpeedWidgetEnabled,
|
|
+ cb_auto_ban_unknown_peer, cb_show_tracker_auth_window;
|
|
QComboBox comboBoxInterface, comboBoxInterfaceAddress, comboBoxUtpMixedMode, comboBoxChokingAlgorithm, comboBoxSeedChokingAlgorithm;
|
|
QLineEdit lineEditAnnounceIP;
|
|
|
|
--- a/src/gui/mainwindow.cpp
|
|
+++ b/src/gui/mainwindow.cpp
|
|
@@ -73,6 +73,7 @@
|
|
#include "addnewtorrentdialog.h"
|
|
#include "application.h"
|
|
#include "autoexpandabledialog.h"
|
|
+#include "base/bittorrent/peerinfo.h"
|
|
#include "cookiesdialog.h"
|
|
#include "downloadfromurldialog.h"
|
|
#include "executionlogwidget.h"
|
|
--- a/src/gui/properties/peerlistdelegate.h
|
|
+++ b/src/gui/properties/peerlistdelegate.h
|
|
@@ -49,6 +49,7 @@ public:
|
|
CONNECTION,
|
|
FLAGS,
|
|
CLIENT,
|
|
+ PEERID,
|
|
PROGRESS,
|
|
DOWN_SPEED,
|
|
UP_SPEED,
|
|
--- a/src/gui/properties/peerlistwidget.cpp
|
|
+++ b/src/gui/properties/peerlistwidget.cpp
|
|
@@ -75,6 +75,7 @@ PeerListWidget::PeerListWidget(Propertie
|
|
m_listModel->setHeaderData(PeerListDelegate::FLAGS, Qt::Horizontal, tr("Flags"));
|
|
m_listModel->setHeaderData(PeerListDelegate::CONNECTION, Qt::Horizontal, tr("Connection"));
|
|
m_listModel->setHeaderData(PeerListDelegate::CLIENT, Qt::Horizontal, tr("Client", "i.e.: Client application"));
|
|
+ m_listModel->setHeaderData(PeerListDelegate::PEERID, Qt::Horizontal, tr("Peer ID", "i.e.: Client Peer ID"));
|
|
m_listModel->setHeaderData(PeerListDelegate::PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded"));
|
|
m_listModel->setHeaderData(PeerListDelegate::DOWN_SPEED, Qt::Horizontal, tr("Down Speed", "i.e: Download speed"));
|
|
m_listModel->setHeaderData(PeerListDelegate::UP_SPEED, Qt::Horizontal, tr("Up Speed", "i.e: Upload speed"));
|
|
@@ -288,8 +289,13 @@ void PeerListWidget::banSelectedPeers()
|
|
for (const QModelIndex &index : selectedIndexes) {
|
|
int row = m_proxyModel->mapToSource(index).row();
|
|
QString ip = m_listModel->data(m_listModel->index(row, PeerListDelegate::IP_HIDDEN)).toString();
|
|
+ QString client = m_listModel->data(m_listModel->index(row, PeerListDelegate::CLIENT)).toString();
|
|
+ QString peerid = m_listModel->data(m_listModel->index(row, PeerListDelegate::PEERID)).toString();
|
|
+ QHostAddress host;
|
|
+ host.setAddress(ip);
|
|
+ const QString countryName = Net::GeoIPManager::CountryName(Net::GeoIPManager::instance()->lookup(host));
|
|
qDebug("Banning peer %s...", ip.toLocal8Bit().data());
|
|
- Logger::instance()->addMessage(tr("Manually banning peer '%1'...").arg(ip));
|
|
+ Logger::instance()->addMessage(tr("Manually banning peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(peerid).arg(client).arg(countryName));
|
|
BitTorrent::Session::instance()->banIP(ip);
|
|
}
|
|
// Refresh list
|
|
@@ -398,6 +404,7 @@ QStandardItem *PeerListWidget::addPeer(c
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags());
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole);
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client().toHtmlEscaped());
|
|
+ m_listModel->setData(m_listModel->index(row, PeerListDelegate::PEERID), peer.pid().left(8).toHtmlEscaped());
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
|
|
@@ -429,6 +436,7 @@ void PeerListWidget::updatePeer(const QS
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags());
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole);
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client().toHtmlEscaped());
|
|
+ m_listModel->setData(m_listModel->index(row, PeerListDelegate::PEERID), peer.pid().left(8).toHtmlEscaped());
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
|
|
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
|
|
--- a/src/webui/api/appcontroller.cpp
|
|
+++ b/src/webui/api/appcontroller.cpp
|
|
@@ -153,6 +153,7 @@ void AppController::preferencesAction()
|
|
data["ip_filter_path"] = Utils::Fs::toNativePath(session->IPFilterFile());
|
|
data["ip_filter_trackers"] = session->isTrackerFilteringEnabled();
|
|
data["banned_IPs"] = session->bannedIPs().join("\n");
|
|
+ data["auto_ban_unknown_peer"] = session->isAutoBanUnknownPeerEnabled();
|
|
|
|
// Speed
|
|
// Global Rate Limits
|
|
@@ -401,6 +402,8 @@ void AppController::setPreferencesAction
|
|
session->setTrackerFilteringEnabled(m["ip_filter_trackers"].toBool());
|
|
if (m.contains("banned_IPs"))
|
|
session->setBannedIPs(m["banned_IPs"].toString().split('\n'));
|
|
+ if (m.contains("auto_ban_unknown_peer"))
|
|
+ session->setAutoBanUnknownPeer(m["auto_ban_unknown_peer"].toBool());
|
|
|
|
// Speed
|
|
// Global Rate Limits
|
|
--- a/src/webui/api/transfercontroller.cpp
|
|
+++ b/src/webui/api/transfercontroller.cpp
|
|
@@ -30,6 +30,7 @@
|
|
|
|
#include <QJsonObject>
|
|
|
|
+#include "base/logger.h"
|
|
#include "base/bittorrent/session.h"
|
|
|
|
const char KEY_TRANSFER_DLSPEED[] = "dl_info_speed";
|
|
@@ -111,3 +112,37 @@ void TransferController::speedLimitsMode
|
|
{
|
|
setResult(QString::number(BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled()));
|
|
}
|
|
+
|
|
+void TransferController::tempblockPeerAction()
|
|
+{
|
|
+ checkParams({"ip"});
|
|
+ QString ip = params()["ip"];
|
|
+ boost::system::error_code ec;
|
|
+ boost::asio::ip::address addr = boost::asio::ip::address::from_string(ip.toStdString(), ec);
|
|
+ bool isBanned = BitTorrent::Session::instance()->checkAccessFlags(QString::fromStdString(addr.to_string()));
|
|
+
|
|
+ if (ip.isEmpty()) {
|
|
+ setResult(QLatin1String("IP field should not be empty."));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (ec) {
|
|
+ setResult(QLatin1String("The given IP address is not valid."));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (isBanned) {
|
|
+ setResult(QLatin1String("The given IP address already exists."));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ BitTorrent::Session::instance()->tempblockIP(ip);
|
|
+ Logger::instance()->addMessage(tr("Peer '%1' banned via Web API.").arg(ip));
|
|
+ setResult(QLatin1String("Done."));
|
|
+}
|
|
+
|
|
+void TransferController::resetIPFilterAction()
|
|
+{
|
|
+ BitTorrent::Session::instance()->eraseIPFilter();
|
|
+ setResult(QLatin1String("Erased."));
|
|
+}
|
|
--- a/src/webui/api/transfercontroller.h
|
|
+++ b/src/webui/api/transfercontroller.h
|
|
@@ -46,4 +46,6 @@ private slots:
|
|
void downloadLimitAction();
|
|
void setUploadLimitAction();
|
|
void setDownloadLimitAction();
|
|
+ void tempblockPeerAction();
|
|
+ void resetIPFilterAction();
|
|
};
|
|
--- a/src/webui/www/private/preferences_content.html
|
|
+++ b/src/webui/www/private/preferences_content.html
|
|
@@ -377,6 +377,8 @@
|
|
<textarea id="banned_IPs_textarea" rows="5" cols="70"></textarea>
|
|
</fieldset>
|
|
</div>
|
|
+ <input type="checkbox" id="auto_ban_unknown_peer_checkbox" />
|
|
+ <label for="auto_ban_unknown_peer_checkbox">QBT_TR(Auto Ban Unknown Client From China)QBT_TR[CONTEXT=OptionsDialog]</label>
|
|
</fieldset>
|
|
</div>
|
|
|
|
@@ -1252,6 +1254,7 @@
|
|
$('ipfilter_text').setProperty('value', pref.ip_filter_path);
|
|
$('ipfilter_trackers_checkbox').setProperty('checked', pref.ip_filter_trackers);
|
|
$('banned_IPs_textarea').setProperty('value', pref.banned_IPs);
|
|
+ $('auto_ban_unknown_peer_checkbox').setProperty('checked', pref.auto_ban_unknown_peer);
|
|
updateFilterSettings();
|
|
|
|
// Speed tab
|
|
@@ -1502,6 +1505,7 @@
|
|
settings.set('ip_filter_path', $('ipfilter_text').getProperty('value'));
|
|
settings.set('ip_filter_trackers', $('ipfilter_trackers_checkbox').getProperty('checked'));
|
|
settings.set('banned_IPs', $('banned_IPs_textarea').getProperty('value'));
|
|
+ settings.set('auto_ban_unknown_peer', $('auto_ban_unknown_peer_checkbox').getProperty('checked'));
|
|
|
|
// Speed tab
|
|
// Global Rate Limits
|