Sync Changelog entries between branches
[qBittorrent.git] / src / base / net / geoipmanager.cpp
blobf0bd89cdb80eea9561a07b9c28c46eccafcb7767
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
4 * Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * In addition, as a special exception, the copyright holders give permission to
21 * link this program with the OpenSSL project's "OpenSSL" library (or with
22 * modified versions of it that use the same license as the "OpenSSL" library),
23 * and distribute the linked executables. You must obey the GNU General Public
24 * License in all respects for all of the code used other than "OpenSSL". If you
25 * modify file(s), you may extend this exception to your version of the file(s),
26 * but you are not obligated to do so. If you do not wish to do so, delete this
27 * exception statement from your version.
30 #include "geoipmanager.h"
32 #include <QDateTime>
33 #include <QDir>
34 #include <QHostAddress>
35 #include <QLocale>
37 #include "base/logger.h"
38 #include "base/preferences.h"
39 #include "base/profile.h"
40 #include "base/utils/fs.h"
41 #include "base/utils/gzip.h"
42 #include "base/utils/io.h"
43 #include "downloadmanager.h"
44 #include "geoipdatabase.h"
46 static const QString DATABASE_URL = QStringLiteral("https://download.db-ip.com/free/dbip-country-lite-%1.mmdb.gz");
47 static const char GEODB_FOLDER[] = "GeoDB";
48 static const char GEODB_FILENAME[] = "dbip-country-lite.mmdb";
50 using namespace Net;
52 // GeoIPManager
54 GeoIPManager *GeoIPManager::m_instance = nullptr;
56 GeoIPManager::GeoIPManager()
57 : m_enabled(false)
58 , m_geoIPDatabase(nullptr)
60 configure();
61 connect(Preferences::instance(), &Preferences::changed, this, &GeoIPManager::configure);
64 GeoIPManager::~GeoIPManager()
66 delete m_geoIPDatabase;
69 void GeoIPManager::initInstance()
71 if (!m_instance)
72 m_instance = new GeoIPManager;
75 void GeoIPManager::freeInstance()
77 delete m_instance;
78 m_instance = nullptr;
81 GeoIPManager *GeoIPManager::instance()
83 return m_instance;
86 void GeoIPManager::loadDatabase()
88 delete m_geoIPDatabase;
89 m_geoIPDatabase = nullptr;
91 const QString filepath = Utils::Fs::expandPathAbs(
92 QString::fromLatin1("%1%2/%3").arg(specialFolderLocation(SpecialFolder::Data), GEODB_FOLDER, GEODB_FILENAME));
94 QString error;
95 m_geoIPDatabase = GeoIPDatabase::load(filepath, error);
96 if (m_geoIPDatabase)
97 Logger::instance()->addMessage(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
98 .arg(m_geoIPDatabase->type(), m_geoIPDatabase->buildEpoch().toString()),
99 Log::INFO);
100 else
101 Logger::instance()->addMessage(tr("Couldn't load IP geolocation database. Reason: %1").arg(error), Log::WARNING);
103 manageDatabaseUpdate();
106 void GeoIPManager::manageDatabaseUpdate()
108 const auto expired = [](const QDateTime &testDateTime)
110 const QDate testDate = testDateTime.date();
111 const QDate curDate = QDateTime::currentDateTimeUtc().date();
113 if ((testDate.year() < curDate.year()) && (curDate.day() > 1))
114 return true;
116 if ((testDate.month() < curDate.month()) && (curDate.day() > 1))
117 return true;
119 return false;
122 if (!m_geoIPDatabase || expired(m_geoIPDatabase->buildEpoch()))
123 downloadDatabaseFile();
126 void GeoIPManager::downloadDatabaseFile()
128 const QDateTime curDatetime = QDateTime::currentDateTimeUtc();
129 const QString curUrl = DATABASE_URL.arg(QLocale::c().toString(curDatetime, "yyyy-MM"));
130 DownloadManager::instance()->download({curUrl}, this, &GeoIPManager::downloadFinished);
133 QString GeoIPManager::lookup(const QHostAddress &hostAddr) const
135 if (m_enabled && m_geoIPDatabase)
136 return m_geoIPDatabase->lookup(hostAddr);
138 return {};
141 QString GeoIPManager::CountryName(const QString &countryISOCode)
143 static const QHash<QString, QString> countries =
145 // ISO 3166-1 alpha-2 codes
146 // http://www.iso.org/iso/home/standards/country_codes/country_names_and_code_elements_txt-temp.htm
148 // Officially assigned
149 {"AD", tr("Andorra")},
150 {"AE", tr("United Arab Emirates")},
151 {"AF", tr("Afghanistan")},
152 {"AG", tr("Antigua and Barbuda")},
153 {"AI", tr("Anguilla")},
154 {"AL", tr("Albania")},
155 {"AM", tr("Armenia")},
156 {"AO", tr("Angola")},
157 {"AQ", tr("Antarctica")},
158 {"AR", tr("Argentina")},
159 {"AS", tr("American Samoa")},
160 {"AT", tr("Austria")},
161 {"AU", tr("Australia")},
162 {"AW", tr("Aruba")},
163 {"AX", tr("Aland Islands")},
164 {"AZ", tr("Azerbaijan")},
165 {"BA", tr("Bosnia and Herzegovina")},
166 {"BB", tr("Barbados")},
167 {"BD", tr("Bangladesh")},
168 {"BE", tr("Belgium")},
169 {"BF", tr("Burkina Faso")},
170 {"BG", tr("Bulgaria")},
171 {"BH", tr("Bahrain")},
172 {"BI", tr("Burundi")},
173 {"BJ", tr("Benin")},
174 {"BL", tr("Saint Barthelemy")},
175 {"BM", tr("Bermuda")},
176 {"BN", tr("Brunei Darussalam")},
177 {"BO", tr("Bolivia, Plurinational State of")},
178 {"BQ", tr("Bonaire, Sint Eustatius and Saba")},
179 {"BR", tr("Brazil")},
180 {"BS", tr("Bahamas")},
181 {"BT", tr("Bhutan")},
182 {"BV", tr("Bouvet Island")},
183 {"BW", tr("Botswana")},
184 {"BY", tr("Belarus")},
185 {"BZ", tr("Belize")},
186 {"CA", tr("Canada")},
187 {"CC", tr("Cocos (Keeling) Islands")},
188 {"CD", tr("Congo, The Democratic Republic of the")},
189 {"CF", tr("Central African Republic")},
190 {"CG", tr("Congo")},
191 {"CH", tr("Switzerland")},
192 {"CI", tr("Cote d'Ivoire")},
193 {"CK", tr("Cook Islands")},
194 {"CL", tr("Chile")},
195 {"CM", tr("Cameroon")},
196 {"CN", tr("China")},
197 {"CO", tr("Colombia")},
198 {"CR", tr("Costa Rica")},
199 {"CU", tr("Cuba")},
200 {"CV", tr("Cape Verde")},
201 {"CW", tr("Curacao")},
202 {"CX", tr("Christmas Island")},
203 {"CY", tr("Cyprus")},
204 {"CZ", tr("Czech Republic")},
205 {"DE", tr("Germany")},
206 {"DJ", tr("Djibouti")},
207 {"DK", tr("Denmark")},
208 {"DM", tr("Dominica")},
209 {"DO", tr("Dominican Republic")},
210 {"DZ", tr("Algeria")},
211 {"EC", tr("Ecuador")},
212 {"EE", tr("Estonia")},
213 {"EG", tr("Egypt")},
214 {"EH", tr("Western Sahara")},
215 {"ER", tr("Eritrea")},
216 {"ES", tr("Spain")},
217 {"ET", tr("Ethiopia")},
218 {"FI", tr("Finland")},
219 {"FJ", tr("Fiji")},
220 {"FK", tr("Falkland Islands (Malvinas)")},
221 {"FM", tr("Micronesia, Federated States of")},
222 {"FO", tr("Faroe Islands")},
223 {"FR", tr("France")},
224 {"GA", tr("Gabon")},
225 {"GB", tr("United Kingdom")},
226 {"GD", tr("Grenada")},
227 {"GE", tr("Georgia")},
228 {"GF", tr("French Guiana")},
229 {"GG", tr("Guernsey")},
230 {"GH", tr("Ghana")},
231 {"GI", tr("Gibraltar")},
232 {"GL", tr("Greenland")},
233 {"GM", tr("Gambia")},
234 {"GN", tr("Guinea")},
235 {"GP", tr("Guadeloupe")},
236 {"GQ", tr("Equatorial Guinea")},
237 {"GR", tr("Greece")},
238 {"GS", tr("South Georgia and the South Sandwich Islands")},
239 {"GT", tr("Guatemala")},
240 {"GU", tr("Guam")},
241 {"GW", tr("Guinea-Bissau")},
242 {"GY", tr("Guyana")},
243 {"HK", tr("Hong Kong")},
244 {"HM", tr("Heard Island and McDonald Islands")},
245 {"HN", tr("Honduras")},
246 {"HR", tr("Croatia")},
247 {"HT", tr("Haiti")},
248 {"HU", tr("Hungary")},
249 {"ID", tr("Indonesia")},
250 {"IE", tr("Ireland")},
251 {"IL", tr("Israel")},
252 {"IM", tr("Isle of Man")},
253 {"IN", tr("India")},
254 {"IO", tr("British Indian Ocean Territory")},
255 {"IQ", tr("Iraq")},
256 {"IR", tr("Iran, Islamic Republic of")},
257 {"IS", tr("Iceland")},
258 {"IT", tr("Italy")},
259 {"JE", tr("Jersey")},
260 {"JM", tr("Jamaica")},
261 {"JO", tr("Jordan")},
262 {"JP", tr("Japan")},
263 {"KE", tr("Kenya")},
264 {"KG", tr("Kyrgyzstan")},
265 {"KH", tr("Cambodia")},
266 {"KI", tr("Kiribati")},
267 {"KM", tr("Comoros")},
268 {"KN", tr("Saint Kitts and Nevis")},
269 {"KP", tr("Korea, Democratic People's Republic of")},
270 {"KR", tr("Korea, Republic of")},
271 {"KW", tr("Kuwait")},
272 {"KY", tr("Cayman Islands")},
273 {"KZ", tr("Kazakhstan")},
274 {"LA", tr("Lao People's Democratic Republic")},
275 {"LB", tr("Lebanon")},
276 {"LC", tr("Saint Lucia")},
277 {"LI", tr("Liechtenstein")},
278 {"LK", tr("Sri Lanka")},
279 {"LR", tr("Liberia")},
280 {"LS", tr("Lesotho")},
281 {"LT", tr("Lithuania")},
282 {"LU", tr("Luxembourg")},
283 {"LV", tr("Latvia")},
284 {"LY", tr("Libya")},
285 {"MA", tr("Morocco")},
286 {"MC", tr("Monaco")},
287 {"MD", tr("Moldova, Republic of")},
288 {"ME", tr("Montenegro")},
289 {"MF", tr("Saint Martin (French part)")},
290 {"MG", tr("Madagascar")},
291 {"MH", tr("Marshall Islands")},
292 {"MK", tr("Macedonia, The Former Yugoslav Republic of")},
293 {"ML", tr("Mali")},
294 {"MM", tr("Myanmar")},
295 {"MN", tr("Mongolia")},
296 {"MO", tr("Macao")},
297 {"MP", tr("Northern Mariana Islands")},
298 {"MQ", tr("Martinique")},
299 {"MR", tr("Mauritania")},
300 {"MS", tr("Montserrat")},
301 {"MT", tr("Malta")},
302 {"MU", tr("Mauritius")},
303 {"MV", tr("Maldives")},
304 {"MW", tr("Malawi")},
305 {"MX", tr("Mexico")},
306 {"MY", tr("Malaysia")},
307 {"MZ", tr("Mozambique")},
308 {"NA", tr("Namibia")},
309 {"NC", tr("New Caledonia")},
310 {"NE", tr("Niger")},
311 {"NF", tr("Norfolk Island")},
312 {"NG", tr("Nigeria")},
313 {"NI", tr("Nicaragua")},
314 {"NL", tr("Netherlands")},
315 {"NO", tr("Norway")},
316 {"NP", tr("Nepal")},
317 {"NR", tr("Nauru")},
318 {"NU", tr("Niue")},
319 {"NZ", tr("New Zealand")},
320 {"OM", tr("Oman")},
321 {"PA", tr("Panama")},
322 {"PE", tr("Peru")},
323 {"PF", tr("French Polynesia")},
324 {"PG", tr("Papua New Guinea")},
325 {"PH", tr("Philippines")},
326 {"PK", tr("Pakistan")},
327 {"PL", tr("Poland")},
328 {"PM", tr("Saint Pierre and Miquelon")},
329 {"PN", tr("Pitcairn")},
330 {"PR", tr("Puerto Rico")},
331 {"PS", tr("Palestine, State of")},
332 {"PT", tr("Portugal")},
333 {"PW", tr("Palau")},
334 {"PY", tr("Paraguay")},
335 {"QA", tr("Qatar")},
336 {"RE", tr("Reunion")},
337 {"RO", tr("Romania")},
338 {"RS", tr("Serbia")},
339 {"RU", tr("Russian Federation")},
340 {"RW", tr("Rwanda")},
341 {"SA", tr("Saudi Arabia")},
342 {"SB", tr("Solomon Islands")},
343 {"SC", tr("Seychelles")},
344 {"SD", tr("Sudan")},
345 {"SE", tr("Sweden")},
346 {"SG", tr("Singapore")},
347 {"SH", tr("Saint Helena, Ascension and Tristan da Cunha")},
348 {"SI", tr("Slovenia")},
349 {"SJ", tr("Svalbard and Jan Mayen")},
350 {"SK", tr("Slovakia")},
351 {"SL", tr("Sierra Leone")},
352 {"SM", tr("San Marino")},
353 {"SN", tr("Senegal")},
354 {"SO", tr("Somalia")},
355 {"SR", tr("Suriname")},
356 {"SS", tr("South Sudan")},
357 {"ST", tr("Sao Tome and Principe")},
358 {"SV", tr("El Salvador")},
359 {"SX", tr("Sint Maarten (Dutch part)")},
360 {"SY", tr("Syrian Arab Republic")},
361 {"SZ", tr("Swaziland")},
362 {"TC", tr("Turks and Caicos Islands")},
363 {"TD", tr("Chad")},
364 {"TF", tr("French Southern Territories")},
365 {"TG", tr("Togo")},
366 {"TH", tr("Thailand")},
367 {"TJ", tr("Tajikistan")},
368 {"TK", tr("Tokelau")},
369 {"TL", tr("Timor-Leste")},
370 {"TM", tr("Turkmenistan")},
371 {"TN", tr("Tunisia")},
372 {"TO", tr("Tonga")},
373 {"TR", tr("Turkey")},
374 {"TT", tr("Trinidad and Tobago")},
375 {"TV", tr("Tuvalu")},
376 {"TW", tr("Taiwan")},
377 {"TZ", tr("Tanzania, United Republic of")},
378 {"UA", tr("Ukraine")},
379 {"UG", tr("Uganda")},
380 {"UM", tr("United States Minor Outlying Islands")},
381 {"US", tr("United States")},
382 {"UY", tr("Uruguay")},
383 {"UZ", tr("Uzbekistan")},
384 {"VA", tr("Holy See (Vatican City State)")},
385 {"VC", tr("Saint Vincent and the Grenadines")},
386 {"VE", tr("Venezuela, Bolivarian Republic of")},
387 {"VG", tr("Virgin Islands, British")},
388 {"VI", tr("Virgin Islands, U.S.")},
389 {"VN", tr("Vietnam")},
390 {"VU", tr("Vanuatu")},
391 {"WF", tr("Wallis and Futuna")},
392 {"WS", tr("Samoa")},
393 {"YE", tr("Yemen")},
394 {"YT", tr("Mayotte")},
395 {"ZA", tr("South Africa")},
396 {"ZM", tr("Zambia")},
397 {"ZW", tr("Zimbabwe")},
399 {{}, tr("N/A")}
402 return countries.value(countryISOCode, tr("N/A"));
405 void GeoIPManager::configure()
407 const bool enabled = Preferences::instance()->resolvePeerCountries();
408 if (m_enabled != enabled)
410 m_enabled = enabled;
411 if (m_enabled && !m_geoIPDatabase)
413 loadDatabase();
415 else if (!m_enabled)
417 delete m_geoIPDatabase;
418 m_geoIPDatabase = nullptr;
423 void GeoIPManager::downloadFinished(const DownloadResult &result)
425 if (result.status != DownloadStatus::Success)
427 LogMsg(tr("Couldn't download IP geolocation database file. Reason: %1").arg(result.errorString), Log::WARNING);
428 return;
431 bool ok = false;
432 const QByteArray data = Utils::Gzip::decompress(result.data, &ok);
433 if (!ok)
435 LogMsg(tr("Could not decompress IP geolocation database file."), Log::WARNING);
436 return;
439 QString error;
440 GeoIPDatabase *geoIPDatabase = GeoIPDatabase::load(data, error);
441 if (geoIPDatabase)
443 if (!m_geoIPDatabase || (geoIPDatabase->buildEpoch() > m_geoIPDatabase->buildEpoch()))
445 delete m_geoIPDatabase;
446 m_geoIPDatabase = geoIPDatabase;
447 LogMsg(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
448 .arg(m_geoIPDatabase->type(), m_geoIPDatabase->buildEpoch().toString()),
449 Log::INFO);
450 const QString targetPath = Utils::Fs::expandPathAbs(
451 specialFolderLocation(SpecialFolder::Data) + GEODB_FOLDER);
452 if (!QDir(targetPath).exists())
453 QDir().mkpath(targetPath);
455 const auto path = QString::fromLatin1("%1/%2").arg(targetPath, GEODB_FILENAME);
456 const nonstd::expected<void, QString> result = Utils::IO::saveToFile(path, data);
457 if (result)
459 LogMsg(tr("Successfully updated IP geolocation database."), Log::INFO);
461 else
463 LogMsg(tr("Couldn't save downloaded IP geolocation database file. Reason: %1")
464 .arg(result.error()), Log::WARNING);
467 else
469 delete geoIPDatabase;
472 else
474 LogMsg(tr("Couldn't load IP geolocation database. Reason: %1").arg(error), Log::WARNING);