qBittorrent/src/base/net/geoipmanager.cpp
2016-12-07 01:31:39 +08:00

459 lines
18 KiB
C++

/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include <QDebug>
#include <QFile>
#include <QDir>
#include <QHostAddress>
#include <QDateTime>
#include "base/logger.h"
#include "base/preferences.h"
#include "base/utils/fs.h"
#include "base/utils/gzip.h"
#include "downloadmanager.h"
#include "downloadhandler.h"
#include "private/geoipdatabase.h"
#include "geoipmanager.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
using namespace Net;
// GeoIPManager
GeoIPManager *GeoIPManager::m_instance = 0;
GeoIPManager::GeoIPManager()
: m_enabled(false)
, m_geoIPDatabase(0)
{
configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
}
GeoIPManager::~GeoIPManager()
{
if (m_geoIPDatabase)
delete m_geoIPDatabase;
}
void GeoIPManager::initInstance()
{
if (!m_instance)
m_instance = new GeoIPManager;
}
void GeoIPManager::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
}
}
GeoIPManager *GeoIPManager::instance()
{
return m_instance;
}
void GeoIPManager::loadDatabase()
{
if (m_geoIPDatabase) {
delete m_geoIPDatabase;
m_geoIPDatabase = 0;
}
QString filepath = Utils::Fs::expandPathAbs(
QString("%1%2/%3").arg(Utils::Fs::QDesktopServicesDataLocation())
.arg(GEOIP_FOLDER).arg(GEOIP_FILENAME));
QString error;
m_geoIPDatabase = GeoIPDatabase::load(filepath, error);
if (m_geoIPDatabase)
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type()).arg(m_geoIPDatabase->buildEpoch().toString()),
Log::INFO);
else
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING);
manageDatabaseUpdate();
}
void GeoIPManager::manageDatabaseUpdate()
{
if (!m_geoIPDatabase || (m_geoIPDatabase->buildEpoch().daysTo(QDateTime::currentDateTimeUtc()) >= UPDATE_INTERVAL))
downloadDatabaseFile();
}
void GeoIPManager::downloadDatabaseFile()
{
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(DATABASE_URL);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(downloadFinished(QString, QByteArray)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(downloadFailed(QString, QString)));
}
QString GeoIPManager::lookup(const QHostAddress &hostAddr) const
{
if (m_enabled && m_geoIPDatabase)
return m_geoIPDatabase->lookup(hostAddr);
return QString();
}
QString GeoIPManager::CountryName(const QString &countryISOCode)
{
static QHash<QString, QString> countries;
static bool initialized = false;
// ISO 3166-1 alpha-2 codes
// http://www.iso.org/iso/home/standards/country_codes/country_names_and_code_elements_txt-temp.htm
if (!initialized) {
// Officially assigned
countries["AD"] = tr("Andorra");
countries["AE"] = tr("United Arab Emirates");
countries["AF"] = tr("Afghanistan");
countries["AG"] = tr("Antigua and Barbuda");
countries["AI"] = tr("Anguilla");
countries["AL"] = tr("Albania");
countries["AM"] = tr("Armenia");
countries["AO"] = tr("Angola");
countries["AQ"] = tr("Antarctica");
countries["AR"] = tr("Argentina");
countries["AS"] = tr("American Samoa");
countries["AT"] = tr("Austria");
countries["AU"] = tr("Australia");
countries["AW"] = tr("Aruba");
countries["AX"] = tr("Aland Islands");
countries["AZ"] = tr("Azerbaijan");
countries["BA"] = tr("Bosnia and Herzegovina");
countries["BB"] = tr("Barbados");
countries["BD"] = tr("Bangladesh");
countries["BE"] = tr("Belgium");
countries["BF"] = tr("Burkina Faso");
countries["BG"] = tr("Bulgaria");
countries["BH"] = tr("Bahrain");
countries["BI"] = tr("Burundi");
countries["BJ"] = tr("Benin");
countries["BL"] = tr("Saint Barthelemy");
countries["BM"] = tr("Bermuda");
countries["BN"] = tr("Brunei Darussalam");
countries["BO"] = tr("Bolivia, Plurinational State of");
countries["BQ"] = tr("Bonaire, Sint Eustatius and Saba");
countries["BR"] = tr("Brazil");
countries["BS"] = tr("Bahamas");
countries["BT"] = tr("Bhutan");
countries["BV"] = tr("Bouvet Island");
countries["BW"] = tr("Botswana");
countries["BY"] = tr("Belarus");
countries["BZ"] = tr("Belize");
countries["CA"] = tr("Canada");
countries["CC"] = tr("Cocos (Keeling) Islands");
countries["CD"] = tr("Congo, The Democratic Republic of the");
countries["CF"] = tr("Central African Republic");
countries["CG"] = tr("Congo");
countries["CH"] = tr("Switzerland");
countries["CI"] = tr("Cote d'Ivoire");
countries["CK"] = tr("Cook Islands");
countries["CL"] = tr("Chile");
countries["CM"] = tr("Cameroon");
countries["CN"] = tr("China");
countries["CO"] = tr("Colombia");
countries["CR"] = tr("Costa Rica");
countries["CU"] = tr("Cuba");
countries["CV"] = tr("Cape Verde");
countries["CW"] = tr("Curacao");
countries["CX"] = tr("Christmas Island");
countries["CY"] = tr("Cyprus");
countries["CZ"] = tr("Czech Republic");
countries["DE"] = tr("Germany");
countries["DJ"] = tr("Djibouti");
countries["DK"] = tr("Denmark");
countries["DM"] = tr("Dominica");
countries["DO"] = tr("Dominican Republic");
countries["DZ"] = tr("Algeria");
countries["EC"] = tr("Ecuador");
countries["EE"] = tr("Estonia");
countries["EG"] = tr("Egypt");
countries["EH"] = tr("Western Sahara");
countries["ER"] = tr("Eritrea");
countries["ES"] = tr("Spain");
countries["ET"] = tr("Ethiopia");
countries["FI"] = tr("Finland");
countries["FJ"] = tr("Fiji");
countries["FK"] = tr("Falkland Islands (Malvinas)");
countries["FM"] = tr("Micronesia, Federated States of");
countries["FO"] = tr("Faroe Islands");
countries["FR"] = tr("France");
countries["GA"] = tr("Gabon");
countries["GB"] = tr("United Kingdom");
countries["GD"] = tr("Grenada");
countries["GE"] = tr("Georgia");
countries["GF"] = tr("French Guiana");
countries["GG"] = tr("Guernsey");
countries["GH"] = tr("Ghana");
countries["GI"] = tr("Gibraltar");
countries["GL"] = tr("Greenland");
countries["GM"] = tr("Gambia");
countries["GN"] = tr("Guinea");
countries["GP"] = tr("Guadeloupe");
countries["GQ"] = tr("Equatorial Guinea");
countries["GR"] = tr("Greece");
countries["GS"] = tr("South Georgia and the South Sandwich Islands");
countries["GT"] = tr("Guatemala");
countries["GU"] = tr("Guam");
countries["GW"] = tr("Guinea-Bissau");
countries["GY"] = tr("Guyana");
countries["HK"] = tr("Hong Kong");
countries["HM"] = tr("Heard Island and McDonald Islands");
countries["HN"] = tr("Honduras");
countries["HR"] = tr("Croatia");
countries["HT"] = tr("Haiti");
countries["HU"] = tr("Hungary");
countries["ID"] = tr("Indonesia");
countries["IE"] = tr("Ireland");
countries["IL"] = tr("Israel");
countries["IM"] = tr("Isle of Man");
countries["IN"] = tr("India");
countries["IO"] = tr("British Indian Ocean Territory");
countries["IQ"] = tr("Iraq");
countries["IR"] = tr("Iran, Islamic Republic of");
countries["IS"] = tr("Iceland");
countries["IT"] = tr("Italy");
countries["JE"] = tr("Jersey");
countries["JM"] = tr("Jamaica");
countries["JO"] = tr("Jordan");
countries["JP"] = tr("Japan");
countries["KE"] = tr("Kenya");
countries["KG"] = tr("Kyrgyzstan");
countries["KH"] = tr("Cambodia");
countries["KI"] = tr("Kiribati");
countries["KM"] = tr("Comoros");
countries["KN"] = tr("Saint Kitts and Nevis");
countries["KP"] = tr("Korea, Democratic People's Republic of");
countries["KR"] = tr("Korea, Republic of");
countries["KW"] = tr("Kuwait");
countries["KY"] = tr("Cayman Islands");
countries["KZ"] = tr("Kazakhstan");
countries["LA"] = tr("Lao People's Democratic Republic");
countries["LB"] = tr("Lebanon");
countries["LC"] = tr("Saint Lucia");
countries["LI"] = tr("Liechtenstein");
countries["LK"] = tr("Sri Lanka");
countries["LR"] = tr("Liberia");
countries["LS"] = tr("Lesotho");
countries["LT"] = tr("Lithuania");
countries["LU"] = tr("Luxembourg");
countries["LV"] = tr("Latvia");
countries["LY"] = tr("Libya");
countries["MA"] = tr("Morocco");
countries["MC"] = tr("Monaco");
countries["MD"] = tr("Moldova, Republic of");
countries["ME"] = tr("Montenegro");
countries["MF"] = tr("Saint Martin (French part)");
countries["MG"] = tr("Madagascar");
countries["MH"] = tr("Marshall Islands");
countries["MK"] = tr("Macedonia, The Former Yugoslav Republic of");
countries["ML"] = tr("Mali");
countries["MM"] = tr("Myanmar");
countries["MN"] = tr("Mongolia");
countries["MO"] = tr("Macao");
countries["MP"] = tr("Northern Mariana Islands");
countries["MQ"] = tr("Martinique");
countries["MR"] = tr("Mauritania");
countries["MS"] = tr("Montserrat");
countries["MT"] = tr("Malta");
countries["MU"] = tr("Mauritius");
countries["MV"] = tr("Maldives");
countries["MW"] = tr("Malawi");
countries["MX"] = tr("Mexico");
countries["MY"] = tr("Malaysia");
countries["MZ"] = tr("Mozambique");
countries["NA"] = tr("Namibia");
countries["NC"] = tr("New Caledonia");
countries["NE"] = tr("Niger");
countries["NF"] = tr("Norfolk Island");
countries["NG"] = tr("Nigeria");
countries["NI"] = tr("Nicaragua");
countries["NL"] = tr("Netherlands");
countries["NO"] = tr("Norway");
countries["NP"] = tr("Nepal");
countries["NR"] = tr("Nauru");
countries["NU"] = tr("Niue");
countries["NZ"] = tr("New Zealand");
countries["OM"] = tr("Oman");
countries["PA"] = tr("Panama");
countries["PE"] = tr("Peru");
countries["PF"] = tr("French Polynesia");
countries["PG"] = tr("Papua New Guinea");
countries["PH"] = tr("Philippines");
countries["PK"] = tr("Pakistan");
countries["PL"] = tr("Poland");
countries["PM"] = tr("Saint Pierre and Miquelon");
countries["PN"] = tr("Pitcairn");
countries["PR"] = tr("Puerto Rico");
countries["PS"] = tr("Palestine, State of");
countries["PT"] = tr("Portugal");
countries["PW"] = tr("Palau");
countries["PY"] = tr("Paraguay");
countries["QA"] = tr("Qatar");
countries["RE"] = tr("Reunion");
countries["RO"] = tr("Romania");
countries["RS"] = tr("Serbia");
countries["RU"] = tr("Russian Federation");
countries["RW"] = tr("Rwanda");
countries["SA"] = tr("Saudi Arabia");
countries["SB"] = tr("Solomon Islands");
countries["SC"] = tr("Seychelles");
countries["SD"] = tr("Sudan");
countries["SE"] = tr("Sweden");
countries["SG"] = tr("Singapore");
countries["SH"] = tr("Saint Helena, Ascension and Tristan da Cunha");
countries["SI"] = tr("Slovenia");
countries["SJ"] = tr("Svalbard and Jan Mayen");
countries["SK"] = tr("Slovakia");
countries["SL"] = tr("Sierra Leone");
countries["SM"] = tr("San Marino");
countries["SN"] = tr("Senegal");
countries["SO"] = tr("Somalia");
countries["SR"] = tr("Suriname");
countries["SS"] = tr("South Sudan");
countries["ST"] = tr("Sao Tome and Principe");
countries["SV"] = tr("El Salvador");
countries["SX"] = tr("Sint Maarten (Dutch part)");
countries["SY"] = tr("Syrian Arab Republic");
countries["SZ"] = tr("Swaziland");
countries["TC"] = tr("Turks and Caicos Islands");
countries["TD"] = tr("Chad");
countries["TF"] = tr("French Southern Territories");
countries["TG"] = tr("Togo");
countries["TH"] = tr("Thailand");
countries["TJ"] = tr("Tajikistan");
countries["TK"] = tr("Tokelau");
countries["TL"] = tr("Timor-Leste");
countries["TM"] = tr("Turkmenistan");
countries["TN"] = tr("Tunisia");
countries["TO"] = tr("Tonga");
countries["TR"] = tr("Turkey");
countries["TT"] = tr("Trinidad and Tobago");
countries["TV"] = tr("Tuvalu");
countries["TW"] = tr("Taiwan");
countries["TZ"] = tr("Tanzania, United Republic of");
countries["UA"] = tr("Ukraine");
countries["UG"] = tr("Uganda");
countries["UM"] = tr("United States Minor Outlying Islands");
countries["US"] = tr("United States");
countries["UY"] = tr("Uruguay");
countries["UZ"] = tr("Uzbekistan");
countries["VA"] = tr("Holy See (Vatican City State)");
countries["VC"] = tr("Saint Vincent and the Grenadines");
countries["VE"] = tr("Venezuela, Bolivarian Republic of");
countries["VG"] = tr("Virgin Islands, British");
countries["VI"] = tr("Virgin Islands, U.S.");
countries["VN"] = tr("Viet Nam");
countries["VU"] = tr("Vanuatu");
countries["WF"] = tr("Wallis and Futuna");
countries["WS"] = tr("Samoa");
countries["YE"] = tr("Yemen");
countries["YT"] = tr("Mayotte");
countries["ZA"] = tr("South Africa");
countries["ZM"] = tr("Zambia");
countries["ZW"] = tr("Zimbabwe");
countries[QString()] = tr("N/A");
initialized = true;
}
return countries.value(countryISOCode, tr("N/A"));
}
void GeoIPManager::configure()
{
const bool enabled = Preferences::instance()->resolvePeerCountries();
if (m_enabled != enabled) {
m_enabled = enabled;
if (m_enabled && !m_geoIPDatabase) {
loadDatabase();
}
else if (!m_enabled && m_geoIPDatabase) {
delete m_geoIPDatabase;
m_geoIPDatabase = 0;
}
}
}
void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
{
Q_UNUSED(url);
if (!Utils::Gzip::uncompress(data, data)) {
Logger::instance()->addMessage(tr("Could not uncompress GeoIP database file."), Log::WARNING);
return;
}
QString error;
GeoIPDatabase *geoIPDatabase = GeoIPDatabase::load(data, error);
if (geoIPDatabase) {
if (!m_geoIPDatabase || (geoIPDatabase->buildEpoch() > m_geoIPDatabase->buildEpoch())) {
if (m_geoIPDatabase)
delete m_geoIPDatabase;
m_geoIPDatabase = geoIPDatabase;
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type()).arg(m_geoIPDatabase->buildEpoch().toString()),
Log::INFO);
QString targetPath = Utils::Fs::expandPathAbs(
Utils::Fs::QDesktopServicesDataLocation() + GEOIP_FOLDER);
if (!QDir(targetPath).exists())
QDir().mkpath(targetPath);
QFile targetFile(QString("%1/%2").arg(targetPath).arg(GEOIP_FILENAME));
if (!targetFile.open(QFile::WriteOnly) || (targetFile.write(data) == -1)) {
Logger::instance()->addMessage(
tr("Couldn't save downloaded GeoIP database file."), Log::WARNING);
}
else {
Logger::instance()->addMessage(tr("Successfully updated GeoIP database."), Log::INFO);
}
}
else {
delete geoIPDatabase;
}
}
else {
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING);
}
}
void GeoIPManager::downloadFailed(const QString &url, const QString &reason)
{
Q_UNUSED(url);
Logger::instance()->addMessage(tr("Couldn't download GeoIP database file. Reason: %1").arg(reason), Log::WARNING);
}