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 =
SCCalloc(1,
sizeof(DetectGeoipData));
316 if (
str[pos] ==
',' || pos == slen)
318 if (geoipdata->flags == GEOIP_MATCH_NO_FLAG)
324 skiplocationparsing = 0;
325 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
327 skiplocationparsing = 1;
328 if (strncmp(&
str[prevpos], GEOIP_MATCH_SRC_STR, pos-prevpos) == 0)
329 geoipdata->flags |= GEOIP_MATCH_SRC_FLAG;
330 else if (strncmp(&
str[prevpos], GEOIP_MATCH_DST_STR, pos-prevpos) == 0)
331 geoipdata->flags |= GEOIP_MATCH_DST_FLAG;
332 else if (strncmp(&
str[prevpos], GEOIP_MATCH_BOTH_STR, pos-prevpos) == 0)
333 geoipdata->flags |= GEOIP_MATCH_BOTH_FLAG;
334 else if (strncmp(&
str[prevpos], GEOIP_MATCH_ANY_STR, pos-prevpos) == 0)
335 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
338 skiplocationparsing = 0;
339 geoipdata->flags |= GEOIP_MATCH_ANY_FLAG;
343 if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0)
346 if (
str[prevpos] ==
'!') {
347 geoipdata->flags |= GEOIP_MATCH_NEGATED;
351 if (geoipdata->nlocations >= GEOOPTION_MAXLOCATIONS) {
352 SCLogError(
"too many arguments for geoip keyword");
356 if (pos-prevpos > GEOOPTION_MAXSIZE)
357 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
360 strlcpy((
char *)geoipdata->location[geoipdata->nlocations], &
str[prevpos],
363 if (geoipdata->nlocations < GEOOPTION_MAXLOCATIONS)
364 geoipdata->nlocations++;
367 skiplocationparsing = 0;
372 SCLogDebug(
"GeoIP: %"PRIu32
" countries loaded", geoipdata->nlocations);
373 for (
int i=0; i<geoipdata->nlocations; i++)
374 SCLogDebug(
"GeoIP country code: %s", geoipdata->location[i]);
377 if (geoipdata->flags & GEOIP_MATCH_NEGATED) {
384 if (InitGeolocationEngine(geoipdata) ==
false)
391 if (geoipdata != NULL)
392 DetectGeoipDataFree(
de_ctx, geoipdata);
409 DetectGeoipData *geoipdata = NULL;
411 geoipdata = DetectGeoipDataParse(
de_ctx, optstr);
412 if (geoipdata == NULL)
426 if (geoipdata != NULL)
427 DetectGeoipDataFree(
de_ctx, geoipdata);
440 DetectGeoipData *geoipdata = (DetectGeoipData *)ptr;
441 if (geoipdata->mmdb_status == MMDB_SUCCESS)
442 MMDB_close(&geoipdata->mmdb);
449 static int GeoipParseTest(
const char *rule,
int ncountries,
const char **countries, uint32_t
flags)
453 DetectGeoipData *data = NULL;
470 FAIL_IF(data->nlocations!=ncountries);
472 for (
int i=0; i<ncountries; i++)
474 FAIL_IF(strcmp((
char *)data->location[i],countries[i])!=0);
481 static int GeoipParseTest01(
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);
488 static int GeoipParseTest02(
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 GeoipParseTest03(
void)
497 const char *ccodes[1] = {
"US"};
498 return GeoipParseTest(
"alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes,
499 GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED);
502 static int GeoipParseTest04(
void)
504 const char *ccodes[1] = {
"US"};
505 return GeoipParseTest(
"alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes,
506 GEOIP_MATCH_SRC_FLAG);
509 static int GeoipParseTest05(
void)
511 const char *ccodes[1] = {
"US"};
512 return GeoipParseTest(
"alert tcp any any -> any any (geoip:dst,!US;sid:1;)", 1, ccodes,
513 GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED);
516 static int GeoipParseTest06(
void)
518 const char *ccodes[3] = {
"US",
"ES",
"UK"};
519 return GeoipParseTest(
"alert tcp any any -> any any (geoip:US,ES,UK;sid:1;)", 3, ccodes,
520 GEOIP_MATCH_ANY_FLAG);
523 static int GeoipParseTest07(
void)
525 const char *ccodes[3] = {
"US",
"ES",
"UK"};
526 return GeoipParseTest(
"alert tcp any any -> any any (geoip:both,!US,ES,UK;sid:1;)", 3, ccodes,
527 GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED);
534 static void DetectGeoipRegisterTests(
void)