44 SCLogError(
"no GeoIP support built in, needed for geoip keyword");
55 sigmatch_table[
DETECT_GEOIP].
desc =
"match on the source, destination or source and destination IP addresses of network traffic, and to see to which country it belongs";
63 #include <maxminddb.h>
69 static void DetectGeoipRegisterTests(
void);
96 static bool InitGeolocationEngine(DetectGeoipData *geoipdata)
98 const char *filename = NULL;
101 (void)
SCConfGet(
"geoip-database", &filename);
103 if (filename == NULL) {
105 "database filename in YAML conf. GeoIP rule matching "
107 geoipdata->mmdb_status = MMDB_FILE_OPEN_ERROR;
112 int status = MMDB_open(filename, MMDB_MODE_MMAP, &geoipdata->mmdb);
114 if (status == MMDB_SUCCESS) {
115 geoipdata->mmdb_status = status;
120 "Error was: %s. GeoIP rule matching is disabled.",
121 filename, MMDB_strerror(status));
122 geoipdata->mmdb_status = status;
135 static const char *GeolocateIPv4(
const DetectGeoipData *geoipdata, uint32_t ip)
138 struct sockaddr_in sa;
139 sa.sin_family = AF_INET;
141 sa.sin_addr.s_addr = ip;
142 MMDB_lookup_result_s result;
143 MMDB_entry_data_s entry_data;
146 if (geoipdata->mmdb_status != MMDB_SUCCESS)
150 result = MMDB_lookup_sockaddr((MMDB_s *)&geoipdata->mmdb,
151 (
struct sockaddr*)&sa, &mmdb_error);
152 if (mmdb_error != MMDB_SUCCESS)
156 if (result.found_entry) {
157 mmdb_error = MMDB_get_value(&result.entry, &entry_data,
"country",
159 if (mmdb_error != MMDB_SUCCESS)
163 if (entry_data.has_data) {
164 if (entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
165 char *country_code =
SCStrndup((
char *)entry_data.utf8_string,
166 entry_data.data_size);
177 #define GEOIP_MATCH_SRC_STR "src"
178 #define GEOIP_MATCH_DST_STR "dst"
179 #define GEOIP_MATCH_BOTH_STR "both"
180 #define GEOIP_MATCH_ANY_STR "any"
182 #define GEOIP_MATCH_NO_FLAG 0
183 #define GEOIP_MATCH_SRC_FLAG 1
184 #define GEOIP_MATCH_DST_FLAG 2
185 #define GEOIP_MATCH_ANY_FLAG 3
186 #define GEOIP_MATCH_BOTH_FLAG 4
187 #define GEOIP_MATCH_NEGATED 8
198 static int CheckGeoMatchIPv4(
const DetectGeoipData *geoipdata, uint32_t ip)
203 const char *country = GeolocateIPv4(geoipdata, ip);
210 if ((geoipdata->flags & GEOIP_MATCH_NEGATED) == 0)
212 for (i = 0; i < geoipdata->nlocations; i++) {
213 if (strcmp(country, (
char *)geoipdata->location[i])==0) {
220 for (i = 0; i < geoipdata->nlocations; i++) {
221 if (strcmp(country, (
char *)geoipdata->location[i])==0) {
248 const DetectGeoipData *geoipdata = (
const DetectGeoipData *)
ctx;
251 if (PacketIsIPv4(
p)) {
252 if (geoipdata->flags & ( GEOIP_MATCH_SRC_FLAG | GEOIP_MATCH_BOTH_FLAG ))
256 if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG)
262 if (geoipdata->flags & ( GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_BOTH_FLAG ))
266 if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG)
291 DetectGeoipData *geoipdata = NULL;
293 uint16_t prevpos = 0;
295 int skiplocationparsing = 0;
302 geoipdata =
SCCalloc(1,
sizeof(DetectGeoipData));
310 if (
str[pos] ==
',' || pos == slen)
312 if (geoipdata->flags == GEOIP_MATCH_NO_FLAG)
318 skiplocationparsing = 0;
319 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
321 skiplocationparsing = 1;
322 if (strncmp(&
str[prevpos], GEOIP_MATCH_SRC_STR, pos-prevpos) == 0)
323 geoipdata->flags |= GEOIP_MATCH_SRC_FLAG;
324 else if (strncmp(&
str[prevpos], GEOIP_MATCH_DST_STR, pos-prevpos) == 0)
325 geoipdata->flags |= GEOIP_MATCH_DST_FLAG;
326 else if (strncmp(&
str[prevpos], GEOIP_MATCH_BOTH_STR, pos-prevpos) == 0)
327 geoipdata->flags |= GEOIP_MATCH_BOTH_FLAG;
328 else if (strncmp(&
str[prevpos], GEOIP_MATCH_ANY_STR, pos-prevpos) == 0)
329 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
332 skiplocationparsing = 0;
333 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
337 if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0)
340 if (
str[prevpos] ==
'!') {
341 geoipdata->flags |= GEOIP_MATCH_NEGATED;
345 if (geoipdata->nlocations >= GEOOPTION_MAXLOCATIONS) {
346 SCLogError(
"too many arguments for geoip keyword");
350 if (pos-prevpos > GEOOPTION_MAXSIZE)
351 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
354 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
357 if (geoipdata->nlocations < GEOOPTION_MAXLOCATIONS)
358 geoipdata->nlocations++;
361 skiplocationparsing = 0;
366 SCLogDebug(
"GeoIP: %"PRIu32
" countries loaded", geoipdata->nlocations);
367 for (
int i=0; i<geoipdata->nlocations; i++)
368 SCLogDebug(
"GeoIP country code: %s", geoipdata->location[i]);
371 if (geoipdata->flags & GEOIP_MATCH_NEGATED) {
378 if (!InitGeolocationEngine(geoipdata))
385 if (geoipdata != NULL)
386 DetectGeoipDataFree(
de_ctx, geoipdata);
403 DetectGeoipData *geoipdata = NULL;
405 geoipdata = DetectGeoipDataParse(
de_ctx, optstr);
406 if (geoipdata == NULL)
419 if (geoipdata != NULL)
420 DetectGeoipDataFree(
de_ctx, geoipdata);
433 DetectGeoipData *geoipdata = (DetectGeoipData *)ptr;
434 if (geoipdata->mmdb_status == MMDB_SUCCESS)
435 MMDB_close(&geoipdata->mmdb);
442 static int GeoipParseTest(
const char *rule,
int ncountries,
const char **countries, uint32_t
flags)
446 DetectGeoipData *data = NULL;
463 FAIL_IF(data->nlocations!=ncountries);
465 for (
int i=0; i<ncountries; i++)
467 FAIL_IF(strcmp((
char *)data->location[i],countries[i])!=0);
474 static int GeoipParseTest01(
void)
476 const char *ccodes[1] = {
"US"};
477 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US;sid:1;)", 1, ccodes,
478 GEOIP_MATCH_ANY_FLAG);
481 static int GeoipParseTest02(
void)
483 const char *ccodes[1] = {
"US"};
484 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
485 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
488 static int GeoipParseTest03(
void)
490 const char *ccodes[1] = {
"US"};
491 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
492 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
495 static int GeoipParseTest04(
void)
497 const char *ccodes[1] = {
"US"};
498 return GeoipParseTest(
"alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes,
499 GEOIP_MATCH_SRC_FLAG);
502 static int GeoipParseTest05(
void)
504 const char *ccodes[1] = {
"US"};
505 return GeoipParseTest(
"alert tcp any any -> any any (geoip:dst,!US;sid:1;)", 1, ccodes,
506 GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED);
509 static int GeoipParseTest06(
void)
511 const char *ccodes[3] = {
"US",
"ES",
"UK"};
512 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US,ES,UK;sid:1;)", 3, ccodes,
513 GEOIP_MATCH_ANY_FLAG);
516 static int GeoipParseTest07(
void)
518 const char *ccodes[3] = {
"US",
"ES",
"UK"};
519 return GeoipParseTest(
"alert tcp any any -> any any (geoip:both,!US,ES,UK;sid:1;)", 3, ccodes,
520 GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED);
527 static void DetectGeoipRegisterTests(
void)