Use IP geolocation database by DB-IP instead of MaxMind

Closes #11792
This commit is contained in:
sledgehammer999
2020-02-14 22:07:19 +02:00
parent 322ae3e0bc
commit ea1481beef
10 changed files with 73 additions and 38 deletions

View File

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

View File

@@ -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;

View File

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