TrinityCore
Loading...
Searching...
No Matches
IPLocation.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "IPLocation.h"
19#include "BigNumber.h"
20#include "Config.h"
21#include "Errors.h"
22#include "IpAddress.h"
23#include "Log.h"
24#include "Util.h"
25#include <algorithm>
26#include <fstream>
27
30
32{
33 _ipLocationStore.clear();
34 TC_LOG_INFO("server.loading", "Loading IP Location Database...");
35
36 std::string databaseFilePath = sConfigMgr->GetStringDefault("IPLocationFile", "");
37 if (databaseFilePath.empty())
38 return;
39
40 // Check if file exists
41 std::ifstream databaseFile(databaseFilePath);
42 if (!databaseFile)
43 {
44 TC_LOG_ERROR("server.loading", "IPLocation: No ip database file exists ({}).", databaseFilePath);
45 return;
46 }
47
48 if (!databaseFile.is_open())
49 {
50 TC_LOG_ERROR("server.loading", "IPLocation: Ip database file ({}) can not be opened.", databaseFilePath);
51 return;
52 }
53
54 std::string ipFrom;
55 std::string ipTo;
56 std::string countryCode;
57 std::string countryName;
58 BigNumber bnParser;
59 BigNumber ipv4Max(0xFFFFFFFF);
60 BigNumber ipv6MappedMask(0xFFFF);
61 ipv6MappedMask <<= 32;
62
63 auto parseStringToIPv6 = [&](std::string const& str) -> Optional<std::array<uint8, 16>>
64 {
65 bnParser.SetDecStr(str);
66 if (!bnParser.SetDecStr(str))
67 return {};
68 // convert ipv4 to ipv6 v4 mapped value
69 if (bnParser <= ipv4Max)
70 bnParser += ipv6MappedMask;
71 return bnParser.ToByteArray<16>(false);
72 };
73
74 while (databaseFile.good())
75 {
76 // Read lines
77 if (!std::getline(databaseFile, ipFrom, ','))
78 break;
79 if (!std::getline(databaseFile, ipTo, ','))
80 break;
81 if (!std::getline(databaseFile, countryCode, ','))
82 break;
83 if (!std::getline(databaseFile, countryName, '\n'))
84 break;
85
86 // Remove new lines and return
87 std::erase_if(countryName, [](char c) { return c == '\r' || c == '\n'; });
88
89 // Remove quotation marks
90 std::erase(ipFrom, '"');
91 std::erase(ipTo, '"');
92 std::erase(countryCode, '"');
93 std::erase(countryName, '"');
94
95 if (countryCode == "-")
96 continue;
97
98 // Convert country code to lowercase
99 strToLower(countryCode);
100
101 Optional<std::array<uint8, 16>> from = parseStringToIPv6(ipFrom);
102 if (!from)
103 continue;
104
105 Optional<std::array<uint8, 16>> to = parseStringToIPv6(ipTo);
106 if (!to)
107 continue;
108
109 _ipLocationStore.emplace_back(*from, *to, std::move(countryCode), std::move(countryName));
110 }
111
112 std::ranges::sort(_ipLocationStore, {}, &IpLocationRecord::IpFrom);
113 ASSERT(std::ranges::is_sorted(_ipLocationStore, [](IpLocationRecord const& a, IpLocationRecord const& b) { return a.IpFrom < b.IpTo; }),
114 "Overlapping IP ranges detected in database file");
115
116 databaseFile.close();
117
118 TC_LOG_INFO("server.loading", ">> Loaded {} ip location entries.", _ipLocationStore.size());
119}
120
121IpLocationRecord const* IpLocationStore::GetLocationRecord(std::string const& ipAddress) const
122{
123 boost::system::error_code error;
124 boost::asio::ip::address address = Trinity::Net::make_address(ipAddress, error);
125 if (error)
126 return nullptr;
127
128 std::array<uint8, 16> bytes = [&]() -> std::array<uint8, 16>
129 {
130 if (address.is_v6())
131 return address.to_v6().to_bytes();
132 if (address.is_v4())
133 return Trinity::Net::make_address_v6(Trinity::Net::v4_mapped, address.to_v4()).to_bytes();
134 return {};
135 }();
136 auto itr = std::ranges::upper_bound(_ipLocationStore, bytes, {}, &IpLocationRecord::IpTo);
137 if (itr == _ipLocationStore.end())
138 return nullptr;
139
140 if (bytes < itr->IpFrom)
141 return nullptr;
142
143 return &(*itr);
144}
145
147{
148 static IpLocationStore instance;
149 return &instance;
150}
#define sConfigMgr
Definition Config.h:64
#define ASSERT
Definition Errors.h:80
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
void strToLower(std::string &str)
Definition Util.cpp:435
std::array< uint8, Size > ToByteArray(bool littleEndian=true) const
Definition BigNumber.h:134
bool SetDecStr(char const *str)
Definition BigNumber.cpp:64
IpLocationRecord const * GetLocationRecord(std::string const &ipAddress) const
static IpLocationStore * Instance()
std::vector< IpLocationRecord > _ipLocationStore
Definition IPLocation.h:53
std::array< uint8, 16 > IpFrom
Definition IPLocation.h:32
std::array< uint8, 16 > IpTo
Definition IPLocation.h:33