Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //-----------------------------------------------------------------------------
- //
- // Zandronum Source
- // Copyright (C) 2012 Santeri `Dusk` Piippo
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are met:
- //
- // 1. Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- // 2. Redistributions in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- // 3. Neither the name of the Skulltag Development Team nor the names of its
- // contributors may be used to endorse or promote products derived from this
- // software without specific prior written permission.
- // 4. Redistributions in any form must be accompanied by information on how to
- // obtain complete source code for the software and any accompanying
- // software that uses the software. The source code must either be included
- // in the distribution or be available for no more than the cost of
- // distribution plus a nominal fee, and must be freely redistributable
- // under reasonable conditions. For an executable file, complete source
- // code means the source code for all modules it contains. It does not
- // include source code for modules or files that typically accompany the
- // major components of the operating system on which the executable file
- // runs.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- // POSSIBILITY OF SUCH DAMAGE.
- //
- // Filename: sv_ip2c.cpp
- //
- // Description: IP2C CSV database parsing, storing and accessing functionality.
- //
- //-----------------------------------------------------------------------------
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <string.h>
- #include <assert.h>
- #include "i_system.h"
- #include "c_cvars.h"
- #include "sv_ip2c.h"
- #include "network.h"
- #include "networkshared.h"
- #include "c_dispatch.h"
- #define MAX_ENTRIES 150000
- CUSTOM_CVAR (Bool, sv_ip2c, true, CVAR_ARCHIVE) {
- if (self)
- IP2C::LoadDB ();
- else
- IP2C::UnloadDB ();
- }
- CUSTOM_CVAR (String, sv_ip2c_dbfile, "IpToCountry.csv", CVAR_ARCHIVE) {
- // If we change location of the DB file, try
- // load the DB from the new path.
- if (sv_ip2c) {
- IP2C::UnloadDB ();
- IP2C::LoadDB ();
- }
- }
- namespace IP2C {
- typedef struct {
- ULONG minIP;
- const Country_t* country;
- } link_t;
- // IPLinks is dynamically allocated so that the database is not allocated if
- // sv_ip2c is false. The database needs over a megabyte of memory!
- static link_t* IPLinks;
- static bool IP2CReady = false;
- static const char* ErrorMsg;
- static unsigned long int entryCount = 0;
- const Country_t* Localhost = NULL;
- const Country_t* LocalNetwork = NULL;
- const Country_t* PlayerCountries[MAXPLAYERS] = {NULL};
- const Country_t CountryData[] = {
- {"ABW", "Aruba"},
- {"AFG", "Afghanistan"},
- {"AFR", "Asia"},
- {"AGO", "Angola"},
- {"AIA", "Anguilla"},
- {"ALA", "Aland Islands"},
- {"ALB", "Albania"},
- {"AND", "Andorra"},
- {"ANT", "Antilles"},
- {"ARE", "United Arab Emirates"},
- {"ARG", "Argentina"},
- {"ARM", "Armenia"},
- {"ASM", "American Samoa"},
- {"ATG", "Antigua and Barbuda"},
- {"AUS", "Australia"},
- {"AUT", "Austria"},
- {"AZE", "Azerbaijan"},
- {"BDI", "Burundi"},
- {"BEL", "Belgium"},
- {"BEN", "Benin"},
- {"BES", "Bonaire"},
- {"BFA", "Burkina Faso"},
- {"BGD", "Bangladesh"},
- {"BGR", "Bulgaria"},
- {"BHR", "Bahrain"},
- {"BHS", "Bahamas"},
- {"BIH", "Bosnia and Herzegowina"},
- {"BLR", "Belarus"},
- {"BLZ", "Belize"},
- {"BMU", "Bermuda"},
- {"BOL", "Bolivia"},
- {"BRA", "Brazil"},
- {"BRB", "Barbados"},
- {"BRN", "Brunei"},
- {"BTN", "Bhutan"},
- {"BWA", "Botswana"},
- {"CAF", "Central Africa"},
- {"CAN", "Canada"},
- {"CHE", "Switzerland"},
- {"CHL", "Chile"},
- {"CHN", "China"},
- {"CIV", "Ivory Coast"},
- {"CMR", "Cameroon"},
- {"COD", "Congo-Kinshasa"},
- {"COG", "Congo-Brazzaville"},
- {"COK", "Cook Islands"},
- {"COL", "Colombia"},
- {"COM", "Comoros"},
- {"CPV", "Cape Verde"},
- {"CRI", "Costa Rica"},
- {"CUB", "Cuba"},
- {"CUW", "Curacao"},
- {"CYM", "Cayman Islands"},
- {"CYP", "Cyprus"},
- {"CZE", "Czech Republic"},
- {"DEU", "Germany"},
- {"DJI", "Djibouti"},
- {"DMA", "Dominica"},
- {"DNK", "Denmark"},
- {"DOM", "Dominican Republic"},
- {"DZA", "Algeria"},
- {"ECU", "Ecuador"},
- {"EGY", "Egypt"},
- {"ERI", "Eritrea"},
- {"ESP", "Spain"},
- {"EST", "Estonia"},
- {"ETH", "Ethiopia"},
- {"EU" , "Europe"},
- {"FIN", "Finland"},
- {"FJI", "Fiji"},
- {"FRA", "France"},
- {"FRO", "Faroe Islands"},
- {"FSM", "Micronesia"},
- {"GAB", "Gabon"},
- {"GBR", "United Kingdom"},
- {"GEO", "Georgia"},
- {"GGY", "Guernsey"},
- {"GHA", "Ghana"},
- {"GIB", "Gibraltar"},
- {"GIN", "Guinea"},
- {"GLP", "Guadeloupe"},
- {"GMB", "Gambia"},
- {"GNB", "Guinea-Bissau"},
- {"GNQ", "Equatorial Guinea"},
- {"GRC", "Greece"},
- {"GRD", "Grenada"},
- {"GRL", "Greenland"},
- {"GTM", "Guatemala"},
- {"GUF", "French Guiana"},
- {"GUM", "Guam"},
- {"GUY", "Guyana"},
- {"HKG", "Hong Kong"},
- {"HND", "Honduras"},
- {"HRV", "Croatia"},
- {"HTI", "Haiti"},
- {"HUN", "Hungary"},
- {"IDN", "Indonesia"},
- {"IMN", "Isle of Man"},
- {"IND", "India"},
- {"IOT", "Chagos Islands"},
- {"IRL", "Ireland"},
- {"IRN", "Iran"},
- {"IRQ", "Iraq"},
- {"ISL", "Iceland"},
- {"ISR", "Israel"},
- {"ITA", "Italy"},
- {"JAM", "Jamaica"},
- {"JEY", "Jersey"},
- {"JOR", "Jordan"},
- {"JPN", "Japan"},
- {"KAZ", "Kazakhstan"},
- {"KEN", "Kenya"},
- {"KGZ", "Kyrgyzstan"},
- {"KHM", "Cambodia"},
- {"KIR", "Kiribati"},
- {"KNA", "St. Kitts and Nevis"},
- {"KOR", "South Korea"},
- {"KWT", "Kuwait"},
- {"LAN", "Local network"},
- {"LAO", "Laos"},
- {"LBN", "Lebanon"},
- {"LBR", "Liberia"},
- {"LBY", "Libya"},
- {"LCA", "St. Lucia"},
- {"LIE", "Liechtenstein"},
- {"LKA", "Sri Lanka"},
- {"LOC", "Localhost"},
- {"LSO", "Lesotho"},
- {"LTU", "Lithuania"},
- {"LUX", "Luxembourg"},
- {"LVA", "Latvia"},
- {"MAC", "Macau"},
- {"MAF", "St. Martin"},
- {"MAR", "Morocco"},
- {"MCO", "Monaco"},
- {"MDA", "Moldova"},
- {"MDG", "Madagascar"},
- {"MDV", "Maldives"},
- {"MEX", "Mexico"},
- {"MHL", "Marshall Islands"},
- {"MKD", "Macedonia"},
- {"MLI", "Mali"},
- {"MLT", "Malta"},
- {"MMR", "Burma"},
- {"MNE", "Montenegro"},
- {"MNG", "Mongolia"},
- {"MNP", "Northern Mariana Islands"},
- {"MOZ", "Mozambique"},
- {"MRT", "Mauritania"},
- {"MSR", "Montserrat"},
- {"MTQ", "Martinique"},
- {"MUS", "Mauritius"},
- {"MWI", "Malawi"},
- {"MYS", "Malaysia"},
- {"NAM", "Namibia"},
- {"NCL", "New Caledonia"},
- {"NER", "Niger"},
- {"NFK", "Norfolk Island"},
- {"NGA", "Nigeria"},
- {"NIC", "Nicaragua"},
- {"NIU", "Niue"},
- {"NLD", "Netherlands"},
- {"NOR", "Norway"},
- {"NPL", "Nepal"},
- {"NRU", "Nauru"},
- {"NZL", "New Zealand"},
- {"OMN", "Oman"},
- {"PAK", "Pakistan"},
- {"PAN", "Panama"},
- {"PER", "Peru"},
- {"PHL", "Philippines"},
- {"PLW", "Palau"},
- {"PNG", "Papua New Guinea"},
- {"POL", "Poland"},
- {"PRI", "Puerto Rico"},
- {"PRK", "North Korea"},
- {"PRT", "Portugal"},
- {"PRY", "Paraguay"},
- {"PSE", "Palestine"},
- {"PYF", "French Polynesia"},
- {"QAT", "Qatar"},
- {"REU", "Reunion"},
- {"ROM", "Romania"},
- {"RUS", "Russia"},
- {"RWA", "Rwanda"},
- {"SAU", "Saudi Arabia"},
- {"SDN", "Sudan"},
- {"SEN", "Senegal"},
- {"SGP", "Singapore"},
- {"SLB", "Solomon Islands"},
- {"SLE", "Sierra Leone"},
- {"SLV", "El Salvador"},
- {"SMR", "San Marino"},
- {"SOM", "Somalia"},
- {"SPM", "St. Pierre and Miquelon"},
- {"SRB", "Serbia"},
- {"SSD", "South Sudan"},
- {"STP", "Sao Tome and Principe"},
- {"SUR", "Suriname"},
- {"SVK", "Slovakia"},
- {"SVN", "Slovenia"},
- {"SWE", "Sweden"},
- {"SWZ", "Swaziland"},
- {"SYC", "Seychelles"},
- {"SYR", "Syria"},
- {"TCA", "Turks and Caicos Islands"},
- {"TCD", "Chad"},
- {"TGO", "Togo"},
- {"THA", "Thailand"},
- {"TJK", "Tajikistan"},
- {"TKL", "Tokelau"},
- {"TKM", "Turkmenistan"},
- {"TLS", "Timor-Leste"},
- {"TON", "Tonga"},
- {"TTO", "Trinidad and Tobago"},
- {"TUN", "Tunisia"},
- {"TUR", "Turkey"},
- {"TUV", "Tuvalu"},
- {"TWN", "Taiwan"},
- {"TZA", "Tanzania"},
- {"UGA", "Uganda"},
- {"UKR", "Ukraine"},
- {"URY", "Uruguay"},
- {"USA", "United States"},
- {"UZB", "Uzbekistan"},
- {"VAT", "Vatican City"},
- {"VCT", "St. Vincent and Grenadines"},
- {"VEN", "Venezuela"},
- {"VGB", "Virgin Islands (UK)"},
- {"VIR", "Virgin Islands (US)"},
- {"VNM", "Vietnam"},
- {"VUT", "Vanuatu"},
- {"WLF", "Wallis and Futuna"},
- {"WSM", "Samoa"},
- {"YEM", "Yemen"},
- {"ZAF", "South Africa"},
- {"ZMB", "Zambia"},
- {"ZWE", "Zimbabwe"},
- {"ZZZ", "Reserved"},
- };
- // =========================================================================
- // Find a country definition by code
- int FindCountry (char* code) {
- for (unsigned int i = 0; i < sizeof (CountryData) / sizeof (Country_t); i++)
- if (!strcmp (CountryData[i].code, code))
- return i;
- return -1;
- }
- // =========================================================================
- // Parses the CSV database and builds the IP database.
- bool LoadIPTable (const char* path) {
- FILE* fp = fopen (path, "r");
- if (!fp) {
- ErrorMsg = "Could not open IP table for reading!";
- return false;
- }
- ULONG x = 0;
- char line[256];
- // First, skim through the file to count the amount of entries;
- entryCount = 0;
- while (fgets (line, 256, fp)) {
- if (line[0] == '#' || line[0] == '\n')
- continue;
- entryCount++;
- }
- // Rewind back to start of file
- fseek (fp, 0, SEEK_SET);
- // Allocate the table
- IPLinks = new link_t[entryCount];
- unsigned def = 0;
- while (fgets (line, 256, fp)) {
- // Ignore comments
- if (line[0] == '#' || line[0] == '\n')
- continue;
- // This shouldn't be happening but I'm still paranoid
- if (x >= entryCount) {
- Printf ("\\cKIP2C: Warning: Could not fit the entire IP2C database to memory!\n");
- break;
- }
- int i = 1;
- IPLinks[x].minIP = atoi (line + i);
- // Skip past unneeded junk
- for (int j = 0; j < 5; j++) {
- do
- i++;
- while (*(line + i) != '"');
- i += 3;
- }
- // Read the country code
- char countrycode[4];
- strncpy (countrycode, line + i, 3);
- // Add the null terminator, assuming there's no one-character
- // country codes.
- if (countrycode[2] == '"') {
- // 2-character code
- countrycode[2] = '\0';
- i += 5;
- } else {
- // 3-character code
- countrycode[3] = '\0';
- i += 6;
- }
- // Find the country for this code
- int ci = FindCountry (countrycode);
- if (ci == -1) {
- Printf ("IP2C: Couldn't find country definition for `%s`!\n", countrycode);
- IPLinks[x].country = NULL;
- } else {
- IPLinks[x].country = &CountryData[ci];
- }
- x++;
- }
- // Mark a NULL entry to sign the end of list.
- IPLinks[x].country = NULL;
- return true;
- }
- // =========================================================================
- // Gets the country data of a given IP.
- const Country_t* GetCountry (ULONG ip) {
- if (!IP2CReady)
- return NULL;
- // Localhost
- if (ip == 0x7F000001)
- return Localhost;
- // Local network
- if (ip >= 0xC0A80000 && ip <= 0xC0A8FFFF)
- return LocalNetwork;
- link_t* IPLink = NULL;
- for (int i = 0; i < MAX_ENTRIES; i++) {
- if (!IPLinks[i].country)
- break;
- if (ip > IPLinks[i].minIP)
- continue;
- return IPLinks[i - 1].country;
- }
- return NULL;
- }
- // =========================================================================
- // Variant that can handle the Zandronum IP type.
- const Country_t* GetCountry (NETADDRESS_s ip) {
- ULONG ulIP = (ip.abIP[0] * 0x1000000) + (ip.abIP[1] * 0x10000) + (ip.abIP[2] * 0x100) + ip.abIP[3];
- return GetCountry (ulIP);
- }
- // =========================================================================
- // Get a country by index
- const Country_t* GetCountryByIndex (int id) {
- if (id < 0 || id >= (int)(sizeof (CountryData) / sizeof (CountryData[0])))
- return NULL;
- return &CountryData[id];
- }
- const Country_t* GetCountryByName (char* countryName) {
- for (int i = 0; i < (int)(sizeof (CountryData) / sizeof (CountryData[0])); i++)
- if (!strcmp (CountryData[i].name, countryName))
- return &CountryData[i];
- return NULL;
- }
- const Country_t* GetCountryByCode (char* countryCode) {
- for (int i = 0; i < (int)(sizeof (CountryData) / sizeof (CountryData[0])); i++)
- if (!strcmp (CountryData[i].code, countryCode))
- return &CountryData[i];
- return NULL;
- }
- // =========================================================================
- // Get an index by country
- long GetCountryIndex (const Country_t* country) {
- if (!country)
- return -1;
- return country - CountryData;
- }
- // =========================================================================
- // Does the necessary procedures to ready the IP2C database.
- void Initiate () {
- // Only the server needs the IP2C database.
- if (NETWORK_GetState() != NETSTATE_SERVER || !sv_ip2c)
- return;
- // If there ever are more than 255 countries, the networking needs to be
- // updated to send a short for the country data. This is an alarm for that.
- assert (sizeof (CountryData) / sizeof (CountryData[0]) <= 255);
- // load the actual database.
- LoadDB ();
- // Locate the LAN and localhost entries in the country table.
- for (unsigned int i = 0; i < sizeof (CountryData) / sizeof (CountryData[0]); i++) {
- if (!strcmp (CountryData[i].code, "LAN"))
- LocalNetwork = &CountryData[i];
- else if (!strcmp (CountryData[i].code, "LOC"))
- Localhost = &CountryData[i];
- }
- atterm (IP2C::Destroy);
- }
- void UnloadDB () {
- if (!IP2CReady)
- return;
- delete[] IPLinks;
- IP2CReady = false;
- IPLinks = NULL;
- Printf ("IP2C: IP-to-country database unloaded.\n");
- }
- void LoadDB () {
- if (IP2CReady)
- return;
- if (!LoadIPTable (sv_ip2c_dbfile)) {
- Printf ("IP2C: Failed to load the IP2C database!\n");
- return;
- }
- Printf ("IP2C: IP-to-country database loaded.\n");
- IP2CReady = true;
- }
- void Destroy () {
- delete[] IPLinks;
- }
- // =========================================================================
- // Access function for IP2CReady
- bool IsReady () {
- return IP2CReady;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment