Merge pull request #12159 from thalieht/backportflags

Backport #12014: Use IP geolocation database by DB-IP instead of MaxMind
This commit is contained in:
Mike Tzou 2020-03-13 18:38:35 +08:00 committed by GitHub
commit d8cb552804
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 67 additions and 36 deletions

View file

@ -13,8 +13,7 @@ It aims to be a good alternative to all other bittorrent clients
out there. qBittorrent is fast, stable and provides unicode out there. qBittorrent is fast, stable and provides unicode
support as well as many features. support as well as many features.
This product includes GeoLite data created by MaxMind, available from The free [IP to Country Lite database](https://db-ip.com/db/download/ip-to-country-lite) by [DB-IP](https://db-ip.com/) is used for resolving the countries of peers. The database is licensed under the [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/).
https://www.maxmind.com/
### Installation: ### Installation:
For installation, follow the instructions from INSTALL file, but simple: For installation, follow the instructions from INSTALL file, but simple:

View file

@ -44,10 +44,9 @@
#include "downloadmanager.h" #include "downloadmanager.h"
#include "private/geoipdatabase.h" #include "private/geoipdatabase.h"
static const char DATABASE_URL[] = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz"; static const QString DATABASE_URL = QStringLiteral("https://download.db-ip.com/free/dbip-country-lite-%1.mmdb.gz");
static const char GEOIP_FOLDER[] = "GeoIP"; static const char GEODB_FOLDER[] = "GeoDB";
static const char GEOIP_FILENAME[] = "GeoLite2-Country.mmdb"; static const char GEODB_FILENAME[] = "dbip-country-lite.mmdb";
static const int UPDATE_INTERVAL = 30; // Days between database updates
using namespace Net; using namespace Net;
@ -96,29 +95,45 @@ void GeoIPManager::loadDatabase()
} }
QString filepath = Utils::Fs::expandPathAbs( QString filepath = Utils::Fs::expandPathAbs(
QString("%1%2/%3").arg(specialFolderLocation(SpecialFolder::Data), GEOIP_FOLDER, GEOIP_FILENAME)); QString("%1%2/%3").arg(specialFolderLocation(SpecialFolder::Data), GEODB_FOLDER, GEODB_FILENAME));
QString error; QString error;
m_geoIPDatabase = GeoIPDatabase::load(filepath, error); m_geoIPDatabase = GeoIPDatabase::load(filepath, error);
if (m_geoIPDatabase) if (m_geoIPDatabase)
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.") Logger::instance()->addMessage(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type(), m_geoIPDatabase->buildEpoch().toString()), .arg(m_geoIPDatabase->type(), m_geoIPDatabase->buildEpoch().toString()),
Log::INFO); Log::INFO);
else else
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING); Logger::instance()->addMessage(tr("Couldn't load IP geolocation database. Reason: %1").arg(error), Log::WARNING);
manageDatabaseUpdate(); manageDatabaseUpdate();
} }
void GeoIPManager::manageDatabaseUpdate() void GeoIPManager::manageDatabaseUpdate()
{ {
if (!m_geoIPDatabase || (m_geoIPDatabase->buildEpoch().daysTo(QDateTime::currentDateTimeUtc()) >= UPDATE_INTERVAL)) const auto expired = [](const QDateTime &testDateTime)
{
const QDate testDate = testDateTime.date();
const QDate curDate = QDateTime::currentDateTimeUtc().date();
if ((testDate.year() < curDate.year()) && (curDate.day() > 1))
return true;
if ((testDate.month() < curDate.month()) && (curDate.day() > 1))
return true;
return false;
};
if (!m_geoIPDatabase || expired(m_geoIPDatabase->buildEpoch()))
downloadDatabaseFile(); downloadDatabaseFile();
} }
void GeoIPManager::downloadDatabaseFile() void GeoIPManager::downloadDatabaseFile()
{ {
DownloadHandler *handler = DownloadManager::instance()->download({DATABASE_URL}); const QDate curDate = QDateTime::currentDateTimeUtc().date();
const QString curUrl = DATABASE_URL.arg(curDate.toString("yyyy-MM"));
DownloadHandler *handler = DownloadManager::instance()->download({curUrl});
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished) connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &GeoIPManager::downloadFinished); , this, &GeoIPManager::downloadFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &GeoIPManager::downloadFailed); connect(handler, &Net::DownloadHandler::downloadFailed, this, &GeoIPManager::downloadFailed);
@ -420,7 +435,7 @@ void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
bool ok = false; bool ok = false;
data = Utils::Gzip::decompress(data, &ok); data = Utils::Gzip::decompress(data, &ok);
if (!ok) { if (!ok) {
Logger::instance()->addMessage(tr("Could not decompress GeoIP database file."), Log::WARNING); LogMsg(tr("Could not decompress IP geolocation database file."), Log::WARNING);
return; return;
} }
@ -431,28 +446,25 @@ void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
if (m_geoIPDatabase) if (m_geoIPDatabase)
delete m_geoIPDatabase; delete m_geoIPDatabase;
m_geoIPDatabase = geoIPDatabase; m_geoIPDatabase = geoIPDatabase;
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.") LogMsg(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type(), m_geoIPDatabase->buildEpoch().toString()), .arg(m_geoIPDatabase->type(), m_geoIPDatabase->buildEpoch().toString()),
Log::INFO); Log::INFO);
QString targetPath = Utils::Fs::expandPathAbs( const QString targetPath = Utils::Fs::expandPathAbs(
specialFolderLocation(SpecialFolder::Data) + GEOIP_FOLDER); specialFolderLocation(SpecialFolder::Data) + GEODB_FOLDER);
if (!QDir(targetPath).exists()) if (!QDir(targetPath).exists())
QDir().mkpath(targetPath); QDir().mkpath(targetPath);
QFile targetFile(QString("%1/%2").arg(targetPath, GEOIP_FILENAME)); QFile targetFile(QString("%1/%2").arg(targetPath, GEODB_FILENAME));
if (!targetFile.open(QFile::WriteOnly) || (targetFile.write(data) == -1)) { if (!targetFile.open(QFile::WriteOnly) || (targetFile.write(data) == -1))
Logger::instance()->addMessage( LogMsg(tr("Couldn't save downloaded IP geolocation database file."), Log::WARNING);
tr("Couldn't save downloaded GeoIP database file."), Log::WARNING); else
} LogMsg(tr("Successfully updated IP geolocation database."), Log::INFO);
else {
Logger::instance()->addMessage(tr("Successfully updated GeoIP database."), Log::INFO);
}
} }
else { else {
delete geoIPDatabase; delete geoIPDatabase;
} }
} }
else { else {
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING); LogMsg(tr("Couldn't load IP geolocation database. Reason: %1").arg(error), Log::WARNING);
} }
} }

View file

@ -38,7 +38,6 @@
namespace namespace
{ {
const qint32 MAX_FILE_SIZE = 67108864; // 64MB const qint32 MAX_FILE_SIZE = 67108864; // 64MB
const char DB_TYPE[] = "GeoLite2-Country";
const quint32 MAX_METADATA_SIZE = 131072; // 128KB const quint32 MAX_METADATA_SIZE = 131072; // 128KB
const char METADATA_BEGIN_MARK[] = "\xab\xcd\xefMaxMind.com"; const char METADATA_BEGIN_MARK[] = "\xab\xcd\xefMaxMind.com";
const char DATA_SECTION_SEPARATOR[16] = {0}; const char DATA_SECTION_SEPARATOR[16] = {0};
@ -144,7 +143,7 @@ GeoIPDatabase::~GeoIPDatabase()
QString GeoIPDatabase::type() const QString GeoIPDatabase::type() const
{ {
return DB_TYPE; return m_dbType;
} }
quint16 GeoIPDatabase::ipVersion() const quint16 GeoIPDatabase::ipVersion() const
@ -255,11 +254,7 @@ bool GeoIPDatabase::parseMetadata(const QVariantHash &metadata, QString &error)
m_indexSize = m_nodeCount * m_nodeSize; m_indexSize = m_nodeCount * m_nodeSize;
CHECK_METADATA_REQ(database_type, QString); CHECK_METADATA_REQ(database_type, QString);
QString dbType = metadata.value("database_type").toString(); m_dbType = metadata.value("database_type").toString();
if (dbType != DB_TYPE) {
error = tr("Invalid database type: %1").arg(dbType);
return false;
}
CHECK_METADATA_REQ(build_epoch, ULongLong); CHECK_METADATA_REQ(build_epoch, ULongLong);
m_buildEpoch = QDateTime::fromTime_t(metadata.value("build_epoch").toULongLong()); m_buildEpoch = QDateTime::fromTime_t(metadata.value("build_epoch").toULongLong());
@ -272,7 +267,7 @@ bool GeoIPDatabase::parseMetadata(const QVariantHash &metadata, QString &error)
bool GeoIPDatabase::loadDB(QString &error) const bool GeoIPDatabase::loadDB(QString &error) const
{ {
qDebug() << "Parsing MaxMindDB index tree..."; qDebug() << "Parsing IP geolocation database index tree...";
const int nodeSize = m_recordSize / 4; // in bytes const int nodeSize = m_recordSize / 4; // in bytes
const int indexSize = m_nodeCount * nodeSize; const int indexSize = m_nodeCount * nodeSize;

View file

@ -93,6 +93,7 @@ private:
int m_indexSize; int m_indexSize;
int m_recordBytes; int m_recordBytes;
QDateTime m_buildEpoch; QDateTime m_buildEpoch;
QString m_dbType;
// Search data // Search data
mutable QHash<quint32, QString> m_countries; mutable QHash<quint32, QString> m_countries;
quint32 m_size; quint32 m_size;

View file

@ -102,6 +102,14 @@ public:
labelLibtVer->setText(Utils::Misc::libtorrentVersionString()); labelLibtVer->setText(Utils::Misc::libtorrentVersionString());
labelBoostVer->setText(Utils::Misc::boostVersionString()); labelBoostVer->setText(Utils::Misc::boostVersionString());
const QString DBIPText = QString(
"<html><head/><body><p>"
"%1"
" (<a href=\"https://db-ip.com/\">https://db-ip.com/</a>)</p></body></html>")
.arg(tr("The free IP to Country Lite database by DB-IP is used for resolving the countries of peers. "
"The database is licensed under the Creative Commons Attribution 4.0 International License"));
labelDBIP->setText(DBIPText);
Utils::Gui::resize(this); Utils::Gui::resize(this);
show(); show();
} }

View file

@ -314,11 +314,11 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="librariesTab"> <widget class="QWidget" name="SoftwareUsedTab">
<attribute name="title"> <attribute name="title">
<string>Libraries</string> <string>Software Used</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="librariesTabLayout"> <layout class="QVBoxLayout" name="SoftwareUsedTabLayout">
<item> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
@ -430,6 +430,22 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="labelDBIP">
<property name="text">
<string notr="true">DB-IP license text</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer_2"> <spacer name="verticalSpacer_2">
<property name="orientation"> <property name="orientation">

View file

@ -419,7 +419,7 @@ void AdvancedSettings::loadAdvancedSettings()
addRow(LIST_REFRESH, tr("Transfer list refresh interval"), &spinBoxListRefresh); addRow(LIST_REFRESH, tr("Transfer list refresh interval"), &spinBoxListRefresh);
// Resolve Peer countries // Resolve Peer countries
checkBoxResolveCountries.setChecked(pref->resolvePeerCountries()); checkBoxResolveCountries.setChecked(pref->resolvePeerCountries());
addRow(RESOLVE_COUNTRIES, tr("Resolve peer countries (GeoIP)"), &checkBoxResolveCountries); addRow(RESOLVE_COUNTRIES, tr("Resolve peer countries"), &checkBoxResolveCountries);
// Resolve peer hosts // Resolve peer hosts
checkBoxResolveHosts.setChecked(pref->resolvePeerHostNames()); checkBoxResolveHosts.setChecked(pref->resolvePeerHostNames());
addRow(RESOLVE_HOSTS, tr("Resolve peer host names"), &checkBoxResolveHosts); addRow(RESOLVE_HOSTS, tr("Resolve peer host names"), &checkBoxResolveHosts);