Blame apache2/msc_geo.c

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