mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 05:45:59 +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
|
?? ??? 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
|
* Do not try to intercept a request after a failed rule. This fixes the
|
||||||
issue associated with an "Internal Error: Asked to intercept request
|
issue associated with an "Internal Error: Asked to intercept request
|
||||||
but was_intercepted is zero" error message.
|
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 \
|
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 \
|
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_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)
|
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_token_name = NOT_SET_P;
|
||||||
dcfg->pdfp_only_get = NOT_SET;
|
dcfg->pdfp_only_get = NOT_SET;
|
||||||
|
|
||||||
|
/* Geo Lookups */
|
||||||
|
dcfg->geo = NOT_SET_P;
|
||||||
|
|
||||||
return dcfg;
|
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
|
merged->pdfp_only_get = (child->pdfp_only_get == NOT_SET
|
||||||
? parent->pdfp_only_get : child->pdfp_only_get);
|
? parent->pdfp_only_get : child->pdfp_only_get);
|
||||||
|
|
||||||
|
/* Geo Lookup */
|
||||||
|
merged->geo = (child->geo == NOT_SET_P
|
||||||
|
? parent->geo : child->geo);
|
||||||
|
|
||||||
return merged;
|
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_timeout == NOT_SET) dcfg->pdfp_timeout = 10;
|
||||||
if (dcfg->pdfp_token_name == NOT_SET_P) dcfg->pdfp_token_name = "PDFPTOKEN";
|
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;
|
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;
|
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 -- */
|
/* -- Configuration directives definitions -- */
|
||||||
|
|
||||||
@ -1524,5 +1550,13 @@ const command_rec module_directives[] = {
|
|||||||
"whether or not to intercept only GET requess."
|
"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 }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
@ -289,6 +289,9 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
|
|||||||
msr->tx_vars = apr_table_make(msr->mp, 32);
|
msr->tx_vars = apr_table_make(msr->mp, 32);
|
||||||
if (msr->tx_vars == NULL) return -1;
|
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);
|
msr->collections = apr_table_make(msr->mp, 8);
|
||||||
if (msr->collections == NULL) return -1;
|
if (msr->collections == NULL) return -1;
|
||||||
msr->collections_dirty = apr_table_make(msr->mp, 8);
|
msr->collections_dirty = apr_table_make(msr->mp, 8);
|
||||||
|
@ -39,6 +39,7 @@ typedef struct msc_string msc_string;
|
|||||||
#ifdef WITH_LIBXML2
|
#ifdef WITH_LIBXML2
|
||||||
#include "msc_xml.h"
|
#include "msc_xml.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "msc_geo.h"
|
||||||
#include "re.h"
|
#include "re.h"
|
||||||
|
|
||||||
#include "ap_config.h"
|
#include "ap_config.h"
|
||||||
@ -243,6 +244,9 @@ struct modsec_rec {
|
|||||||
|
|
||||||
apr_table_t *tx_vars;
|
apr_table_t *tx_vars;
|
||||||
|
|
||||||
|
/* ENH: refactor to allow arbitrary var tables */
|
||||||
|
apr_table_t *geo_vars;
|
||||||
|
|
||||||
/* response */
|
/* response */
|
||||||
unsigned int response_status;
|
unsigned int response_status;
|
||||||
const char *status_line;
|
const char *status_line;
|
||||||
@ -402,6 +406,9 @@ struct directory_config {
|
|||||||
int pdfp_timeout;
|
int pdfp_timeout;
|
||||||
const char *pdfp_token_name;
|
const char *pdfp_token_name;
|
||||||
int pdfp_only_get;
|
int pdfp_only_get;
|
||||||
|
|
||||||
|
/* Geo Lookup */
|
||||||
|
geo_db *geo;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct error_message {
|
struct error_message {
|
||||||
|
@ -2,10 +2,11 @@
|
|||||||
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
||||||
re re_operators re_actions re_tfns re_variables \
|
re re_operators re_actions re_tfns re_variables \
|
||||||
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
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 \
|
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:=.slo}: ${H}
|
||||||
${MOD_SECURITY2:=.lo}: ${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);
|
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.
|
* 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 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,
|
char DSOLOCAL *_log_escape(apr_pool_t *p, const unsigned char *input,
|
||||||
unsigned long int input_length, int escape_quotes, int escape_colon);
|
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 "persist_dbm.h"
|
||||||
#include "apache2.h"
|
#include "apache2.h"
|
||||||
|
|
||||||
|
|
||||||
/* Actions, variables, functions and operator functions */
|
/* Actions, variables, functions and operator functions */
|
||||||
|
|
||||||
int DSOLOCAL expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp);
|
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 "re.h"
|
||||||
#include "msc_pcre.h"
|
#include "msc_pcre.h"
|
||||||
|
#include "msc_geo.h"
|
||||||
#include "apr_strmatch.h"
|
#include "apr_strmatch.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -560,6 +561,102 @@ static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre
|
|||||||
|
|
||||||
#endif
|
#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 */
|
/* rbl */
|
||||||
|
|
||||||
static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
|
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
|
#endif
|
||||||
|
|
||||||
|
/* geoLookup */
|
||||||
|
msre_engine_op_register(engine,
|
||||||
|
"geoLookup",
|
||||||
|
NULL,
|
||||||
|
msre_op_geoLookup_execute
|
||||||
|
);
|
||||||
|
|
||||||
/* rbl */
|
/* rbl */
|
||||||
msre_engine_op_register(engine,
|
msre_engine_op_register(engine,
|
||||||
"rbl",
|
"rbl",
|
||||||
|
@ -548,6 +548,50 @@ static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
|||||||
return count;
|
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 */
|
/* IP */
|
||||||
|
|
||||||
static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
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
|
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 */
|
/* IP */
|
||||||
msre_engine_variable_register(engine,
|
msre_engine_variable_register(engine,
|
||||||
"IP",
|
"IP",
|
||||||
|
@ -1018,6 +1018,28 @@ SecAuditLogStorageDir logs/audit
|
|||||||
phase.</para>
|
phase.</para>
|
||||||
</section>
|
</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>
|
<section>
|
||||||
<title><literal>SecGuardianLog</literal></title>
|
<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>
|
<programlisting format="linespecific">SecRule <emphasis role="bold">FILES_TMPNAMES</emphasis> "@inspectFile /path/to/inspect_script.pl"</programlisting>
|
||||||
</section>
|
</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>
|
<section>
|
||||||
<title><literal moreinfo="none">PATH_INFO</literal></title>
|
<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>
|
role="bold">@ge</emphasis> 15"</programlisting>
|
||||||
</section>
|
</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>
|
<section>
|
||||||
<title><literal>gt</literal></title>
|
<title><literal>gt</literal></title>
|
||||||
|
|
||||||
@ -4383,4 +4495,4 @@ SecRule XML "<emphasis role="bold">@validateSchema /path/to/apache2/conf/xml.xsd
|
|||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user