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"
33 #include <QHostAddress>
36 #include "base/global.h"
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 const QString DATABASE_URL
= QStringLiteral("https://download.db-ip.com/free/dbip-country-lite-%1.mmdb.gz");
47 const QString GEODB_FOLDER
= u
"GeoDB"_qs
;
48 const QString GEODB_FILENAME
= u
"dbip-country-lite.mmdb"_qs
;
54 GeoIPManager
*GeoIPManager::m_instance
= nullptr;
56 GeoIPManager::GeoIPManager()
58 , m_geoIPDatabase(nullptr)
61 connect(Preferences::instance(), &Preferences::changed
, this, &GeoIPManager::configure
);
64 GeoIPManager::~GeoIPManager()
66 delete m_geoIPDatabase
;
69 void GeoIPManager::initInstance()
72 m_instance
= new GeoIPManager
;
75 void GeoIPManager::freeInstance()
81 GeoIPManager
*GeoIPManager::instance()
86 void GeoIPManager::loadDatabase()
88 delete m_geoIPDatabase
;
89 m_geoIPDatabase
= nullptr;
91 const Path filepath
= specialFolderLocation(SpecialFolder::Data
)
92 / Path(GEODB_FOLDER
) / Path(GEODB_FILENAME
);
95 m_geoIPDatabase
= GeoIPDatabase::load(filepath
, error
);
98 Logger::instance()->addMessage(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
99 .arg(m_geoIPDatabase
->type(), m_geoIPDatabase
->buildEpoch().toString()),
104 Logger::instance()->addMessage(tr("Couldn't load IP geolocation database. Reason: %1").arg(error
), Log::WARNING
);
107 manageDatabaseUpdate();
110 void GeoIPManager::manageDatabaseUpdate()
112 const auto expired
= [](const QDateTime
&testDateTime
)
114 const QDate testDate
= testDateTime
.date();
115 const QDate curDate
= QDateTime::currentDateTimeUtc().date();
117 if ((testDate
.year() < curDate
.year()) && (curDate
.day() > 1))
120 if ((testDate
.month() < curDate
.month()) && (curDate
.day() > 1))
126 if (!m_geoIPDatabase
|| expired(m_geoIPDatabase
->buildEpoch()))
127 downloadDatabaseFile();
130 void GeoIPManager::downloadDatabaseFile()
132 const QDateTime curDatetime
= QDateTime::currentDateTimeUtc();
133 const QString curUrl
= DATABASE_URL
.arg(QLocale::c().toString(curDatetime
, u
"yyyy-MM"));
134 DownloadManager::instance()->download({curUrl
}, this, &GeoIPManager::downloadFinished
);
137 QString
GeoIPManager::lookup(const QHostAddress
&hostAddr
) const
139 if (m_enabled
&& m_geoIPDatabase
)
140 return m_geoIPDatabase
->lookup(hostAddr
);
145 QString
GeoIPManager::CountryName(const QString
&countryISOCode
)
147 static const QHash
<QString
, QString
> countries
=
149 // ISO 3166-1 alpha-2 codes
150 // http://www.iso.org/iso/home/standards/country_codes/country_names_and_code_elements_txt-temp.htm
152 // Officially assigned
153 {u
"AD"_qs
, tr("Andorra")},
154 {u
"AE"_qs
, tr("United Arab Emirates")},
155 {u
"AF"_qs
, tr("Afghanistan")},
156 {u
"AG"_qs
, tr("Antigua and Barbuda")},
157 {u
"AI"_qs
, tr("Anguilla")},
158 {u
"AL"_qs
, tr("Albania")},
159 {u
"AM"_qs
, tr("Armenia")},
160 {u
"AO"_qs
, tr("Angola")},
161 {u
"AQ"_qs
, tr("Antarctica")},
162 {u
"AR"_qs
, tr("Argentina")},
163 {u
"AS"_qs
, tr("American Samoa")},
164 {u
"AT"_qs
, tr("Austria")},
165 {u
"AU"_qs
, tr("Australia")},
166 {u
"AW"_qs
, tr("Aruba")},
167 {u
"AX"_qs
, tr("Aland Islands")},
168 {u
"AZ"_qs
, tr("Azerbaijan")},
169 {u
"BA"_qs
, tr("Bosnia and Herzegovina")},
170 {u
"BB"_qs
, tr("Barbados")},
171 {u
"BD"_qs
, tr("Bangladesh")},
172 {u
"BE"_qs
, tr("Belgium")},
173 {u
"BF"_qs
, tr("Burkina Faso")},
174 {u
"BG"_qs
, tr("Bulgaria")},
175 {u
"BH"_qs
, tr("Bahrain")},
176 {u
"BI"_qs
, tr("Burundi")},
177 {u
"BJ"_qs
, tr("Benin")},
178 {u
"BL"_qs
, tr("Saint Barthelemy")},
179 {u
"BM"_qs
, tr("Bermuda")},
180 {u
"BN"_qs
, tr("Brunei Darussalam")},
181 {u
"BO"_qs
, tr("Bolivia, Plurinational State of")},
182 {u
"BQ"_qs
, tr("Bonaire, Sint Eustatius and Saba")},
183 {u
"BR"_qs
, tr("Brazil")},
184 {u
"BS"_qs
, tr("Bahamas")},
185 {u
"BT"_qs
, tr("Bhutan")},
186 {u
"BV"_qs
, tr("Bouvet Island")},
187 {u
"BW"_qs
, tr("Botswana")},
188 {u
"BY"_qs
, tr("Belarus")},
189 {u
"BZ"_qs
, tr("Belize")},
190 {u
"CA"_qs
, tr("Canada")},
191 {u
"CC"_qs
, tr("Cocos (Keeling) Islands")},
192 {u
"CD"_qs
, tr("Congo, The Democratic Republic of the")},
193 {u
"CF"_qs
, tr("Central African Republic")},
194 {u
"CG"_qs
, tr("Congo")},
195 {u
"CH"_qs
, tr("Switzerland")},
196 {u
"CI"_qs
, tr("Cote d'Ivoire")},
197 {u
"CK"_qs
, tr("Cook Islands")},
198 {u
"CL"_qs
, tr("Chile")},
199 {u
"CM"_qs
, tr("Cameroon")},
200 {u
"CN"_qs
, tr("China")},
201 {u
"CO"_qs
, tr("Colombia")},
202 {u
"CR"_qs
, tr("Costa Rica")},
203 {u
"CU"_qs
, tr("Cuba")},
204 {u
"CV"_qs
, tr("Cape Verde")},
205 {u
"CW"_qs
, tr("Curacao")},
206 {u
"CX"_qs
, tr("Christmas Island")},
207 {u
"CY"_qs
, tr("Cyprus")},
208 {u
"CZ"_qs
, tr("Czech Republic")},
209 {u
"DE"_qs
, tr("Germany")},
210 {u
"DJ"_qs
, tr("Djibouti")},
211 {u
"DK"_qs
, tr("Denmark")},
212 {u
"DM"_qs
, tr("Dominica")},
213 {u
"DO"_qs
, tr("Dominican Republic")},
214 {u
"DZ"_qs
, tr("Algeria")},
215 {u
"EC"_qs
, tr("Ecuador")},
216 {u
"EE"_qs
, tr("Estonia")},
217 {u
"EG"_qs
, tr("Egypt")},
218 {u
"EH"_qs
, tr("Western Sahara")},
219 {u
"ER"_qs
, tr("Eritrea")},
220 {u
"ES"_qs
, tr("Spain")},
221 {u
"ET"_qs
, tr("Ethiopia")},
222 {u
"FI"_qs
, tr("Finland")},
223 {u
"FJ"_qs
, tr("Fiji")},
224 {u
"FK"_qs
, tr("Falkland Islands (Malvinas)")},
225 {u
"FM"_qs
, tr("Micronesia, Federated States of")},
226 {u
"FO"_qs
, tr("Faroe Islands")},
227 {u
"FR"_qs
, tr("France")},
228 {u
"GA"_qs
, tr("Gabon")},
229 {u
"GB"_qs
, tr("United Kingdom")},
230 {u
"GD"_qs
, tr("Grenada")},
231 {u
"GE"_qs
, tr("Georgia")},
232 {u
"GF"_qs
, tr("French Guiana")},
233 {u
"GG"_qs
, tr("Guernsey")},
234 {u
"GH"_qs
, tr("Ghana")},
235 {u
"GI"_qs
, tr("Gibraltar")},
236 {u
"GL"_qs
, tr("Greenland")},
237 {u
"GM"_qs
, tr("Gambia")},
238 {u
"GN"_qs
, tr("Guinea")},
239 {u
"GP"_qs
, tr("Guadeloupe")},
240 {u
"GQ"_qs
, tr("Equatorial Guinea")},
241 {u
"GR"_qs
, tr("Greece")},
242 {u
"GS"_qs
, tr("South Georgia and the South Sandwich Islands")},
243 {u
"GT"_qs
, tr("Guatemala")},
244 {u
"GU"_qs
, tr("Guam")},
245 {u
"GW"_qs
, tr("Guinea-Bissau")},
246 {u
"GY"_qs
, tr("Guyana")},
247 {u
"HK"_qs
, tr("Hong Kong")},
248 {u
"HM"_qs
, tr("Heard Island and McDonald Islands")},
249 {u
"HN"_qs
, tr("Honduras")},
250 {u
"HR"_qs
, tr("Croatia")},
251 {u
"HT"_qs
, tr("Haiti")},
252 {u
"HU"_qs
, tr("Hungary")},
253 {u
"ID"_qs
, tr("Indonesia")},
254 {u
"IE"_qs
, tr("Ireland")},
255 {u
"IL"_qs
, tr("Israel")},
256 {u
"IM"_qs
, tr("Isle of Man")},
257 {u
"IN"_qs
, tr("India")},
258 {u
"IO"_qs
, tr("British Indian Ocean Territory")},
259 {u
"IQ"_qs
, tr("Iraq")},
260 {u
"IR"_qs
, tr("Iran, Islamic Republic of")},
261 {u
"IS"_qs
, tr("Iceland")},
262 {u
"IT"_qs
, tr("Italy")},
263 {u
"JE"_qs
, tr("Jersey")},
264 {u
"JM"_qs
, tr("Jamaica")},
265 {u
"JO"_qs
, tr("Jordan")},
266 {u
"JP"_qs
, tr("Japan")},
267 {u
"KE"_qs
, tr("Kenya")},
268 {u
"KG"_qs
, tr("Kyrgyzstan")},
269 {u
"KH"_qs
, tr("Cambodia")},
270 {u
"KI"_qs
, tr("Kiribati")},
271 {u
"KM"_qs
, tr("Comoros")},
272 {u
"KN"_qs
, tr("Saint Kitts and Nevis")},
273 {u
"KP"_qs
, tr("Korea, Democratic People's Republic of")},
274 {u
"KR"_qs
, tr("Korea, Republic of")},
275 {u
"KW"_qs
, tr("Kuwait")},
276 {u
"KY"_qs
, tr("Cayman Islands")},
277 {u
"KZ"_qs
, tr("Kazakhstan")},
278 {u
"LA"_qs
, tr("Lao People's Democratic Republic")},
279 {u
"LB"_qs
, tr("Lebanon")},
280 {u
"LC"_qs
, tr("Saint Lucia")},
281 {u
"LI"_qs
, tr("Liechtenstein")},
282 {u
"LK"_qs
, tr("Sri Lanka")},
283 {u
"LR"_qs
, tr("Liberia")},
284 {u
"LS"_qs
, tr("Lesotho")},
285 {u
"LT"_qs
, tr("Lithuania")},
286 {u
"LU"_qs
, tr("Luxembourg")},
287 {u
"LV"_qs
, tr("Latvia")},
288 {u
"LY"_qs
, tr("Libya")},
289 {u
"MA"_qs
, tr("Morocco")},
290 {u
"MC"_qs
, tr("Monaco")},
291 {u
"MD"_qs
, tr("Moldova, Republic of")},
292 {u
"ME"_qs
, tr("Montenegro")},
293 {u
"MF"_qs
, tr("Saint Martin (French part)")},
294 {u
"MG"_qs
, tr("Madagascar")},
295 {u
"MH"_qs
, tr("Marshall Islands")},
296 {u
"MK"_qs
, tr("Macedonia, The Former Yugoslav Republic of")},
297 {u
"ML"_qs
, tr("Mali")},
298 {u
"MM"_qs
, tr("Myanmar")},
299 {u
"MN"_qs
, tr("Mongolia")},
300 {u
"MO"_qs
, tr("Macao")},
301 {u
"MP"_qs
, tr("Northern Mariana Islands")},
302 {u
"MQ"_qs
, tr("Martinique")},
303 {u
"MR"_qs
, tr("Mauritania")},
304 {u
"MS"_qs
, tr("Montserrat")},
305 {u
"MT"_qs
, tr("Malta")},
306 {u
"MU"_qs
, tr("Mauritius")},
307 {u
"MV"_qs
, tr("Maldives")},
308 {u
"MW"_qs
, tr("Malawi")},
309 {u
"MX"_qs
, tr("Mexico")},
310 {u
"MY"_qs
, tr("Malaysia")},
311 {u
"MZ"_qs
, tr("Mozambique")},
312 {u
"NA"_qs
, tr("Namibia")},
313 {u
"NC"_qs
, tr("New Caledonia")},
314 {u
"NE"_qs
, tr("Niger")},
315 {u
"NF"_qs
, tr("Norfolk Island")},
316 {u
"NG"_qs
, tr("Nigeria")},
317 {u
"NI"_qs
, tr("Nicaragua")},
318 {u
"NL"_qs
, tr("Netherlands")},
319 {u
"NO"_qs
, tr("Norway")},
320 {u
"NP"_qs
, tr("Nepal")},
321 {u
"NR"_qs
, tr("Nauru")},
322 {u
"NU"_qs
, tr("Niue")},
323 {u
"NZ"_qs
, tr("New Zealand")},
324 {u
"OM"_qs
, tr("Oman")},
325 {u
"PA"_qs
, tr("Panama")},
326 {u
"PE"_qs
, tr("Peru")},
327 {u
"PF"_qs
, tr("French Polynesia")},
328 {u
"PG"_qs
, tr("Papua New Guinea")},
329 {u
"PH"_qs
, tr("Philippines")},
330 {u
"PK"_qs
, tr("Pakistan")},
331 {u
"PL"_qs
, tr("Poland")},
332 {u
"PM"_qs
, tr("Saint Pierre and Miquelon")},
333 {u
"PN"_qs
, tr("Pitcairn")},
334 {u
"PR"_qs
, tr("Puerto Rico")},
335 {u
"PS"_qs
, tr("Palestine, State of")},
336 {u
"PT"_qs
, tr("Portugal")},
337 {u
"PW"_qs
, tr("Palau")},
338 {u
"PY"_qs
, tr("Paraguay")},
339 {u
"QA"_qs
, tr("Qatar")},
340 {u
"RE"_qs
, tr("Reunion")},
341 {u
"RO"_qs
, tr("Romania")},
342 {u
"RS"_qs
, tr("Serbia")},
343 {u
"RU"_qs
, tr("Russian Federation")},
344 {u
"RW"_qs
, tr("Rwanda")},
345 {u
"SA"_qs
, tr("Saudi Arabia")},
346 {u
"SB"_qs
, tr("Solomon Islands")},
347 {u
"SC"_qs
, tr("Seychelles")},
348 {u
"SD"_qs
, tr("Sudan")},
349 {u
"SE"_qs
, tr("Sweden")},
350 {u
"SG"_qs
, tr("Singapore")},
351 {u
"SH"_qs
, tr("Saint Helena, Ascension and Tristan da Cunha")},
352 {u
"SI"_qs
, tr("Slovenia")},
353 {u
"SJ"_qs
, tr("Svalbard and Jan Mayen")},
354 {u
"SK"_qs
, tr("Slovakia")},
355 {u
"SL"_qs
, tr("Sierra Leone")},
356 {u
"SM"_qs
, tr("San Marino")},
357 {u
"SN"_qs
, tr("Senegal")},
358 {u
"SO"_qs
, tr("Somalia")},
359 {u
"SR"_qs
, tr("Suriname")},
360 {u
"SS"_qs
, tr("South Sudan")},
361 {u
"ST"_qs
, tr("Sao Tome and Principe")},
362 {u
"SV"_qs
, tr("El Salvador")},
363 {u
"SX"_qs
, tr("Sint Maarten (Dutch part)")},
364 {u
"SY"_qs
, tr("Syrian Arab Republic")},
365 {u
"SZ"_qs
, tr("Swaziland")},
366 {u
"TC"_qs
, tr("Turks and Caicos Islands")},
367 {u
"TD"_qs
, tr("Chad")},
368 {u
"TF"_qs
, tr("French Southern Territories")},
369 {u
"TG"_qs
, tr("Togo")},
370 {u
"TH"_qs
, tr("Thailand")},
371 {u
"TJ"_qs
, tr("Tajikistan")},
372 {u
"TK"_qs
, tr("Tokelau")},
373 {u
"TL"_qs
, tr("Timor-Leste")},
374 {u
"TM"_qs
, tr("Turkmenistan")},
375 {u
"TN"_qs
, tr("Tunisia")},
376 {u
"TO"_qs
, tr("Tonga")},
377 {u
"TR"_qs
, tr("Turkey")},
378 {u
"TT"_qs
, tr("Trinidad and Tobago")},
379 {u
"TV"_qs
, tr("Tuvalu")},
380 {u
"TW"_qs
, tr("Taiwan")},
381 {u
"TZ"_qs
, tr("Tanzania, United Republic of")},
382 {u
"UA"_qs
, tr("Ukraine")},
383 {u
"UG"_qs
, tr("Uganda")},
384 {u
"UM"_qs
, tr("United States Minor Outlying Islands")},
385 {u
"US"_qs
, tr("United States")},
386 {u
"UY"_qs
, tr("Uruguay")},
387 {u
"UZ"_qs
, tr("Uzbekistan")},
388 {u
"VA"_qs
, tr("Holy See (Vatican City State)")},
389 {u
"VC"_qs
, tr("Saint Vincent and the Grenadines")},
390 {u
"VE"_qs
, tr("Venezuela, Bolivarian Republic of")},
391 {u
"VG"_qs
, tr("Virgin Islands, British")},
392 {u
"VI"_qs
, tr("Virgin Islands, U.S.")},
393 {u
"VN"_qs
, tr("Vietnam")},
394 {u
"VU"_qs
, tr("Vanuatu")},
395 {u
"WF"_qs
, tr("Wallis and Futuna")},
396 {u
"WS"_qs
, tr("Samoa")},
397 {u
"YE"_qs
, tr("Yemen")},
398 {u
"YT"_qs
, tr("Mayotte")},
399 {u
"ZA"_qs
, tr("South Africa")},
400 {u
"ZM"_qs
, tr("Zambia")},
401 {u
"ZW"_qs
, tr("Zimbabwe")},
406 return countries
.value(countryISOCode
, tr("N/A"));
409 void GeoIPManager::configure()
411 const bool enabled
= Preferences::instance()->resolvePeerCountries();
412 if (m_enabled
!= enabled
)
415 if (m_enabled
&& !m_geoIPDatabase
)
421 delete m_geoIPDatabase
;
422 m_geoIPDatabase
= nullptr;
427 void GeoIPManager::downloadFinished(const DownloadResult
&result
)
429 if (result
.status
!= DownloadStatus::Success
)
431 LogMsg(tr("Couldn't download IP geolocation database file. Reason: %1").arg(result
.errorString
), Log::WARNING
);
436 const QByteArray data
= Utils::Gzip::decompress(result
.data
, &ok
);
439 LogMsg(tr("Could not decompress IP geolocation database file."), Log::WARNING
);
444 GeoIPDatabase
*geoIPDatabase
= GeoIPDatabase::load(data
, error
);
447 if (!m_geoIPDatabase
|| (geoIPDatabase
->buildEpoch() > m_geoIPDatabase
->buildEpoch()))
449 delete m_geoIPDatabase
;
450 m_geoIPDatabase
= geoIPDatabase
;
451 LogMsg(tr("IP geolocation database loaded. Type: %1. Build time: %2.")
452 .arg(m_geoIPDatabase
->type(), m_geoIPDatabase
->buildEpoch().toString())
454 const Path targetPath
= specialFolderLocation(SpecialFolder::Data
) / Path(GEODB_FOLDER
);
455 if (!targetPath
.exists())
456 Utils::Fs::mkpath(targetPath
);
458 const auto path
= targetPath
/ Path(GEODB_FILENAME
);
459 const nonstd::expected
<void, QString
> result
= Utils::IO::saveToFile(path
, data
);
462 LogMsg(tr("Successfully updated IP geolocation database."), Log::INFO
);
466 LogMsg(tr("Couldn't save downloaded IP geolocation database file. Reason: %1")
467 .arg(result
.error()), Log::WARNING
);
472 delete geoIPDatabase
;
477 LogMsg(tr("Couldn't load IP geolocation database. Reason: %1").arg(error
), Log::WARNING
);