Add ipv6 geolocation table
This commit is contained in:
parent
0ef632114b
commit
9085658653
@ -183,6 +183,9 @@ The current server configuration xml looks like this:
|
||||
<!-- IP geolocation table, you only need this table if you want to geolocate IP from non-stk-addons connection, as all validated players connecting from stk-addons will provide the location info, you need to create the table first, see NETWORKING.md for details, empty to disable. This table can be shared for all servers if you use the same name. -->
|
||||
<ip-geolocation-table value="ip_mapping" />
|
||||
|
||||
<!-- IPv6 geolocation table, you only need this table if you want to geolocate IP from non-stk-addons connection, as all validated players connecting from stk-addons will provide the location info, you need to create the table first, see NETWORKING.md for details, empty to disable. This table can be shared for all servers if you use the same name. -->
|
||||
<ipv6-geolocation-table value="ipv6_mapping" />
|
||||
|
||||
<!-- If true this server will auto add / remove AI connected with network-ai=x, which will kick N - 1 bot(s) where N is the number of human players. Only use this for non-GP racing server. -->
|
||||
<ai-handling value="false" />
|
||||
|
||||
@ -341,6 +344,15 @@ CREATE TABLE ip_mapping
|
||||
longitude REAL NOT NULL, -- Longitude of this IP range
|
||||
country_code TEXT NOT NULL -- 2-letter country code
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE TABLE ipv6_mapping
|
||||
(
|
||||
ip_start INTEGER UNSIGNED NOT NULL PRIMARY KEY UNIQUE, -- IP decimal (upper 64bit) start
|
||||
ip_end INTEGER UNSIGNED NOT NULL UNIQUE, -- IP decimal (upper 64bit) end
|
||||
latitude REAL NOT NULL, -- Latitude of this IP range
|
||||
longitude REAL NOT NULL, -- Longitude of this IP range
|
||||
country_code TEXT NOT NULL -- 2-letter country code
|
||||
)
|
||||
```
|
||||
|
||||
For initialization of `ip_mapping` table, check [this script](tools/generate-ip-mappings.py).
|
||||
|
@ -63,6 +63,26 @@
|
||||
|
||||
|
||||
#ifdef ENABLE_SQLITE3
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static void upperIPv6SQL(sqlite3_context* context, int argc,
|
||||
sqlite3_value** argv)
|
||||
{
|
||||
if (argc != 1)
|
||||
{
|
||||
sqlite3_result_int64(context, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
char* ipv6 = (char*)sqlite3_value_text(argv[0]);
|
||||
if (ipv6 == NULL)
|
||||
{
|
||||
sqlite3_result_int64(context, 0);
|
||||
return;
|
||||
}
|
||||
sqlite3_result_int64(context, upperIPv6(ipv6));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void insideIPv6CIDRSQL(sqlite3_context* context, int argc,
|
||||
sqlite3_value** argv)
|
||||
@ -97,6 +117,8 @@ sqlite3_extension_init(sqlite3* db, char** pzErrMsg,
|
||||
SQLITE_EXTENSION_INIT2(pApi)
|
||||
sqlite3_create_function(db, "insideIPv6CIDR", 2, SQLITE_UTF8, NULL,
|
||||
insideIPv6CIDRSQL, NULL, NULL);
|
||||
sqlite3_create_function(db, "upperIPv6", 1, SQLITE_UTF8, 0, upperIPv6SQL,
|
||||
0, 0);
|
||||
return 0;
|
||||
} // sqlite3_extension_init
|
||||
*/
|
||||
@ -256,6 +278,7 @@ void ServerLobby::initDatabase()
|
||||
m_ipv6_ban_table_exists = false;
|
||||
m_online_id_ban_table_exists = false;
|
||||
m_ip_geolocation_table_exists = false;
|
||||
m_ipv6_geolocation_table_exists = false;
|
||||
if (!ServerConfig::m_sql_management)
|
||||
return;
|
||||
const std::string& path = ServerConfig::getConfigDirectory() + "/" +
|
||||
@ -285,6 +308,8 @@ void ServerLobby::initDatabase()
|
||||
}, NULL);
|
||||
sqlite3_create_function(m_db, "insideIPv6CIDR", 2, SQLITE_UTF8, NULL,
|
||||
&insideIPv6CIDRSQL, NULL, NULL);
|
||||
sqlite3_create_function(m_db, "upperIPv6", 1, SQLITE_UTF8, NULL,
|
||||
&upperIPv6SQL, NULL, NULL);
|
||||
checkTableExists(ServerConfig::m_ip_ban_table, m_ip_ban_table_exists);
|
||||
checkTableExists(ServerConfig::m_ipv6_ban_table, m_ipv6_ban_table_exists);
|
||||
checkTableExists(ServerConfig::m_online_id_ban_table,
|
||||
@ -293,6 +318,8 @@ void ServerLobby::initDatabase()
|
||||
m_player_reports_table_exists);
|
||||
checkTableExists(ServerConfig::m_ip_geolocation_table,
|
||||
m_ip_geolocation_table_exists);
|
||||
checkTableExists(ServerConfig::m_ipv6_geolocation_table,
|
||||
m_ipv6_geolocation_table_exists);
|
||||
#endif
|
||||
} // initDatabase
|
||||
|
||||
@ -1144,6 +1171,47 @@ std::string ServerLobby::ip2Country(const TransportAddress& addr) const
|
||||
return cc_code;
|
||||
} // ip2Country
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string ServerLobby::ipv62Country(const std::string& ipv6) const
|
||||
{
|
||||
if (!m_db || !m_ipv6_geolocation_table_exists)
|
||||
return "";
|
||||
|
||||
std::string cc_code;
|
||||
std::string query = StringUtils::insertValues(
|
||||
"SELECT country_code FROM %s "
|
||||
"WHERE `ip_start` <= upperIPv6(\"%s\") AND `ip_end` >= upperIPv6(\"%s\") "
|
||||
"ORDER BY `ip_start` DESC LIMIT 1;",
|
||||
ServerConfig::m_ipv6_geolocation_table.c_str(), ipv6.c_str(),
|
||||
ipv6.c_str());
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
|
||||
if (ret == SQLITE_OK)
|
||||
{
|
||||
ret = sqlite3_step(stmt);
|
||||
if (ret == SQLITE_ROW)
|
||||
{
|
||||
const char* country_code = (char*)sqlite3_column_text(stmt, 0);
|
||||
cc_code = country_code;
|
||||
}
|
||||
ret = sqlite3_finalize(stmt);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
Log::error("ServerLobby",
|
||||
"Error finalize database for query %s: %s",
|
||||
query.c_str(), sqlite3_errmsg(m_db));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("ServerLobby", "Error preparing database for query %s: %s",
|
||||
query.c_str(), sqlite3_errmsg(m_db));
|
||||
return "";
|
||||
}
|
||||
return cc_code;
|
||||
} // ipv62Country
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -3317,8 +3385,10 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SQLITE3
|
||||
if (country_code.empty())
|
||||
if (country_code.empty() && peer->getIPV6Address().empty())
|
||||
country_code = ip2Country(peer->getAddress());
|
||||
if (country_code.empty() && !peer->getIPV6Address().empty())
|
||||
country_code = ipv62Country(peer->getIPV6Address());
|
||||
#endif
|
||||
|
||||
auto red_blue = STKHost::get()->getAllPlayersTeamInfo();
|
||||
|
@ -91,6 +91,8 @@ private:
|
||||
|
||||
bool m_ip_geolocation_table_exists;
|
||||
|
||||
bool m_ipv6_geolocation_table_exists;
|
||||
|
||||
uint64_t m_last_poll_db_time;
|
||||
|
||||
void pollDatabase();
|
||||
@ -101,6 +103,8 @@ private:
|
||||
void checkTableExists(const std::string& table, bool& result);
|
||||
|
||||
std::string ip2Country(const TransportAddress& addr) const;
|
||||
|
||||
std::string ipv62Country(const std::string& ipv6) const;
|
||||
#endif
|
||||
void initDatabase();
|
||||
|
||||
|
@ -412,6 +412,16 @@ namespace ServerConfig
|
||||
"empty to disable. "
|
||||
"This table can be shared for all servers if you use the same name."));
|
||||
|
||||
SERVER_CFG_PREFIX StringServerConfigParam m_ipv6_geolocation_table
|
||||
SERVER_CFG_DEFAULT(StringServerConfigParam("ipv6_mapping",
|
||||
"ipv6-geolocation-table",
|
||||
"IPv6 geolocation table, you only need this table if you want to "
|
||||
"geolocate IP from non-stk-addons connection, as all validated "
|
||||
"players connecting from stk-addons will provide the location info, "
|
||||
"you need to create the table first, see NETWORKING.md for details, "
|
||||
"empty to disable. "
|
||||
"This table can be shared for all servers if you use the same name."));
|
||||
|
||||
SERVER_CFG_PREFIX BoolServerConfigParam m_ai_handling
|
||||
SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "ai-handling",
|
||||
"If true this server will auto add / remove AI connected with "
|
||||
|
@ -138,6 +138,23 @@ void andIPv6(struct in6_addr* ipv6, const struct in6_addr* mask)
|
||||
ipv6->s6_addr[i] &= mask->s6_addr[i];
|
||||
} // andIPv6
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
extern "C" int64_t upperIPv6(const char* ipv6)
|
||||
{
|
||||
struct in6_addr v6_in;
|
||||
if (inet_pton(AF_INET6, ipv6, &v6_in) != 1)
|
||||
return 0;
|
||||
uint64_t result = 0;
|
||||
unsigned shift = 56;
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
{
|
||||
uint64_t val = v6_in.s6_addr[i];
|
||||
result += val << shift;
|
||||
shift -= 8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
extern "C" int insideIPv6CIDR(const char* ipv6_cidr, const char* ipv6_in)
|
||||
{
|
||||
|
@ -29,6 +29,7 @@ void getMappedFromIPV6(const struct sockaddr_in6* in6, ENetAddress* ea);
|
||||
void addMappedAddress(const ENetAddress* ea, const struct sockaddr_in6* in6);
|
||||
int getaddrinfo_compat(const char* hostname, const char* servname,
|
||||
const struct addrinfo* hints, struct addrinfo** res);
|
||||
int64_t upperIPv6(const char* ipv6);
|
||||
int insideIPv6CIDR(const char* ipv6_cidr, const char* ipv6_in);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user