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;
258 if (geoipdata->flags & ( GEOIP_MATCH_SRC_FLAG | GEOIP_MATCH_BOTH_FLAG ))
262 if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG)
268 if (geoipdata->flags & ( GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_BOTH_FLAG ))
272 if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG)
297 DetectGeoipData *geoipdata = NULL;
299 uint16_t prevpos = 0;
301 int skiplocationparsing = 0;
308 geoipdata =
SCMalloc(
sizeof(DetectGeoipData));
312 memset(geoipdata, 0x00,
sizeof(DetectGeoipData));
318 if (
str[pos] ==
',' || pos == slen)
320 if (geoipdata->flags == GEOIP_MATCH_NO_FLAG)
326 skiplocationparsing = 0;
327 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
329 skiplocationparsing = 1;
330 if (strncmp(&
str[prevpos], GEOIP_MATCH_SRC_STR, pos-prevpos) == 0)
331 geoipdata->flags |= GEOIP_MATCH_SRC_FLAG;
332 else if (strncmp(&
str[prevpos], GEOIP_MATCH_DST_STR, pos-prevpos) == 0)
333 geoipdata->flags |= GEOIP_MATCH_DST_FLAG;
334 else if (strncmp(&
str[prevpos], GEOIP_MATCH_BOTH_STR, pos-prevpos) == 0)
335 geoipdata->flags |= GEOIP_MATCH_BOTH_FLAG;
336 else if (strncmp(&
str[prevpos], GEOIP_MATCH_ANY_STR, pos-prevpos) == 0)
337 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
340 skiplocationparsing = 0;
341 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
345 if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0)
348 if (
str[prevpos] ==
'!') {
349 geoipdata->flags |= GEOIP_MATCH_NEGATED;
353 if (geoipdata->nlocations >= GEOOPTION_MAXLOCATIONS) {
354 SCLogError(
"too many arguments for geoip keyword");
358 if (pos-prevpos > GEOOPTION_MAXSIZE)
359 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
362 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
365 if (geoipdata->nlocations < GEOOPTION_MAXLOCATIONS)
366 geoipdata->nlocations++;
369 skiplocationparsing = 0;
374 SCLogDebug(
"GeoIP: %"PRIu32
" countries loaded", geoipdata->nlocations);
375 for (
int i=0; i<geoipdata->nlocations; i++)
376 SCLogDebug(
"GeoIP country code: %s", geoipdata->location[i]);
379 if (geoipdata->flags & GEOIP_MATCH_NEGATED) {
386 if (InitGeolocationEngine(geoipdata) ==
false)
393 if (geoipdata != NULL)
394 DetectGeoipDataFree(
de_ctx, geoipdata);
411 DetectGeoipData *geoipdata = NULL;
414 geoipdata = DetectGeoipDataParse(
de_ctx, optstr);
415 if (geoipdata == NULL)
432 if (geoipdata != NULL)
433 DetectGeoipDataFree(
de_ctx, geoipdata);
448 DetectGeoipData *geoipdata = (DetectGeoipData *)ptr;
449 if (geoipdata->mmdb_status == MMDB_SUCCESS)
450 MMDB_close(&geoipdata->mmdb);
457 static int GeoipParseTest(
const char *rule,
int ncountries,
const char **countries, uint32_t
flags)
461 DetectGeoipData *data = NULL;
478 FAIL_IF(data->nlocations!=ncountries);
480 for (
int i=0; i<ncountries; i++)
482 FAIL_IF(strcmp((
char *)data->location[i],countries[i])!=0);
489 static int GeoipParseTest01(
void)
491 const char *ccodes[1] = {
"US"};
492 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US;sid:1;)", 1, ccodes,
493 GEOIP_MATCH_ANY_FLAG);
496 static int GeoipParseTest02(
void)
498 const char *ccodes[1] = {
"US"};
499 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
500 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
503 static int GeoipParseTest03(
void)
505 const char *ccodes[1] = {
"US"};
506 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
507 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
510 static int GeoipParseTest04(
void)
512 const char *ccodes[1] = {
"US"};
513 return GeoipParseTest(
"alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes,
514 GEOIP_MATCH_SRC_FLAG);
517 static int GeoipParseTest05(
void)
519 const char *ccodes[1] = {
"US"};
520 return GeoipParseTest(
"alert tcp any any -> any any (geoip:dst,!US;sid:1;)", 1, ccodes,
521 GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED);
524 static int GeoipParseTest06(
void)
526 const char *ccodes[3] = {
"US",
"ES",
"UK"};
527 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US,ES,UK;sid:1;)", 3, ccodes,
528 GEOIP_MATCH_ANY_FLAG);
531 static int GeoipParseTest07(
void)
533 const char *ccodes[3] = {
"US",
"ES",
"UK"};
534 return GeoipParseTest(
"alert tcp any any -> any any (geoip:both,!US,ES,UK;sid:1;)", 3, ccodes,
535 GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED);
542 static void DetectGeoipRegisterTests(
void)