mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 21:36:00 +03:00
Add geo lookup support. See #22.
This commit is contained in:
parent
d8abb48ad9
commit
a68eb04884
3
CHANGES
3
CHANGES
@ -2,6 +2,9 @@
|
||||
?? ??? 2007 - 2.2.0-trunk
|
||||
-------------------------
|
||||
|
||||
* Add SecGeoLookupsDb, @geoLookups and GEO collection to support
|
||||
geographical lookups by IP/host.
|
||||
|
||||
* Do not try to intercept a request after a failed rule. This fixes the
|
||||
issue associated with an "Internal Error: Asked to intercept request
|
||||
but was_intercepted is zero" error message.
|
||||
|
@ -23,7 +23,8 @@ LIBS = $(BASE)\lib\libhttpd.lib $(BASE)\lib\libapr.lib $(BASE)\lib\libaprutil.li
|
||||
OBJS = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \
|
||||
re.obj re_operators.obj re_actions.obj re_tfns.obj re_variables.obj \
|
||||
msc_logging.obj msc_xml.obj msc_multipart.obj modsecurity.obj msc_parsers.obj \
|
||||
msc_util.obj msc_pcre.obj persist_dbm.obj msc_reqbody.obj pdf_protec.obj
|
||||
msc_util.obj msc_pcre.obj persist_dbm.obj msc_reqbody.obj pdf_protect.obj \
|
||||
msc_geo.obj
|
||||
|
||||
all: $(DLL)
|
||||
|
||||
|
@ -91,6 +91,9 @@ void *create_directory_config(apr_pool_t *mp, char *path) {
|
||||
dcfg->pdfp_token_name = NOT_SET_P;
|
||||
dcfg->pdfp_only_get = NOT_SET;
|
||||
|
||||
/* Geo Lookups */
|
||||
dcfg->geo = NOT_SET_P;
|
||||
|
||||
return dcfg;
|
||||
}
|
||||
|
||||
@ -382,6 +385,10 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) {
|
||||
merged->pdfp_only_get = (child->pdfp_only_get == NOT_SET
|
||||
? parent->pdfp_only_get : child->pdfp_only_get);
|
||||
|
||||
/* Geo Lookup */
|
||||
merged->geo = (child->geo == NOT_SET_P
|
||||
? parent->geo : child->geo);
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
@ -450,6 +457,9 @@ void init_directory_config(directory_config *dcfg) {
|
||||
if (dcfg->pdfp_timeout == NOT_SET) dcfg->pdfp_timeout = 10;
|
||||
if (dcfg->pdfp_token_name == NOT_SET_P) dcfg->pdfp_token_name = "PDFPTOKEN";
|
||||
if (dcfg->pdfp_only_get == NOT_SET) dcfg->pdfp_only_get = 0;
|
||||
|
||||
/* Geo Lookup */
|
||||
if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1185,6 +1195,22 @@ static const char *cmd_pdf_protect_intercept_get_only(cmd_parms *cmd, void *_dcf
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* -- Geo Lookup configuration -- */
|
||||
|
||||
static const char *cmd_geo_lookups_db(cmd_parms *cmd, void *_dcfg,
|
||||
const char *p1)
|
||||
{
|
||||
char *error_msg;
|
||||
directory_config *dcfg = (directory_config *)_dcfg;
|
||||
if (dcfg == NULL) return NULL;
|
||||
|
||||
if (geo_init(dcfg, p1, &error_msg) <= 0) {
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* -- Configuration directives definitions -- */
|
||||
|
||||
@ -1524,5 +1550,13 @@ const command_rec module_directives[] = {
|
||||
"whether or not to intercept only GET requess."
|
||||
),
|
||||
|
||||
AP_INIT_TAKE1 (
|
||||
"SecGeoLookupsDb",
|
||||
cmd_geo_lookups_db,
|
||||
NULL,
|
||||
RSRC_CONF,
|
||||
"database for geographical lookups module."
|
||||
),
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
@ -289,6 +289,9 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
|
||||
msr->tx_vars = apr_table_make(msr->mp, 32);
|
||||
if (msr->tx_vars == NULL) return -1;
|
||||
|
||||
msr->geo_vars = apr_table_make(msr->mp, 8);
|
||||
if (msr->geo_vars == NULL) return -1;
|
||||
|
||||
msr->collections = apr_table_make(msr->mp, 8);
|
||||
if (msr->collections == NULL) return -1;
|
||||
msr->collections_dirty = apr_table_make(msr->mp, 8);
|
||||
|
@ -39,6 +39,7 @@ typedef struct msc_string msc_string;
|
||||
#ifdef WITH_LIBXML2
|
||||
#include "msc_xml.h"
|
||||
#endif
|
||||
#include "msc_geo.h"
|
||||
#include "re.h"
|
||||
|
||||
#include "ap_config.h"
|
||||
@ -243,6 +244,9 @@ struct modsec_rec {
|
||||
|
||||
apr_table_t *tx_vars;
|
||||
|
||||
/* ENH: refactor to allow arbitrary var tables */
|
||||
apr_table_t *geo_vars;
|
||||
|
||||
/* response */
|
||||
unsigned int response_status;
|
||||
const char *status_line;
|
||||
@ -402,6 +406,9 @@ struct directory_config {
|
||||
int pdfp_timeout;
|
||||
const char *pdfp_token_name;
|
||||
int pdfp_only_get;
|
||||
|
||||
/* Geo Lookup */
|
||||
geo_db *geo;
|
||||
};
|
||||
|
||||
struct error_message {
|
||||
|
@ -2,10 +2,11 @@
|
||||
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
||||
re re_operators re_actions re_tfns re_variables \
|
||||
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
||||
persist_dbm msc_reqbody pdf_protect
|
||||
persist_dbm msc_reqbody pdf_protect msc_geo
|
||||
|
||||
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
|
||||
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h
|
||||
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
||||
msc_geo.h
|
||||
|
||||
${MOD_SECURITY2:=.slo}: ${H}
|
||||
${MOD_SECURITY2:=.lo}: ${H}
|
||||
|
447
apache2/msc_geo.c
Normal file
447
apache2/msc_geo.c
Normal file
@ -0,0 +1,447 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
|
||||
*
|
||||
* You should have received a copy of the licence along with this
|
||||
* program (stored in the file "LICENSE"). If the file is missing,
|
||||
* or if you have any other questions related to the licence, please
|
||||
* write to Thinking Stone at contact@thinkingstone.com.
|
||||
*
|
||||
*/
|
||||
#include "msc_geo.h"
|
||||
|
||||
|
||||
/* -- Lookup Tables -- */
|
||||
|
||||
static const char *geo_country_code[] = {
|
||||
"--",
|
||||
"AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
|
||||
"AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
|
||||
"BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
|
||||
"BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
|
||||
"CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
|
||||
"CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
|
||||
"DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
|
||||
"FK","FM","FO","FR","FX","GA","GB","GD","GE","GF",
|
||||
"GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
|
||||
"GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
|
||||
"IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
|
||||
"JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
|
||||
"KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
|
||||
"LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
|
||||
"MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
|
||||
"MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
|
||||
"NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
|
||||
"PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
|
||||
"PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
|
||||
"SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
|
||||
"SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
|
||||
"TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
|
||||
"TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
|
||||
"VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
|
||||
"ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE"
|
||||
};
|
||||
|
||||
static const char *geo_country_code3[] = {
|
||||
"--",
|
||||
"AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT",
|
||||
"AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
|
||||
"BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
|
||||
"BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD",
|
||||
"CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
|
||||
"CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
|
||||
"DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
|
||||
"FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF",
|
||||
"GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM",
|
||||
"GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN",
|
||||
"IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR",
|
||||
"JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
|
||||
"CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
|
||||
"LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
|
||||
"MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
|
||||
"MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
|
||||
"NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
|
||||
"PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
|
||||
"PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
|
||||
"SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
|
||||
"SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA",
|
||||
"TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
|
||||
"TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN",
|
||||
"VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF",
|
||||
"ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY"
|
||||
};
|
||||
|
||||
static const char *geo_country_name[] = {
|
||||
"N/A",
|
||||
"Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles",
|
||||
"Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
|
||||
"Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
|
||||
"Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
|
||||
"Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
|
||||
"Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
|
||||
"Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
|
||||
"Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
|
||||
"Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
|
||||
"Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
|
||||
"Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
|
||||
"Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
|
||||
"Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
|
||||
"Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
|
||||
"Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
|
||||
"Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
|
||||
"Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
|
||||
"Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
|
||||
"Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
|
||||
"Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
|
||||
"Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
|
||||
"Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
|
||||
"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",
|
||||
"Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
|
||||
"Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey"
|
||||
};
|
||||
|
||||
static const char *geo_country_continent[] = {
|
||||
"--",
|
||||
"AS","EU","EU","AS","AS","SA","SA","EU","AS","SA",
|
||||
"AF","AN","SA","OC","EU","OC","SA","AS","EU","SA",
|
||||
"AS","EU","AF","EU","AS","AF","AF","SA","AS","SA",
|
||||
"SA","SA","AS","AF","AF","EU","SA","NA","AS","AF",
|
||||
"AF","AF","EU","AF","OC","SA","AF","AS","SA","SA",
|
||||
"SA","AF","AS","AS","EU","EU","AF","EU","SA","SA",
|
||||
"AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
|
||||
"SA","OC","EU","EU","EU","AF","EU","SA","AS","SA",
|
||||
"AF","EU","SA","AF","AF","SA","AF","EU","SA","SA",
|
||||
"OC","AF","SA","AS","AF","SA","EU","SA","EU","AS",
|
||||
"EU","AS","AS","AS","AS","AS","EU","EU","SA","AS",
|
||||
"AS","AF","AS","AS","OC","AF","SA","AS","AS","AS",
|
||||
"SA","AS","AS","AS","SA","EU","AS","AF","AF","EU",
|
||||
"EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
|
||||
"AS","AS","AS","OC","SA","AF","SA","EU","AF","AS",
|
||||
"AF","NA","AS","AF","AF","OC","AF","OC","AF","SA",
|
||||
"EU","EU","AS","OC","OC","OC","AS","SA","SA","OC",
|
||||
"OC","AS","AS","EU","SA","OC","SA","AS","EU","OC",
|
||||
"SA","AS","AF","EU","AS","AF","AS","OC","AF","AF",
|
||||
"EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
|
||||
"SA","AF","SA","AS","AF","SA","AF","AF","AF","AS",
|
||||
"AS","OC","AS","AF","OC","AS","AS","SA","OC","AS",
|
||||
"AF","EU","AF","OC","NA","SA","AS","EU","SA","SA",
|
||||
"SA","SA","AS","OC","OC","OC","AS","AF","EU","AF",
|
||||
"AF","EU","AF","--","--","--","EU","EU","EU","EU"
|
||||
};
|
||||
|
||||
|
||||
static int db_open(directory_config *dcfg, char **error_msg)
|
||||
{
|
||||
char errstr[1024];
|
||||
apr_pool_t *mp = dcfg->mp;
|
||||
geo_db *geo = dcfg->geo;
|
||||
apr_status_t rc;
|
||||
apr_size_t nbytes;
|
||||
apr_off_t offset;
|
||||
unsigned char buf[3];
|
||||
int i, j;
|
||||
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: Initializing geo DB \"%s\".\n", geo->dbfn);
|
||||
#endif
|
||||
|
||||
if ((rc = apr_file_open(&geo->db, geo->dbfn, APR_READ, APR_OS_DEFAULT, mp)) != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(mp, "Could not open geo database \"%s\": %s", geo->dbfn, apr_strerror(rc, errstr, 1024));
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = -3;
|
||||
apr_file_seek(geo->db, APR_END, &offset);
|
||||
/* TODO check offset */
|
||||
|
||||
/* Defaults */
|
||||
geo->dbtype = GEO_COUNTRY_DATABASE;
|
||||
geo->ctry_offset = GEO_COUNTRY_OFFSET;
|
||||
|
||||
for (i = 0; i < GEO_STRUCT_INFO_MAX_SIZE; i++) {
|
||||
memset(buf, 0, 3);
|
||||
rc = apr_file_read_full(geo->db, &buf, 3, &nbytes);
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: read 0x%02x%02x%02x\n", buf[0], buf[1], buf[2]);
|
||||
#endif
|
||||
if ((rc != APR_SUCCESS) || (nbytes != 3)) {
|
||||
*error_msg = apr_psprintf(mp, "Could not read from geo database \"%s\" (%d/3 bytes read): %s", geo->dbfn, nbytes, apr_strerror(rc, errstr, 1024));
|
||||
return -1;
|
||||
}
|
||||
if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) {
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: Found DB info marker at offset 0x%08x\n", (unsigned int)offset);
|
||||
#endif
|
||||
memset(buf, 0, 3);
|
||||
rc = apr_file_read_full(geo->db, &buf, 1, &nbytes);
|
||||
/* TODO: check rc */
|
||||
geo->dbtype = (int)buf[0];
|
||||
|
||||
/* Backwards compat */
|
||||
if (geo->dbtype >= 106) {
|
||||
geo->dbtype -= 105;
|
||||
}
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: DB type %d\n", geo->dbtype);
|
||||
#endif
|
||||
|
||||
/* If a cities DB, then get country offset */
|
||||
if ((geo->dbtype == GEO_CITY_DATABASE_0) || (geo->dbtype == GEO_CITY_DATABASE_1)) {
|
||||
memset(buf, 0, 3);
|
||||
rc = apr_file_read_full(geo->db, &buf, 3, &nbytes);
|
||||
if ((rc != APR_SUCCESS) || (nbytes != 3)) {
|
||||
*error_msg = apr_psprintf(mp, "Could not read geo database \"%s\" country offset (%d/3 bytes read): %s", geo->dbfn, nbytes, apr_strerror(rc, errstr, 1024));
|
||||
return -1;
|
||||
}
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: read 0x%02x%02x%02x\n", buf[0], buf[1], buf[2]);
|
||||
#endif
|
||||
geo->ctry_offset = 0;
|
||||
for (j = 0; j < 3; j++) {
|
||||
geo->ctry_offset += (buf[j] << (j * 8));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: Country offset 0x%08x\n", geo->ctry_offset);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* Backup a byte from where we started */
|
||||
offset = -4;
|
||||
apr_file_seek(geo->db, APR_CUR, &offset);
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: DB offset 0x%08x\n", (unsigned int)offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (geo->dbtype != GEO_COUNTRY_DATABASE) {
|
||||
*error_msg = apr_psprintf(mp, "Unknown database format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: DB type %d\n", geo->dbtype);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Geo data structure
|
||||
*/
|
||||
int geo_init(directory_config *dcfg, const char *dbfn, char **error_msg)
|
||||
{
|
||||
*error_msg = NULL;
|
||||
|
||||
if ((dcfg->geo == NULL) || (dcfg->geo == NOT_SET_P)) {
|
||||
dcfg->geo = apr_pcalloc(dcfg->mp, sizeof(geo_db));
|
||||
}
|
||||
|
||||
dcfg->geo->db = NULL;
|
||||
dcfg->geo->dbfn = apr_pstrdup(dcfg->mp, dbfn);
|
||||
dcfg->geo->dbtype = 0;
|
||||
dcfg->geo->ctry_offset = 0;
|
||||
|
||||
return db_open(dcfg, error_msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform geographical lookup on target.
|
||||
*/
|
||||
int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **error_msg)
|
||||
{
|
||||
apr_sockaddr_t *addr;
|
||||
long ipnum = 0;
|
||||
char *targetip = NULL;
|
||||
geo_db *geo = msr->txcfg->geo;
|
||||
char errstr[1024];
|
||||
unsigned char buf[2* GEO_MAX_RECORD_LEN];
|
||||
const int reclen = 3; /* Algorithm needs changed if this changes */
|
||||
apr_size_t nbytes;
|
||||
unsigned int rec_val = 0;
|
||||
apr_off_t seekto = 0;
|
||||
int rc;
|
||||
int country = 0;
|
||||
int level;
|
||||
double dtmp;
|
||||
int itmp;
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
/* init */
|
||||
georec->country_code = geo_country_code[0];
|
||||
georec->country_code3 = geo_country_code3[0];
|
||||
georec->country_name = geo_country_name[0];
|
||||
georec->country_continent = geo_country_continent[0];
|
||||
georec->region = "";
|
||||
georec->city = "";
|
||||
georec->postal_code = "";
|
||||
georec->latitude = 0;
|
||||
georec->longitude = 0;
|
||||
georec->dma_code = 0;
|
||||
georec->area_code = 0;
|
||||
|
||||
msr_log(msr, 9, "GEO: Looking up \"%s\".", target);
|
||||
|
||||
/* NOTE: This only works with ipv4 */
|
||||
if ((rc = apr_sockaddr_info_get(&addr, target, APR_INET, 0, 0, msr->mp)) != APR_SUCCESS) {
|
||||
|
||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", target, apr_strerror(rc, errstr, 1024));
|
||||
return 0;
|
||||
}
|
||||
if ((rc = apr_sockaddr_ip_get(&targetip, addr)) != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", target, apr_strerror(rc, errstr, 1024));
|
||||
return 0;
|
||||
};
|
||||
|
||||
/* Why is this in host byte order? */
|
||||
ipnum = ntohl(addr->sa.sin.sin_addr.s_addr);
|
||||
|
||||
msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08x).", targetip, ipnum);
|
||||
|
||||
for (level = 31; level >= 0; level--) {
|
||||
|
||||
/* Read the record */
|
||||
seekto = 2 * reclen * rec_val;
|
||||
apr_file_seek(geo->db, APR_SET, &seekto);
|
||||
/* TODO: check rc */
|
||||
rc = apr_file_read_full(geo->db, &buf, (2 * reclen), &nbytes);
|
||||
|
||||
|
||||
|
||||
/* NOTE: This is hard-coded for size 3 records */
|
||||
/* Left */
|
||||
if ((ipnum & (1 << level)) == 0) {
|
||||
rec_val = buf[0] +
|
||||
(buf[1] << 8) +
|
||||
(buf[2] << 16);
|
||||
}
|
||||
/* Right */
|
||||
else {
|
||||
rec_val = buf[3] +
|
||||
(buf[4] << 8) +
|
||||
(buf[5] << 16);
|
||||
}
|
||||
|
||||
/* If we are past the country offset, then we are done */
|
||||
if (rec_val >= geo->ctry_offset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (geo->dbtype == GEO_COUNTRY_DATABASE) {
|
||||
country = rec_val;
|
||||
country -= geo->ctry_offset;
|
||||
if (country <= 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", target);
|
||||
return 0;
|
||||
}
|
||||
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, buf, sizeof(buf)));
|
||||
|
||||
/* Country */
|
||||
msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, (unsigned char *)&rec_val, 1));
|
||||
georec->country_code = geo_country_code[country];
|
||||
georec->country_code3 = geo_country_code3[country];
|
||||
georec->country_name = geo_country_name[country];
|
||||
georec->country_continent = geo_country_continent[country];
|
||||
}
|
||||
else {
|
||||
int field_len = 0;
|
||||
int rec_offset = 0;
|
||||
int remaining = GEO_CITY_RECORD_LEN;
|
||||
unsigned char cbuf[GEO_CITY_RECORD_LEN];
|
||||
|
||||
seekto = rec_val + (2 * reclen - 1) * geo->ctry_offset;
|
||||
apr_file_seek(geo->db, APR_SET, &seekto);
|
||||
/* TODO: check rc */
|
||||
rc = apr_file_read_full(geo->db, &cbuf, sizeof(cbuf), &nbytes);
|
||||
|
||||
country = cbuf[0];
|
||||
if (country <= 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", target);
|
||||
return 0;
|
||||
}
|
||||
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
||||
|
||||
/* Country */
|
||||
msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
||||
georec->country_code = geo_country_code[country];
|
||||
georec->country_code3 = geo_country_code3[country];
|
||||
georec->country_name = geo_country_name[country];
|
||||
georec->country_continent = geo_country_continent[country];
|
||||
rec_offset++;
|
||||
remaining -= rec_offset;
|
||||
|
||||
/* Region */
|
||||
field_len = strnlen((const char *)cbuf+rec_offset,remaining);
|
||||
msr_log(msr, 9, "GEO: region=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
georec->region = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||
rec_offset += field_len + 1;
|
||||
remaining -= field_len + 1;
|
||||
|
||||
/* City */
|
||||
field_len = strnlen((const char *)cbuf+rec_offset,remaining);
|
||||
msr_log(msr, 9, "GEO: city=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
georec->city = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||
rec_offset += field_len + 1;
|
||||
remaining -= field_len + 1;
|
||||
|
||||
/* Postal Code */
|
||||
field_len = strnlen((const char *)cbuf+rec_offset,remaining);
|
||||
msr_log(msr, 9, "GEO: postal_code=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
georec->postal_code = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||
rec_offset += field_len + 1;
|
||||
remaining -= field_len + 1;
|
||||
|
||||
/* Latitude */
|
||||
msr_log(msr, 9, "GEO: latitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
dtmp = cbuf[rec_offset] +
|
||||
(cbuf[rec_offset+1] << 8) +
|
||||
(cbuf[rec_offset+2] << 16);
|
||||
georec->latitude = dtmp/10000 - 180;
|
||||
rec_offset += 3;
|
||||
remaining -= 3;
|
||||
|
||||
|
||||
/* Longitude */
|
||||
msr_log(msr, 9, "GEO: longitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
dtmp = cbuf[rec_offset] +
|
||||
(cbuf[rec_offset+1] << 8) +
|
||||
(cbuf[rec_offset+2] << 16);
|
||||
georec->longitude = dtmp/10000 - 180;
|
||||
rec_offset += 3;
|
||||
remaining -= 3;
|
||||
|
||||
/* dma/area codes are in city rev1 and US only */
|
||||
msr_log(msr, 9, "GEO: dma/area=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
if (geo->dbtype == GEO_CITY_DATABASE_1
|
||||
&& georec->country_code[0] == 'U'
|
||||
&& georec->country_code[1] == 'S')
|
||||
{
|
||||
/* DMA Code */
|
||||
itmp = cbuf[rec_offset] +
|
||||
(cbuf[rec_offset+1] << 8) +
|
||||
(cbuf[rec_offset+2] << 16);
|
||||
georec->dma_code = itmp / 1000;
|
||||
georec->area_code = itmp % 1000;
|
||||
rec_offset += 6;
|
||||
remaining -= 6;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" succeeded.", target);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the resources used for Geo lookups
|
||||
*/
|
||||
apr_status_t geo_cleanup(modsec_rec *msr)
|
||||
{
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
62
apache2/msc_geo.h
Normal file
62
apache2/msc_geo.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
|
||||
*
|
||||
* You should have received a copy of the licence along with this
|
||||
* program (stored in the file "LICENSE"). If the file is missing,
|
||||
* or if you have any other questions related to the licence, please
|
||||
* write to Thinking Stone at contact@thinkingstone.com.
|
||||
*
|
||||
*/
|
||||
#ifndef _MSC_GEO_H_
|
||||
#define _MSC_GEO_H_
|
||||
|
||||
#define GEO_STRUCT_INFO_MAX_SIZE 20
|
||||
#define GEO_DB_INFO_MAX_SIZE 100
|
||||
#define GEO_COUNTRY_OFFSET 0xffff00
|
||||
#define GEO_MAX_RECORD_LEN 4
|
||||
#define GEO_COUNTRY_UNKNOWN "Unknown"
|
||||
#define GEO_CITY_UNKNOWN "Unknown"
|
||||
#define GEO_CITY_RECORD_LEN 50
|
||||
#define GEO_COUNTRY_DATABASE 1
|
||||
#define GEO_CITY_DATABASE_0 6
|
||||
#define GEO_CITY_DATABASE_1 2
|
||||
|
||||
typedef struct geo_rec geo_rec;
|
||||
typedef struct geo_db geo_db;
|
||||
|
||||
#include <apr_file_io.h>
|
||||
#include "modsecurity.h"
|
||||
|
||||
/* Structures */
|
||||
|
||||
struct geo_rec {
|
||||
const char *country_code;
|
||||
const char *country_code3;
|
||||
const char *country_name;
|
||||
const char *country_continent;
|
||||
const char *region;
|
||||
const char *city;
|
||||
const char *postal_code;
|
||||
float latitude;
|
||||
float longitude;
|
||||
int dma_code;
|
||||
int area_code;
|
||||
};
|
||||
|
||||
struct geo_db {
|
||||
apr_file_t *db;
|
||||
const char *dbfn;
|
||||
int dbtype;
|
||||
unsigned int ctry_offset;
|
||||
};
|
||||
|
||||
/* Functions */
|
||||
|
||||
int DSOLOCAL geo_init(directory_config *dcfg, const char *dbfn, char **error_msg);
|
||||
|
||||
int DSOLOCAL geo_lookup(modsec_rec *msr, geo_rec *rec, const char *target, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL geo_cleanup(modsec_rec *msr);
|
||||
|
||||
#endif
|
@ -447,6 +447,18 @@ char *log_escape_header_name(apr_pool_t *mp, const char *text) {
|
||||
return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 0, 1);
|
||||
}
|
||||
|
||||
char *log_escape_raw(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) {
|
||||
unsigned char *ret = apr_palloc(mp, text_length * 4 + 1);
|
||||
unsigned long int i, j;
|
||||
|
||||
for (i = 0, j = 0; i < text_length; i++, j += 4) {
|
||||
apr_snprintf((char *)ret+j, 5, "\\x%02x", text[i]);
|
||||
}
|
||||
ret[text_length * 4] = '\0';
|
||||
|
||||
return (char *)ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform input into a form safe for logging.
|
||||
*/
|
||||
|
@ -61,6 +61,8 @@ char DSOLOCAL *log_escape_nq_ex(apr_pool_t *p, const char *text, unsigned long i
|
||||
|
||||
char DSOLOCAL *log_escape_header_name(apr_pool_t *p, const char *text);
|
||||
|
||||
char *log_escape_raw(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length);
|
||||
|
||||
char DSOLOCAL *_log_escape(apr_pool_t *p, const unsigned char *input,
|
||||
unsigned long int input_length, int escape_quotes, int escape_colon);
|
||||
|
||||
|
@ -36,7 +36,6 @@ typedef struct msre_action msre_action;
|
||||
#include "persist_dbm.h"
|
||||
#include "apache2.h"
|
||||
|
||||
|
||||
/* Actions, variables, functions and operator functions */
|
||||
|
||||
int DSOLOCAL expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp);
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
#include "re.h"
|
||||
#include "msc_pcre.h"
|
||||
#include "msc_geo.h"
|
||||
#include "apr_strmatch.h"
|
||||
|
||||
/**
|
||||
@ -560,6 +561,102 @@ static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Perform geograpical lookups on an IP/Host.
|
||||
*/
|
||||
static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
|
||||
char **error_msg)
|
||||
{
|
||||
geo_rec rec;
|
||||
geo_db *geo = msr->txcfg->geo;
|
||||
const char *geo_host = var->value;
|
||||
msc_string *s = NULL;
|
||||
int rc;
|
||||
|
||||
if (geo == NULL) {
|
||||
msr_log(msr, 1, "Geo lookup for \"%s\" attempted without a database. Set SecGeoLookupDb.", geo_host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
rc = geo_lookup(msr, &rec, geo_host, error_msg);
|
||||
if (rc <= 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: %s={country_code=%s, country_code3=%s, country_name=%s, country_continent=%s, region=%s, city=%s, postal_code=%s, latitude=%f, longitude=%f, dma_code=%d, area_code=%d}",
|
||||
geo_host,
|
||||
rec.country_code,
|
||||
rec.country_code3,
|
||||
rec.country_name,
|
||||
rec.country_continent,
|
||||
rec.region,
|
||||
rec.city,
|
||||
rec.postal_code,
|
||||
rec.latitude,
|
||||
rec.longitude,
|
||||
rec.dma_code,
|
||||
rec.area_code);
|
||||
}
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "country_code");
|
||||
s->value = apr_pstrdup(msr->mp, rec.country_code ? rec.country_code : "");
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "country_code3");
|
||||
s->value = apr_pstrdup(msr->mp, rec.country_code3 ? rec.country_code3 : "");
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "region");
|
||||
s->value = apr_pstrdup(msr->mp, rec.region ? rec.region : "");
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "city");
|
||||
s->value = apr_pstrdup(msr->mp, rec.city ? rec.city : "");
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "postal_code");
|
||||
s->value = apr_pstrdup(msr->mp, rec.postal_code ? rec.postal_code : "");
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "latitude");
|
||||
s->value = apr_psprintf(msr->mp, "%f", rec.latitude);
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "longitude");
|
||||
s->value = apr_psprintf(msr->mp, "%f", rec.longitude);
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "dma_code");
|
||||
s->value = apr_psprintf(msr->mp, "%d", rec.dma_code);
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
s->name = apr_pstrdup(msr->mp, "area_code");
|
||||
s->value = apr_psprintf(msr->mp, "%d", rec.area_code);
|
||||
s->value_len = strlen(s->value);
|
||||
apr_table_setn(msr->geo_vars, s->name, (void *)s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* rbl */
|
||||
|
||||
static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
|
||||
@ -1153,6 +1250,13 @@ void msre_engine_register_default_operators(msre_engine *engine) {
|
||||
|
||||
#endif
|
||||
|
||||
/* geoLookup */
|
||||
msre_engine_op_register(engine,
|
||||
"geoLookup",
|
||||
NULL,
|
||||
msre_op_geoLookup_execute
|
||||
);
|
||||
|
||||
/* rbl */
|
||||
msre_engine_op_register(engine,
|
||||
"rbl",
|
||||
|
@ -548,6 +548,50 @@ static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
||||
return count;
|
||||
}
|
||||
|
||||
/* GEO */
|
||||
|
||||
static int var_geo_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
||||
apr_table_t *vartab, apr_pool_t *mptmp)
|
||||
{
|
||||
const apr_array_header_t *arr = NULL;
|
||||
const apr_table_entry_t *te = NULL;
|
||||
int i, count = 0;
|
||||
|
||||
arr = apr_table_elts(msr->geo_vars);
|
||||
te = (apr_table_entry_t *)arr->elts;
|
||||
for (i = 0; i < arr->nelts; i++) {
|
||||
msc_string *str = (msc_string *)te[i].val;
|
||||
int match;
|
||||
|
||||
/* Figure out if we want to include this variable. */
|
||||
match = 0;
|
||||
if (var->param == NULL) match = 1; /* Unconditional inclusion. */
|
||||
else {
|
||||
if (var->param_data != NULL) { /* Regex. */
|
||||
char *my_error_msg = NULL;
|
||||
if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
|
||||
str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
|
||||
} else { /* Simple comparison. */
|
||||
if (strcasecmp(str->name, var->param) == 0) match = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we had a match add this argument to the collection. */
|
||||
if (match) {
|
||||
msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
|
||||
|
||||
rvar->value = str->value;
|
||||
rvar->value_len = str->value_len;
|
||||
rvar->name = apr_psprintf(mptmp, "GEO:%s", log_escape_nq(mptmp, str->name));
|
||||
apr_table_addn(vartab, rvar->name, (void *)rvar);
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* IP */
|
||||
|
||||
static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
||||
@ -1865,6 +1909,17 @@ void msre_engine_register_default_variables(msre_engine *engine) {
|
||||
PHASE_REQUEST_HEADERS
|
||||
);
|
||||
|
||||
/* GEO */
|
||||
msre_engine_variable_register(engine,
|
||||
"GEO",
|
||||
VAR_LIST,
|
||||
1, 1,
|
||||
var_generic_list_validate,
|
||||
var_geo_generate,
|
||||
VAR_CACHE,
|
||||
PHASE_REQUEST_HEADERS
|
||||
);
|
||||
|
||||
/* IP */
|
||||
msre_engine_variable_register(engine,
|
||||
"IP",
|
||||
|
@ -1018,6 +1018,28 @@ SecAuditLogStorageDir logs/audit
|
||||
phase.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal>SecGeoLookupsDb</literal></title>
|
||||
|
||||
<para><emphasis role="bold">Description:</emphasis> Defines the path to
|
||||
the geograpical database file.</para>
|
||||
|
||||
<para><emphasis role="bold">Syntax:</emphasis> <literal
|
||||
moreinfo="none">SecGeoLookupsDb /path/to/db</literal></para>
|
||||
|
||||
<para><emphasis role="bold">Example Usage:</emphasis> <literal
|
||||
moreinfo="none">SecGeoLookupsDb
|
||||
/usr/local/geo/data/GeoLiteCity.dat</literal></para>
|
||||
|
||||
<para><emphasis role="bold">Processing Phase:</emphasis> N/A</para>
|
||||
|
||||
<para><emphasis role="bold"> <emphasis role="bold">Scope:</emphasis>
|
||||
</emphasis>Any</para>
|
||||
|
||||
<para><emphasis role="bold">Dependencies/Notes:</emphasis> Check out
|
||||
www.maxmind.com for free database files.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal>SecGuardianLog</literal></title>
|
||||
|
||||
@ -2059,6 +2081,80 @@ SecRule <emphasis role="bold">ENV:tag</emphasis> "suspicious"</programlisting>
|
||||
<programlisting format="linespecific">SecRule <emphasis role="bold">FILES_TMPNAMES</emphasis> "@inspectFile /path/to/inspect_script.pl"</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal moreinfo="none">GEO</literal></title>
|
||||
|
||||
<para><literal>GEO</literal> is a collection populated by the <literal
|
||||
moreinfo="none">@geoLookups</literal> operator. It can be used to match
|
||||
geographical fields looked up by an IP address or hostname.</para>
|
||||
|
||||
<para>Available since 2.2.0.</para>
|
||||
|
||||
<para>Fields:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">COUNTRY_CODE:</emphasis> Two character
|
||||
country code. EX: US, UK, etc.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">COUNTRY_CODE3:</emphasis> Up to three
|
||||
character country code.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">COUNTRY_NAME:</emphasis> The full
|
||||
country name.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">COUNTRY_CONTINENT:</emphasis> The teo
|
||||
character continent that the country is located. EX: EU</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">REGION:</emphasis> The two character
|
||||
region. For US, this is state. For Canada, providence, etc.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">CITY:</emphasis> The city name.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">POSTAL_CODE:</emphasis> The postal
|
||||
code.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">LATITUDE:</emphasis> The
|
||||
latitude.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">LONGITUDE:</emphasis> The
|
||||
longitude.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">DMA_CODE:</emphasis> The metropoliton
|
||||
area code. (US only)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis role="bold">AREA_CODE:</emphasis> The phone system
|
||||
area code. (US only)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Example:</para>
|
||||
|
||||
<programlisting format="linespecific">SecRule REMOTE_ADDR "<emphasis
|
||||
role="bold">@geoLookup</emphasis>" chain,drop,msg:'Non-UK IP address'
|
||||
SecRule GEO:COUNTRY_CODE "!@streq UK"</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal moreinfo="none">PATH_INFO</literal></title>
|
||||
|
||||
@ -4124,6 +4220,22 @@ SecRule ARGS:route "!<emphasis role="bold">@endsWith %{REQUEST_ADDR}</emphasis>"
|
||||
role="bold">@ge</emphasis> 15"</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal>geoLookup</literal></title>
|
||||
|
||||
<para><emphasis role="bold">Description:</emphasis> This operator looks
|
||||
up various data fields from an IP address or hostname. The results will
|
||||
be captured in the <literal moreinfo="none">GEO</literal>
|
||||
collection.</para>
|
||||
|
||||
<para>You must provide a database via <literal
|
||||
moreinfo="none">SecGeoLookupsDb</literal> before this operator can be
|
||||
used.</para>
|
||||
|
||||
<para>See the <literal moreinfo="none">GEO</literal> variable for an
|
||||
example and more information on various fields available.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal>gt</literal></title>
|
||||
|
||||
@ -4383,4 +4495,4 @@ SecRule XML "<emphasis role="bold">@validateSchema /path/to/apache2/conf/xml.xsd
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
</article>
|
||||
</article>
|
||||
|
Loading…
x
Reference in New Issue
Block a user