|
Packit |
284210 |
/*
|
|
Packit |
284210 |
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
|
Packit |
284210 |
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* You may not use this file except in compliance with
|
|
Packit |
284210 |
* the License. You may obtain a copy of the License at
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
284210 |
*
|
|
Packit |
284210 |
* If any of the files related to licensing are missing or if you have any
|
|
Packit |
284210 |
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
|
Packit |
284210 |
* directly using the email address security@modsecurity.org.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#include "msc_geo.h"
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* -- Lookup Tables -- */
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static const char geo_country_code[GEO_COUNTRY_LAST + 1][4] = {
|
|
Packit |
284210 |
"--",
|
|
Packit |
284210 |
"AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
|
|
Packit |
284210 |
"AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
|
|
Packit |
284210 |
"BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
|
|
Packit |
284210 |
"BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
|
|
Packit |
284210 |
"CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
|
|
Packit |
284210 |
"CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
|
|
Packit |
284210 |
"DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
|
|
Packit |
284210 |
"FK","FM","FO","FR","FX","GA","GB","GD","GE","GF",
|
|
Packit |
284210 |
"GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
|
|
Packit |
284210 |
"GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
|
|
Packit |
284210 |
"IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
|
|
Packit |
284210 |
"JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
|
|
Packit |
284210 |
"KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
|
|
Packit |
284210 |
"LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
|
|
Packit |
284210 |
"MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
|
|
Packit |
284210 |
"MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
|
|
Packit |
284210 |
"NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
|
|
Packit |
284210 |
"PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
|
|
Packit |
284210 |
"PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
|
|
Packit |
284210 |
"SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
|
|
Packit |
284210 |
"SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
|
|
Packit |
284210 |
"TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
|
|
Packit |
284210 |
"TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
|
|
Packit |
284210 |
"VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
|
|
Packit |
284210 |
"ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE"
|
|
Packit |
284210 |
};
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static const char geo_country_code3[GEO_COUNTRY_LAST + 1][4] = {
|
|
Packit |
284210 |
"--",
|
|
Packit |
284210 |
"AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT",
|
|
Packit |
284210 |
"AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
|
|
Packit |
284210 |
"BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
|
|
Packit |
284210 |
"BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD",
|
|
Packit |
284210 |
"CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
|
|
Packit |
284210 |
"CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
|
|
Packit |
284210 |
"DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
|
|
Packit |
284210 |
"FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF",
|
|
Packit |
284210 |
"GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM",
|
|
Packit |
284210 |
"GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN",
|
|
Packit |
284210 |
"IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR",
|
|
Packit |
284210 |
"JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
|
|
Packit |
284210 |
"CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
|
|
Packit |
284210 |
"LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
|
|
Packit |
284210 |
"MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
|
|
Packit |
284210 |
"MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
|
|
Packit |
284210 |
"NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
|
|
Packit |
284210 |
"PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
|
|
Packit |
284210 |
"PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
|
|
Packit |
284210 |
"SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
|
|
Packit |
284210 |
"SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA",
|
|
Packit |
284210 |
"TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
|
|
Packit |
284210 |
"TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN",
|
|
Packit |
284210 |
"VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF",
|
|
Packit |
284210 |
"ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY"
|
|
Packit |
284210 |
};
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static const char *const geo_country_name[GEO_COUNTRY_LAST + 1] = {
|
|
Packit |
284210 |
"N/A",
|
|
Packit |
284210 |
"Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles",
|
|
Packit |
284210 |
"Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
|
|
Packit |
284210 |
"Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
|
|
Packit |
284210 |
"Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
|
|
Packit |
284210 |
"Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
|
|
Packit |
284210 |
"Cuba","Cape Verde","Christmas Island","Cyprus","Czechia","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
|
|
Packit |
284210 |
"Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
|
|
Packit |
284210 |
"Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
|
|
Packit |
284210 |
"Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
|
|
Packit |
284210 |
"Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
|
|
Packit |
284210 |
"Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
|
|
Packit |
284210 |
"Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
|
|
Packit |
284210 |
"Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
|
|
Packit |
284210 |
"Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
|
|
Packit |
284210 |
"Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
|
|
Packit |
284210 |
"Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
|
|
Packit |
284210 |
"Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
|
|
Packit |
284210 |
"Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
|
|
Packit |
284210 |
"Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
|
|
Packit |
284210 |
"Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
|
|
Packit |
284210 |
"Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
|
|
Packit |
284210 |
"Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
|
|
Packit |
284210 |
"Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela",
|
|
Packit |
284210 |
"Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
|
|
Packit |
284210 |
"Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey"
|
|
Packit |
284210 |
};
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static const char geo_country_continent[GEO_COUNTRY_LAST + 1][4] = {
|
|
Packit |
284210 |
"--",
|
|
Packit |
284210 |
"AS","EU","EU","AS","AS","SA","SA","EU","AS","SA",
|
|
Packit |
284210 |
"AF","AN","SA","OC","EU","OC","SA","AS","EU","SA",
|
|
Packit |
284210 |
"AS","EU","AF","EU","AS","AF","AF","SA","AS","SA",
|
|
Packit |
284210 |
"SA","SA","AS","AF","AF","EU","SA","NA","AS","AF",
|
|
Packit |
284210 |
"AF","AF","EU","AF","OC","SA","AF","AS","SA","SA",
|
|
Packit |
284210 |
"SA","AF","AS","AS","EU","EU","AF","EU","SA","SA",
|
|
Packit |
284210 |
"AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
|
|
Packit |
284210 |
"SA","OC","EU","EU","EU","AF","EU","SA","AS","SA",
|
|
Packit |
284210 |
"AF","EU","SA","AF","AF","SA","AF","EU","SA","SA",
|
|
Packit |
284210 |
"OC","AF","SA","AS","AF","SA","EU","SA","EU","AS",
|
|
Packit |
284210 |
"EU","AS","AS","AS","AS","AS","EU","EU","SA","AS",
|
|
Packit |
284210 |
"AS","AF","AS","AS","OC","AF","SA","AS","AS","AS",
|
|
Packit |
284210 |
"SA","AS","AS","AS","SA","EU","AS","AF","AF","EU",
|
|
Packit |
284210 |
"EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
|
|
Packit |
284210 |
"AS","AS","AS","OC","SA","AF","SA","EU","AF","AS",
|
|
Packit |
284210 |
"AF","NA","AS","AF","AF","OC","AF","OC","AF","SA",
|
|
Packit |
284210 |
"EU","EU","AS","OC","OC","OC","AS","SA","SA","OC",
|
|
Packit |
284210 |
"OC","AS","AS","EU","SA","OC","SA","AS","EU","OC",
|
|
Packit |
284210 |
"SA","AS","AF","EU","AS","AF","AS","OC","AF","AF",
|
|
Packit |
284210 |
"EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
|
|
Packit |
284210 |
"SA","AF","SA","AS","AF","SA","AF","AF","AF","AS",
|
|
Packit |
284210 |
"AS","OC","AS","AF","OC","AS","AS","SA","OC","AS",
|
|
Packit |
284210 |
"AF","EU","AF","OC","NA","SA","AS","EU","SA","SA",
|
|
Packit |
284210 |
"SA","SA","AS","OC","OC","OC","AS","AF","EU","AF",
|
|
Packit |
284210 |
"AF","EU","AF","--","--","--","EU","EU","EU","EU"
|
|
Packit |
284210 |
};
|
|
Packit |
284210 |
|
|
Packit |
284210 |
typedef enum {
|
|
Packit |
284210 |
GEOIP_COUNTRY_EDITION = 1,
|
|
Packit |
284210 |
GEOIP_REGION_EDITION_REV0 = 7,
|
|
Packit |
284210 |
GEOIP_CITY_EDITION_REV0 = 6,
|
|
Packit |
284210 |
GEOIP_ORG_EDITION = 5,
|
|
Packit |
284210 |
GEOIP_ISP_EDITION = 4,
|
|
Packit |
284210 |
GEOIP_CITY_EDITION_REV1 = 2,
|
|
Packit |
284210 |
GEOIP_REGION_EDITION_REV1 = 3,
|
|
Packit |
284210 |
GEOIP_PROXY_EDITION = 8,
|
|
Packit |
284210 |
GEOIP_ASNUM_EDITION = 9,
|
|
Packit |
284210 |
GEOIP_NETSPEED_EDITION = 10,
|
|
Packit |
284210 |
GEOIP_DOMAIN_EDITION = 11
|
|
Packit |
284210 |
} GeoIPDBTypes;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static void create_segments(geo_db *geo) {
|
|
Packit |
284210 |
int i, j;
|
|
Packit |
284210 |
unsigned char delim[3];
|
|
Packit |
284210 |
unsigned char buf[GEO_SEGMENT_RECORD_LENGTH];
|
|
Packit |
284210 |
apr_size_t nbytes;
|
|
Packit |
284210 |
apr_off_t offset;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
geo->ctry_offset = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
geo->dbtype = GEOIP_COUNTRY_EDITION;
|
|
Packit |
284210 |
offset = -3l;
|
|
Packit |
284210 |
apr_file_seek(geo->db, APR_END, &offset);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (i = 0; i < GEO_STRUCT_INFO_MAX_SIZE; i++) {
|
|
Packit |
284210 |
|
|
Packit |
284210 |
apr_file_read_full(geo->db, &delim, 3, &nbytes);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (delim[0] == 255 && delim[1] == 255 && delim[2] == 255) {
|
|
Packit |
284210 |
apr_file_read_full(geo->db, &geo->dbtype, 1, &nbytes);
|
|
Packit |
284210 |
if (geo->dbtype >= 106) {
|
|
Packit |
284210 |
geo->dbtype -= 105;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (geo->dbtype == GEOIP_REGION_EDITION_REV0) {
|
|
Packit |
284210 |
geo->ctry_offset = GEO_STATE_BEGIN_REV0;
|
|
Packit |
284210 |
} else if (geo->dbtype == GEOIP_REGION_EDITION_REV1) {
|
|
Packit |
284210 |
geo->ctry_offset = GEO_STATE_BEGIN_REV1;
|
|
Packit |
284210 |
} else if (geo->dbtype == GEOIP_CITY_EDITION_REV0 ||
|
|
Packit |
284210 |
geo->dbtype == GEOIP_CITY_EDITION_REV1 ||
|
|
Packit |
284210 |
geo->dbtype == GEOIP_ORG_EDITION ||
|
|
Packit |
284210 |
geo->dbtype == GEOIP_ISP_EDITION ||
|
|
Packit |
284210 |
geo->dbtype == GEOIP_ASNUM_EDITION) {
|
|
Packit |
284210 |
geo->ctry_offset = 0;
|
|
Packit |
284210 |
apr_file_read_full(geo->db, &buf, GEO_SEGMENT_RECORD_LENGTH, &nbytes);
|
|
Packit |
284210 |
for (j = 0; j < GEO_SEGMENT_RECORD_LENGTH; j++) {
|
|
Packit |
284210 |
geo->ctry_offset += (buf[j] << (j * 8));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
} else {
|
|
Packit |
284210 |
offset = -4l;
|
|
Packit |
284210 |
apr_file_seek(geo->db, APR_CUR, &offset);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
if (geo->dbtype == GEOIP_COUNTRY_EDITION ||
|
|
Packit |
284210 |
geo->dbtype == GEOIP_PROXY_EDITION ||
|
|
Packit |
284210 |
geo->dbtype == GEOIP_NETSPEED_EDITION) {
|
|
Packit |
284210 |
geo->ctry_offset = GEO_COUNTRY_BEGIN;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static int db_open(directory_config *dcfg, char **error_msg)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
char errstr[1024];
|
|
Packit |
284210 |
apr_pool_t *mp = dcfg->mp;
|
|
Packit |
284210 |
geo_db *geo = dcfg->geo;
|
|
Packit |
284210 |
apr_status_t rc;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
#ifdef DEBUG_CONF
|
|
Packit |
284210 |
fprintf(stderr, "GEO: Initializing geo DB \"%s\".\n", geo->dbfn);
|
|
Packit |
284210 |
#endif
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((rc = apr_file_open(&geo->db, geo->dbfn, APR_READ, APR_OS_DEFAULT, mp)) != APR_SUCCESS) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(mp, "Could not open geo database \"%s\": %s", geo->dbfn, apr_strerror(rc, errstr, 1024));
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
create_segments(geo);
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
static int field_length(const char *field, int maxlen)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
int i;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (field == NULL) {
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (i = 0; i < maxlen; i++) {
|
|
Packit |
284210 |
if (field[i] == '\0') {
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return i;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Initialise Geo data structure
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int geo_init(directory_config *dcfg, const char *dbfn, char **error_msg)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
*error_msg = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if ((dcfg->geo == NULL) || (dcfg->geo == NOT_SET_P)) {
|
|
Packit |
284210 |
dcfg->geo = apr_pcalloc(dcfg->mp, sizeof(geo_db));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
dcfg->geo->db = NULL;
|
|
Packit |
284210 |
dcfg->geo->dbfn = apr_pstrdup(dcfg->mp, dbfn);
|
|
Packit |
284210 |
dcfg->geo->dbtype = 0;
|
|
Packit |
284210 |
dcfg->geo->ctry_offset = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return db_open(dcfg, error_msg);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/**
|
|
Packit |
284210 |
* Perform geographical lookup on target.
|
|
Packit |
284210 |
*/
|
|
Packit |
284210 |
int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **error_msg)
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
apr_sockaddr_t *addr;
|
|
Packit |
284210 |
long ipnum = 0;
|
|
Packit |
284210 |
char *targetip = NULL;
|
|
Packit |
284210 |
geo_db *geo = msr->txcfg->geo;
|
|
Packit |
284210 |
char errstr[1024];
|
|
Packit |
284210 |
unsigned char buf[2* GEO_MAX_RECORD_LEN];
|
|
Packit |
284210 |
const int reclen = 3; /* Algorithm needs changed if this changes */
|
|
Packit |
284210 |
apr_size_t nbytes;
|
|
Packit |
284210 |
unsigned int rec_val = 0;
|
|
Packit |
284210 |
apr_off_t seekto = 0;
|
|
Packit |
284210 |
apr_status_t ret;
|
|
Packit |
284210 |
int rc;
|
|
Packit |
284210 |
int country = 0;
|
|
Packit |
284210 |
int level;
|
|
Packit |
284210 |
double dtmp;
|
|
Packit |
284210 |
int itmp;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*error_msg = NULL;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* init */
|
|
Packit |
284210 |
georec->country_code = geo_country_code[0];
|
|
Packit |
284210 |
georec->country_code3 = geo_country_code3[0];
|
|
Packit |
284210 |
georec->country_name = geo_country_name[0];
|
|
Packit |
284210 |
georec->country_continent = geo_country_continent[0];
|
|
Packit |
284210 |
georec->region = "";
|
|
Packit |
284210 |
georec->city = "";
|
|
Packit |
284210 |
georec->postal_code = "";
|
|
Packit |
284210 |
georec->latitude = 0;
|
|
Packit |
284210 |
georec->longitude = 0;
|
|
Packit |
284210 |
georec->dma_code = 0;
|
|
Packit |
284210 |
georec->area_code = 0;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: Looking up \"%s\".", log_escape(msr->mp, target));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* NOTE: This only works with ipv4 */
|
|
Packit |
284210 |
if ((rc = apr_sockaddr_info_get(&addr, target, APR_INET, 0, 0, msr->mp)) != APR_SUCCESS) {
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024));
|
|
Packit |
284210 |
msr_log(msr, 4, "%s", *error_msg);
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
if ((rc = apr_sockaddr_ip_get(&targetip, addr)) != APR_SUCCESS) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024));
|
|
Packit |
284210 |
msr_log(msr, 4, "%s", *error_msg);
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
};
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Why is this in host byte order? */
|
|
Packit |
284210 |
ipnum = ntohl(addr->sa.sin.sin_addr.s_addr);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08lx). %lu", targetip, ipnum, ipnum);
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
ret = apr_global_mutex_lock(msr->modsecurity->geo_lock);
|
|
Packit |
284210 |
if (ret != APR_SUCCESS) {
|
|
Packit |
284210 |
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
|
Packit |
284210 |
get_apr_error(msr->mp, ret));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
for (level = 31; level >= 0; level--) {
|
|
Packit |
284210 |
/* Read the record */
|
|
Packit |
284210 |
seekto = 2 * reclen * rec_val;
|
|
Packit |
284210 |
apr_file_seek(geo->db, APR_SET, &seekto);
|
|
Packit |
284210 |
/* TODO: check rc */
|
|
Packit |
284210 |
rc = apr_file_read_full(geo->db, &buf, (2 * reclen), &nbytes);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* NOTE: This is hard-coded for size 3 records */
|
|
Packit |
284210 |
/* Left */
|
|
Packit |
284210 |
if ((ipnum & (1 << level)) == 0) {
|
|
Packit |
284210 |
rec_val = (buf[3*0 + 0] << (0*8)) +
|
|
Packit |
284210 |
(buf[3*0 + 1] << (1*8)) +
|
|
Packit |
284210 |
(buf[3*0 + 2] << (2*8));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
/* Right */
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
rec_val = (buf[3*1 + 0] << (0*8)) +
|
|
Packit |
284210 |
(buf[3*1 + 1] << (1*8)) +
|
|
Packit |
284210 |
(buf[3*1 + 2] << (2*8));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* If we are past the country offset, then we are done */
|
|
Packit |
284210 |
if (rec_val >= geo->ctry_offset) {
|
|
Packit |
284210 |
break;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (rec_val == geo->ctry_offset) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\").", log_escape(msr->mp, target));
|
|
Packit |
284210 |
msr_log(msr, 4, "%s", *error_msg);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock);
|
|
Packit |
284210 |
if (ret != APR_SUCCESS) {
|
|
Packit |
284210 |
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
|
Packit |
284210 |
get_apr_error(msr->mp, ret));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
if (geo->dbtype == GEO_COUNTRY_DATABASE) {
|
|
Packit |
284210 |
country = rec_val;
|
|
Packit |
284210 |
country -= geo->ctry_offset;
|
|
Packit |
284210 |
if ((country <= 0) || (country > GEO_COUNTRY_LAST)) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\" (country %d).", log_escape(msr->mp, target), country);
|
|
Packit |
284210 |
msr_log(msr, 4, "%s", *error_msg);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock);
|
|
Packit |
284210 |
if (ret != APR_SUCCESS) {
|
|
Packit |
284210 |
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
|
Packit |
284210 |
get_apr_error(msr->mp, ret));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Country */
|
|
Packit |
284210 |
georec->country_code = geo_country_code[country];
|
|
Packit |
284210 |
georec->country_code3 = geo_country_code3[country];
|
|
Packit |
284210 |
georec->country_name = geo_country_name[country];
|
|
Packit |
284210 |
georec->country_continent = geo_country_continent[country];
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
else {
|
|
Packit |
284210 |
int field_len = 0;
|
|
Packit |
284210 |
int rec_offset = 0;
|
|
Packit |
284210 |
int remaining = GEO_CITY_RECORD_LEN;
|
|
Packit |
284210 |
unsigned char cbuf[GEO_CITY_RECORD_LEN];
|
|
Packit |
284210 |
|
|
Packit |
284210 |
seekto = rec_val + (2 * reclen - 1) * geo->ctry_offset;
|
|
Packit |
284210 |
apr_file_seek(geo->db, APR_SET, &seekto);
|
|
Packit |
284210 |
/* TODO: check rc */
|
|
Packit |
284210 |
rc = apr_file_read_full(geo->db, &cbuf, sizeof(cbuf), &nbytes);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
country = cbuf[0];
|
|
Packit |
284210 |
if ((country <= 0) || (country > GEO_COUNTRY_LAST)) {
|
|
Packit |
284210 |
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\" (country %d).", log_escape(msr->mp, target), country);
|
|
Packit |
284210 |
msr_log(msr, 4, "%s", *error_msg);
|
|
Packit |
284210 |
|
|
Packit |
284210 |
ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock);
|
|
Packit |
284210 |
if (ret != APR_SUCCESS) {
|
|
Packit |
284210 |
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
|
Packit |
284210 |
get_apr_error(msr->mp, ret));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 0;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Country */
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
georec->country_code = geo_country_code[country];
|
|
Packit |
284210 |
georec->country_code3 = geo_country_code3[country];
|
|
Packit |
284210 |
georec->country_name = geo_country_name[country];
|
|
Packit |
284210 |
georec->country_continent = geo_country_continent[country];
|
|
Packit |
284210 |
rec_offset++;
|
|
Packit |
284210 |
remaining -= rec_offset;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Region */
|
|
Packit |
284210 |
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: region=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
georec->region = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
|
Packit |
284210 |
rec_offset += field_len + 1;
|
|
Packit |
284210 |
remaining -= field_len + 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* City */
|
|
Packit |
284210 |
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: city=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
georec->city = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
|
Packit |
284210 |
rec_offset += field_len + 1;
|
|
Packit |
284210 |
remaining -= field_len + 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Postal Code */
|
|
Packit |
284210 |
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: postal_code=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
georec->postal_code = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
|
Packit |
284210 |
rec_offset += field_len + 1;
|
|
Packit |
284210 |
remaining -= field_len + 1;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Latitude */
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: latitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
dtmp = cbuf[rec_offset] +
|
|
Packit |
284210 |
(cbuf[rec_offset+1] << 8) +
|
|
Packit |
284210 |
(cbuf[rec_offset+2] << 16);
|
|
Packit |
284210 |
georec->latitude = dtmp/10000 - 180;
|
|
Packit |
284210 |
rec_offset += 3;
|
|
Packit |
284210 |
remaining -= 3;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* Longitude */
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: longitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
dtmp = cbuf[rec_offset] +
|
|
Packit |
284210 |
(cbuf[rec_offset+1] << 8) +
|
|
Packit |
284210 |
(cbuf[rec_offset+2] << 16);
|
|
Packit |
284210 |
georec->longitude = dtmp/10000 - 180;
|
|
Packit |
284210 |
rec_offset += 3;
|
|
Packit |
284210 |
remaining -= 3;
|
|
Packit |
284210 |
|
|
Packit |
284210 |
/* dma/area codes are in city rev1 and US only */
|
|
Packit |
284210 |
if (msr->txcfg->debuglog_level >= 9) {
|
|
Packit |
284210 |
msr_log(msr, 9, "GEO: dma/area=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
if (geo->dbtype == GEO_CITY_DATABASE_1
|
|
Packit |
284210 |
&& georec->country_code[0] == 'U'
|
|
Packit |
284210 |
&& georec->country_code[1] == 'S')
|
|
Packit |
284210 |
{
|
|
Packit |
284210 |
/* DMA Code */
|
|
Packit |
284210 |
itmp = cbuf[rec_offset] +
|
|
Packit |
284210 |
(cbuf[rec_offset+1] << 8) +
|
|
Packit |
284210 |
(cbuf[rec_offset+2] << 16);
|
|
Packit |
284210 |
georec->dma_code = itmp / 1000;
|
|
Packit |
284210 |
georec->area_code = itmp % 1000;
|
|
Packit |
284210 |
rec_offset += 6;
|
|
Packit |
284210 |
remaining -= 6;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
*error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" succeeded.", log_escape(msr->mp, target));
|
|
Packit |
284210 |
|
|
Packit |
284210 |
ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock);
|
|
Packit |
284210 |
if (ret != APR_SUCCESS) {
|
|
Packit |
284210 |
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
|
Packit |
284210 |
get_apr_error(msr->mp, ret));
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
return 1;
|
|
Packit |
284210 |
}
|
|
Packit |
284210 |
|
|
Packit |
284210 |
|