Skip to content
Permalink
Browse files

Use IP geolocation database by DB-IP instead of MaxMind

Closes #11792
  • Loading branch information
sledgehammer999 committed Feb 14, 2020
1 parent 322ae3e commit ea1481beef19cfd1166126dc4425b661755257ab
@@ -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
support as well as many features.

This product includes GeoLite data created by MaxMind, available from
https://www.maxmind.com/
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/).

### Installation:
For installation, follow the instructions from INSTALL file, but simple:
@@ -42,10 +42,9 @@
#include "downloadmanager.h"
#include "private/geoipdatabase.h"

static const char DATABASE_URL[] = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz";
static const char GEOIP_FOLDER[] = "GeoIP";
static const char GEOIP_FILENAME[] = "GeoLite2-Country.mmdb";
static const int UPDATE_INTERVAL = 30; // Days between database updates
static const QString DATABASE_URL = QStringLiteral("https://download.db-ip.com/free/dbip-country-lite-%1.mmdb.gz");
static const char GEODB_FOLDER[] = "GeoDB";
static const char GEODB_FILENAME[] = "dbip-country-lite.mmdb";

using namespace Net;

@@ -89,29 +88,45 @@ void GeoIPManager::loadDatabase()
m_geoIPDatabase = nullptr;

const 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;
m_geoIPDatabase = GeoIPDatabase::load(filepath, error);
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()),
Log::INFO);
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();
}

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();
}

void GeoIPManager::downloadDatabaseFile()
{
DownloadManager::instance()->download({DATABASE_URL}, this, &GeoIPManager::downloadFinished);
const QDate curDate = QDateTime::currentDateTimeUtc().date();
const QString curUrl = DATABASE_URL.arg(curDate.toString("yyyy-MM"));
DownloadManager::instance()->download({curUrl}, this, &GeoIPManager::downloadFinished);
}

QString GeoIPManager::lookup(const QHostAddress &hostAddr) const
@@ -403,14 +418,14 @@ void GeoIPManager::configure()
void GeoIPManager::downloadFinished(const DownloadResult &result)
{
if (result.status != DownloadStatus::Success) {
LogMsg(tr("Couldn't download GeoIP database file. Reason: %1").arg(result.errorString), Log::WARNING);
LogMsg(tr("Couldn't download IP geolocation database file. Reason: %1").arg(result.errorString), Log::WARNING);
return;
}

bool ok = false;
const QByteArray data = Utils::Gzip::decompress(result.data, &ok);
if (!ok) {
LogMsg(tr("Could not decompress GeoIP database file."), Log::WARNING);
LogMsg(tr("Could not decompress IP geolocation database file."), Log::WARNING);
return;
}

@@ -420,24 +435,24 @@ void GeoIPManager::downloadFinished(const DownloadResult &result)
if (!m_geoIPDatabase || (geoIPDatabase->buildEpoch() > m_geoIPDatabase->buildEpoch())) {
delete m_geoIPDatabase;
m_geoIPDatabase = geoIPDatabase;
LogMsg(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()),
Log::INFO);
const QString targetPath = Utils::Fs::expandPathAbs(
specialFolderLocation(SpecialFolder::Data) + GEOIP_FOLDER);
specialFolderLocation(SpecialFolder::Data) + GEODB_FOLDER);
if (!QDir(targetPath).exists())
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))
LogMsg(tr("Couldn't save downloaded GeoIP database file."), Log::WARNING);
LogMsg(tr("Couldn't save downloaded IP geolocation database file."), Log::WARNING);
else
LogMsg(tr("Successfully updated GeoIP database."), Log::INFO);
LogMsg(tr("Successfully updated IP geolocation database."), Log::INFO);
}
else {
delete geoIPDatabase;
}
}
else {
LogMsg(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);
}
}
@@ -37,7 +37,6 @@
namespace
{
const qint32 MAX_FILE_SIZE = 67108864; // 64MB
const char DB_TYPE[] = "GeoLite2-Country";
const quint32 MAX_METADATA_SIZE = 131072; // 128KB
const char METADATA_BEGIN_MARK[] = "\xab\xcd\xefMaxMind.com";
const char DATA_SECTION_SEPARATOR[16] = {0};
@@ -143,7 +142,7 @@ GeoIPDatabase::~GeoIPDatabase()

QString GeoIPDatabase::type() const
{
return DB_TYPE;
return m_dbType;
}

quint16 GeoIPDatabase::ipVersion() const
@@ -253,11 +252,7 @@ bool GeoIPDatabase::parseMetadata(const QVariantHash &metadata, QString &error)
m_indexSize = m_nodeCount * m_nodeSize;

CHECK_METADATA_REQ(database_type, QString);
const QString dbType = metadata.value("database_type").toString();
if (dbType != DB_TYPE) {
error = tr("Invalid database type: %1").arg(dbType);
return false;
}
m_dbType = metadata.value("database_type").toString();

CHECK_METADATA_REQ(build_epoch, ULongLong);
m_buildEpoch = QDateTime::fromSecsSinceEpoch(metadata.value("build_epoch").toULongLong());
@@ -270,7 +265,7 @@ bool GeoIPDatabase::parseMetadata(const QVariantHash &metadata, QString &error)

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 indexSize = m_nodeCount * nodeSize;
@@ -93,6 +93,7 @@ class GeoIPDatabase
int m_indexSize;
int m_recordBytes;
QDateTime m_buildEpoch;
QString m_dbType;
// Search data
mutable QHash<quint32, QString> m_countries;
quint32 m_size;
@@ -48,7 +48,7 @@ AboutDialog::AboutDialog(QWidget *parent)
m_ui->logo->setPixmap(Utils::Gui::scaledPixmapSvg(":/icons/skin/qbittorrent-tray.svg", this, 32));

// About
QString aboutText = QString(
const QString aboutText = QString(
"<p style=\"white-space: pre-wrap;\">"
"%1\n\n"
"%2\n\n"
@@ -88,13 +88,21 @@ AboutDialog::AboutDialog(QWidget *parent)
licensefile.close();
}

// Libraries
// Software Used
m_ui->labelQtVer->setText(QT_VERSION_STR);
m_ui->labelLibtVer->setText(Utils::Misc::libtorrentVersionString());
m_ui->labelBoostVer->setText(Utils::Misc::boostVersionString());
m_ui->labelOpensslVer->setText(Utils::Misc::opensslVersionString());
m_ui->labelZlibVer->setText(Utils::Misc::zlibVersionString());

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"));
m_ui->labelDBIP->setText(DBIPText);

Utils::Gui::resize(this);
show();
}
@@ -314,11 +314,11 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="librariesTab">
<widget class="QWidget" name="SoftwareUsedTab">
<attribute name="title">
<string>Libraries</string>
<string>Software Used</string>
</attribute>
<layout class="QVBoxLayout" name="librariesTabLayout">
<layout class="QVBoxLayout" name="SoftwareUsedTabLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
@@ -470,6 +470,22 @@
</property>
</widget>
</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>
<spacer name="verticalSpacer_2">
<property name="orientation">
@@ -496,7 +496,7 @@ void AdvancedSettings::loadAdvancedSettings()
addRow(LIST_REFRESH, tr("Transfer list refresh interval"), &m_spinBoxListRefresh);
// Resolve Peer countries
m_checkBoxResolveCountries.setChecked(pref->resolvePeerCountries());
addRow(RESOLVE_COUNTRIES, tr("Resolve peer countries (GeoIP)"), &m_checkBoxResolveCountries);
addRow(RESOLVE_COUNTRIES, tr("Resolve peer countries"), &m_checkBoxResolveCountries);
// Resolve peer hosts
m_checkBoxResolveHosts.setChecked(pref->resolvePeerHostNames());
addRow(RESOLVE_HOSTS, tr("Resolve peer host names"), &m_checkBoxResolveHosts);
@@ -652,7 +652,7 @@ <h3><a name="howto"></a><a name="SEC4" href="#TOC4">How to Apply These Terms to
</p>
</div>

<div id="aboutLibrariesContent" class="aboutTabContent invisible">
<div id="aboutSoftwareUsedContent" class="aboutTabContent invisible">
<p>QBT_TR(qBittorrent was built with the following libraries:)QBT_TR[CONTEXT=AboutDialog]</p>
<table style="margin-left: 20px;">
<tr>
@@ -676,6 +676,7 @@ <h3><a name="howto"></a><a name="SEC4" href="#TOC4">How to Apply These Terms to
<td><span id="zlibVersion"></span></td>
</tr>
</table>
<p>QBT_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)QBT_TR[CONTEXT=AboutDialog] (<a href="https://db-ip.com/" target="_blank" rel="noopener ">https://db-ip.com/</a>)</p>
</div>

<script>
@@ -5,7 +5,7 @@
<li id="aboutSpecialThanksLink"><a>QBT_TR(Special Thanks)QBT_TR[CONTEXT=AboutDialog]</a></li>
<li id="aboutTranslatorsLink"><a>QBT_TR(Translators)QBT_TR[CONTEXT=AboutDialog]</a></li>
<li id="aboutLicenseLink"><a>QBT_TR(License)QBT_TR[CONTEXT=AboutDialog]</a></li>
<li id="aboutLibrariesLink"><a>QBT_TR(Libraries)QBT_TR[CONTEXT=AboutDialog]</a></li>
<li id="aboutSoftwareUsedLink"><a>QBT_TR(Software Used)QBT_TR[CONTEXT=AboutDialog]</a></li>
</ul>
<div class="clear"></div>
</div>
@@ -41,9 +41,9 @@
$('aboutLicenseContent').removeClass('invisible');
});

$('aboutLibrariesLink').addEvent('click', function() {
$('aboutSoftwareUsedLink').addEvent('click', function() {
$$('.aboutTabContent').addClass('invisible');
$('aboutLibrariesContent').removeClass('invisible');
$('aboutSoftwareUsedContent').removeClass('invisible');
});
})();
</script>
@@ -868,7 +868,7 @@
</tr>
<tr>
<td>
<label for="resolvePeerCountries">QBT_TR(Resolve peer countries (GeoIP):)QBT_TR[CONTEXT=OptionsDialog]</label>
<label for="resolvePeerCountries">QBT_TR(Resolve peer countries:)QBT_TR[CONTEXT=OptionsDialog]</label>
</td>
<td>
<input type="checkbox" id="resolvePeerCountries">

0 comments on commit ea1481b

Please sign in to comment.
You can’t perform that action at this time.