--- 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 #include +#include 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 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 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 #include #include +#include #include #include +#include #include #include @@ -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 q_bannedIPs; + QQueue 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 m_isAltGlobalSpeedLimitEnabled; CachedSettingValue m_isBandwidthSchedulerEnabled; CachedSettingValue m_saveResumeDataInterval; + CachedSettingValue m_autoBanUnknownPeer; + CachedSettingValue m_showTrackerAuthWindow; CachedSettingValue m_port; CachedSettingValue m_useRandomPort; CachedSettingValue 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(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(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 +#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 @@ + + @@ -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