46 SCLogError(
"no GeoIP support built in, needed for geoip keyword");
57 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";
65 #include <maxminddb.h>
71 static void DetectGeoipRegisterTests(
void);
98 static bool InitGeolocationEngine(DetectGeoipData *geoipdata)
100 const char *filename = NULL;
103 (void)
ConfGet(
"geoip-database", &filename);
105 if (filename == NULL) {
107 "database filename in YAML conf. GeoIP rule matching "
109 geoipdata->mmdb_status = MMDB_FILE_OPEN_ERROR;
114 int status = MMDB_open(filename, MMDB_MODE_MMAP, &geoipdata->mmdb);
116 if (status == MMDB_SUCCESS) {
117 geoipdata->mmdb_status = status;
122 "Error was: %s. GeoIP rule matching is disabled.",
123 filename, MMDB_strerror(status));
124 geoipdata->mmdb_status = status;
137 static const char *GeolocateIPv4(
const DetectGeoipData *geoipdata, uint32_t ip)
140 struct sockaddr_in sa;
141 sa.sin_family = AF_INET;
143 sa.sin_addr.s_addr = ip;
144 MMDB_lookup_result_s result;
145 MMDB_entry_data_s entry_data;
148 if (geoipdata->mmdb_status != MMDB_SUCCESS)
152 result = MMDB_lookup_sockaddr((MMDB_s *)&geoipdata->mmdb,
153 (
struct sockaddr*)&sa, &mmdb_error);
154 if (mmdb_error != MMDB_SUCCESS)
158 if (result.found_entry) {
159 mmdb_error = MMDB_get_value(&result.entry, &entry_data,
"country",
161 if (mmdb_error != MMDB_SUCCESS)
165 if (entry_data.has_data) {
166 if (entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
167 char *country_code =
SCStrndup((
char *)entry_data.utf8_string,
168 entry_data.data_size);
179 #define GEOIP_MATCH_SRC_STR "src"
180 #define GEOIP_MATCH_DST_STR "dst"
181 #define GEOIP_MATCH_BOTH_STR "both"
182 #define GEOIP_MATCH_ANY_STR "any"
184 #define GEOIP_MATCH_NO_FLAG 0
185 #define GEOIP_MATCH_SRC_FLAG 1
186 #define GEOIP_MATCH_DST_FLAG 2
187 #define GEOIP_MATCH_ANY_FLAG 3
188 #define GEOIP_MATCH_BOTH_FLAG 4
189 #define GEOIP_MATCH_NEGATED 8
200 static int CheckGeoMatchIPv4(
const DetectGeoipData *geoipdata, uint32_t ip)
205 const char *country = GeolocateIPv4(geoipdata, ip);
212 if ((geoipdata->flags & GEOIP_MATCH_NEGATED) == 0)
214 for (i = 0; i < geoipdata->nlocations; i++) {
215 if (strcmp(country, (
char *)geoipdata->location[i])==0) {
222 for (i = 0; i < geoipdata->nlocations; i++) {
223 if (strcmp(country, (
char *)geoipdata->location[i])==0) {
250 const DetectGeoipData *geoipdata = (
const DetectGeoipData *)
ctx;
255 if (PacketIsIPv4(p)) {
256 if (geoipdata->flags & ( GEOIP_MATCH_SRC_FLAG | GEOIP_MATCH_BOTH_FLAG ))
260 if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG)
266 if (geoipdata->flags & ( GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_BOTH_FLAG ))
270 if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG)
295 DetectGeoipData *geoipdata = NULL;
297 uint16_t prevpos = 0;
299 int skiplocationparsing = 0;
306 geoipdata =
SCCalloc(1,
sizeof(DetectGeoipData));
314 if (
str[pos] ==
',' || pos == slen)
316 if (geoipdata->flags == GEOIP_MATCH_NO_FLAG)
322 skiplocationparsing = 0;
323 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
325 skiplocationparsing = 1;
326 if (strncmp(&
str[prevpos], GEOIP_MATCH_SRC_STR, pos-prevpos) == 0)
327 geoipdata->flags |= GEOIP_MATCH_SRC_FLAG;
328 else if (strncmp(&
str[prevpos], GEOIP_MATCH_DST_STR, pos-prevpos) == 0)
329 geoipdata->flags |= GEOIP_MATCH_DST_FLAG;
330 else if (strncmp(&
str[prevpos], GEOIP_MATCH_BOTH_STR, pos-prevpos) == 0)
331 geoipdata->flags |= GEOIP_MATCH_BOTH_FLAG;
332 else if (strncmp(&
str[prevpos], GEOIP_MATCH_ANY_STR, pos-prevpos) == 0)
333 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
336 skiplocationparsing = 0;
337 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
341 if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0)
344 if (
str[prevpos] ==
'!') {
345 geoipdata->flags |= GEOIP_MATCH_NEGATED;
349 if (geoipdata->nlocations >= GEOOPTION_MAXLOCATIONS) {
350 SCLogError(
"too many arguments for geoip keyword");
354 if (pos-prevpos > GEOOPTION_MAXSIZE)
355 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
358 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
361 if (geoipdata->nlocations < GEOOPTION_MAXLOCATIONS)
362 geoipdata->nlocations++;
365 skiplocationparsing = 0;
370 SCLogDebug(
"GeoIP: %"PRIu32
" countries loaded", geoipdata->nlocations);
371 for (
int i=0; i<geoipdata->nlocations; i++)
372 SCLogDebug(
"GeoIP country code: %s", geoipdata->location[i]);
375 if (geoipdata->flags & GEOIP_MATCH_NEGATED) {
382 if (InitGeolocationEngine(geoipdata) ==
false)
389 if (geoipdata != NULL)
390 DetectGeoipDataFree(
de_ctx, geoipdata);
407 DetectGeoipData *geoipdata = NULL;
409 geoipdata = DetectGeoipDataParse(
de_ctx, optstr);
410 if (geoipdata == NULL)
424 if (geoipdata != NULL)
425 DetectGeoipDataFree(
de_ctx, geoipdata);
438 DetectGeoipData *geoipdata = (DetectGeoipData *)ptr;
439 if (geoipdata->mmdb_status == MMDB_SUCCESS)
440 MMDB_close(&geoipdata->mmdb);
447 static int GeoipParseTest(
const char *rule,
int ncountries,
const char **countries, uint32_t
flags)
451 DetectGeoipData *data = NULL;
468 FAIL_IF(data->nlocations!=ncountries);
470 for (
int i=0; i<ncountries; i++)
472 FAIL_IF(strcmp((
char *)data->location[i],countries[i])!=0);
479 static int GeoipParseTest01(
void)
481 const char *ccodes[1] = {
"US"};
482 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US;sid:1;)", 1, ccodes,
483 GEOIP_MATCH_ANY_FLAG);
486 static int GeoipParseTest02(
void)
488 const char *ccodes[1] = {
"US"};
489 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
490 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
493 static int GeoipParseTest03(
void)
495 const char *ccodes[1] = {
"US"};
496 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
497 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
500 static int GeoipParseTest04(
void)
502 const char *ccodes[1] = {
"US"};
503 return GeoipParseTest(
"alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes,
504 GEOIP_MATCH_SRC_FLAG);
507 static int GeoipParseTest05(
void)
509 const char *ccodes[1] = {
"US"};
510 return GeoipParseTest(
"alert tcp any any -> any any (geoip:dst,!US;sid:1;)", 1, ccodes,
511 GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED);
514 static int GeoipParseTest06(
void)
516 const char *ccodes[3] = {
"US",
"ES",
"UK"};
517 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US,ES,UK;sid:1;)", 3, ccodes,
518 GEOIP_MATCH_ANY_FLAG);
521 static int GeoipParseTest07(
void)
523 const char *ccodes[3] = {
"US",
"ES",
"UK"};
524 return GeoipParseTest(
"alert tcp any any -> any any (geoip:both,!US,ES,UK;sid:1;)", 3, ccodes,
525 GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED);
532 static void DetectGeoipRegisterTests(
void)