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)
SCConfGet(
"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;
253 if (PacketIsIPv4(p)) {
254 if (geoipdata->flags & ( GEOIP_MATCH_SRC_FLAG | GEOIP_MATCH_BOTH_FLAG ))
258 if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG)
264 if (geoipdata->flags & ( GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_BOTH_FLAG ))
268 if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG)
293 DetectGeoipData *geoipdata = NULL;
295 uint16_t prevpos = 0;
297 int skiplocationparsing = 0;
304 geoipdata =
SCCalloc(1,
sizeof(DetectGeoipData));
312 if (
str[pos] ==
',' || pos == slen)
314 if (geoipdata->flags == GEOIP_MATCH_NO_FLAG)
320 skiplocationparsing = 0;
321 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
323 skiplocationparsing = 1;
324 if (strncmp(&
str[prevpos], GEOIP_MATCH_SRC_STR, pos-prevpos) == 0)
325 geoipdata->flags |= GEOIP_MATCH_SRC_FLAG;
326 else if (strncmp(&
str[prevpos], GEOIP_MATCH_DST_STR, pos-prevpos) == 0)
327 geoipdata->flags |= GEOIP_MATCH_DST_FLAG;
328 else if (strncmp(&
str[prevpos], GEOIP_MATCH_BOTH_STR, pos-prevpos) == 0)
329 geoipdata->flags |= GEOIP_MATCH_BOTH_FLAG;
330 else if (strncmp(&
str[prevpos], GEOIP_MATCH_ANY_STR, pos-prevpos) == 0)
331 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
334 skiplocationparsing = 0;
335 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
339 if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0)
342 if (
str[prevpos] ==
'!') {
343 geoipdata->flags |= GEOIP_MATCH_NEGATED;
347 if (geoipdata->nlocations >= GEOOPTION_MAXLOCATIONS) {
348 SCLogError(
"too many arguments for geoip keyword");
352 if (pos-prevpos > GEOOPTION_MAXSIZE)
353 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
356 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
359 if (geoipdata->nlocations < GEOOPTION_MAXLOCATIONS)
360 geoipdata->nlocations++;
363 skiplocationparsing = 0;
368 SCLogDebug(
"GeoIP: %"PRIu32
" countries loaded", geoipdata->nlocations);
369 for (
int i=0; i<geoipdata->nlocations; i++)
370 SCLogDebug(
"GeoIP country code: %s", geoipdata->location[i]);
373 if (geoipdata->flags & GEOIP_MATCH_NEGATED) {
380 if (!InitGeolocationEngine(geoipdata))
387 if (geoipdata != NULL)
388 DetectGeoipDataFree(
de_ctx, geoipdata);
405 DetectGeoipData *geoipdata = NULL;
407 geoipdata = DetectGeoipDataParse(
de_ctx, optstr);
408 if (geoipdata == NULL)
421 if (geoipdata != NULL)
422 DetectGeoipDataFree(
de_ctx, geoipdata);
435 DetectGeoipData *geoipdata = (DetectGeoipData *)ptr;
436 if (geoipdata->mmdb_status == MMDB_SUCCESS)
437 MMDB_close(&geoipdata->mmdb);
444 static int GeoipParseTest(
const char *rule,
int ncountries,
const char **countries, uint32_t
flags)
448 DetectGeoipData *data = NULL;
465 FAIL_IF(data->nlocations!=ncountries);
467 for (
int i=0; i<ncountries; i++)
469 FAIL_IF(strcmp((
char *)data->location[i],countries[i])!=0);
476 static int GeoipParseTest01(
void)
478 const char *ccodes[1] = {
"US"};
479 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US;sid:1;)", 1, ccodes,
480 GEOIP_MATCH_ANY_FLAG);
483 static int GeoipParseTest02(
void)
485 const char *ccodes[1] = {
"US"};
486 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
487 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
490 static int GeoipParseTest03(
void)
492 const char *ccodes[1] = {
"US"};
493 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
494 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
497 static int GeoipParseTest04(
void)
499 const char *ccodes[1] = {
"US"};
500 return GeoipParseTest(
"alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes,
501 GEOIP_MATCH_SRC_FLAG);
504 static int GeoipParseTest05(
void)
506 const char *ccodes[1] = {
"US"};
507 return GeoipParseTest(
"alert tcp any any -> any any (geoip:dst,!US;sid:1;)", 1, ccodes,
508 GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED);
511 static int GeoipParseTest06(
void)
513 const char *ccodes[3] = {
"US",
"ES",
"UK"};
514 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US,ES,UK;sid:1;)", 3, ccodes,
515 GEOIP_MATCH_ANY_FLAG);
518 static int GeoipParseTest07(
void)
520 const char *ccodes[3] = {
"US",
"ES",
"UK"};
521 return GeoipParseTest(
"alert tcp any any -> any any (geoip:both,!US,ES,UK;sid:1;)", 3, ccodes,
522 GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED);
529 static void DetectGeoipRegisterTests(
void)