Commit c84661c8 authored by Mark Karpilovskij's avatar Mark Karpilovskij

geoip: move mmdb logic to separate file

parent 7b2ff05f
...@@ -144,6 +144,7 @@ src/knot/journal/serialization.h ...@@ -144,6 +144,7 @@ src/knot/journal/serialization.h
src/knot/modules/cookies/cookies.c src/knot/modules/cookies/cookies.c
src/knot/modules/dnsproxy/dnsproxy.c src/knot/modules/dnsproxy/dnsproxy.c
src/knot/modules/dnstap/dnstap.c src/knot/modules/dnstap/dnstap.c
src/knot/modules/geoip/geodb.h
src/knot/modules/geoip/geoip.c src/knot/modules/geoip/geoip.c
src/knot/modules/noudp/noudp.c src/knot/modules/noudp/noudp.c
src/knot/modules/onlinesign/nsec_next.c src/knot/modules/onlinesign/nsec_next.c
......
/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if HAVE_MAXMINDDB
#include <maxminddb.h>
#endif
enum geodb_key {
CONTINENT,
COUNTRY,
CITY,
ISP
};
// MaxMind DB related constants.
#define MAX_PATH_LEN 4
#define GEODB_KEYS 4
typedef struct {
const char *path[MAX_PATH_LEN];
}mmdb_path_t;
mmdb_path_t paths[] = {
{{"continent", "code", NULL}},
{{"country", "iso_code", NULL}},
{{"city", "names", "en", NULL}},
{{"isp", NULL}}
};
void *geodb_open(const char *filename)
{
#if HAVE_MAXMINDDB
MMDB_s *db = calloc(1, sizeof(MMDB_s));
if (db == NULL) {
return NULL;
}
int mmdb_error = MMDB_open(filename, MMDB_MODE_MMAP, db);
if (mmdb_error != MMDB_SUCCESS) {
return NULL;
}
return (void *)db;
#endif
return NULL;
}
void geodb_close(void *geodb)
{
#if HAVE_MAXMINDDB
MMDB_s *db = (MMDB_s *)geodb;
MMDB_close(db);
#endif
}
int geodb_query(void *geodb, struct sockaddr *remote,
enum geodb_key *keys, uint16_t keyc,
char **geodata, uint32_t *geodata_len, uint16_t *netmask)
{
#if HAVE_MAXMINDDB
MMDB_s *db = (MMDB_s *)geodb;
int mmdb_error = 0;
MMDB_lookup_result_s res;
res = MMDB_lookup_sockaddr(db, remote, &mmdb_error);
if (mmdb_error != MMDB_SUCCESS || !res.found_entry) {
return -1;
}
// Save netmask.
*netmask = res.netmask;
MMDB_entry_data_s entry;
// Set the remote's geo information.
for (uint16_t i = 0; i < keyc; i++) {
enum geodb_key key = keys[i];
geodata[key] = NULL;
mmdb_error = MMDB_aget_value(&res.entry, &entry, paths[key].path);
if (mmdb_error != MMDB_SUCCESS &&
mmdb_error != MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR) {
return -1;
}
if (mmdb_error == MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR ||
!entry.has_data || entry.type != MMDB_DATA_TYPE_UTF8_STRING) {
continue;
}
geodata[key] = (char *)entry.utf8_string;
geodata_len[key] = entry.data_size;
}
return 0;
#endif
return -1;
}
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "contrib/openbsd/strlcpy.h" #include "contrib/openbsd/strlcpy.h"
#include "contrib/string.h" #include "contrib/string.h"
#include "libzscanner/scanner.h" #include "libzscanner/scanner.h"
#include "geodb.h"
// Next dependecies force static module! // Next dependecies force static module!
#include "knot/dnssec/rrset-sign.h" #include "knot/dnssec/rrset-sign.h"
...@@ -51,13 +52,6 @@ static const knot_lookup_t modes[] = { ...@@ -51,13 +52,6 @@ static const knot_lookup_t modes[] = {
{ 0, NULL } { 0, NULL }
}; };
enum geodb_key {
CONTINENT,
COUNTRY,
CITY,
ISP
};
static const knot_lookup_t geodb_keys[] = { static const knot_lookup_t geodb_keys[] = {
{ CONTINENT, "continent" }, { CONTINENT, "continent" },
{ COUNTRY, "country" }, { COUNTRY, "country" },
...@@ -104,9 +98,7 @@ typedef struct { ...@@ -104,9 +98,7 @@ typedef struct {
zone_keyset_t keyset; zone_keyset_t keyset;
kdnssec_ctx_t kctx; kdnssec_ctx_t kctx;
#if HAVE_MAXMINDDB void *geodb;
MMDB_s db;
#endif
} geoip_ctx_t; } geoip_ctx_t;
typedef struct { typedef struct {
...@@ -534,9 +526,8 @@ void clear_geo_ctx(geoip_ctx_t *ctx) ...@@ -534,9 +526,8 @@ void clear_geo_ctx(geoip_ctx_t *ctx)
{ {
kdnssec_ctx_deinit(&ctx->kctx); kdnssec_ctx_deinit(&ctx->kctx);
free_zone_keys(&ctx->keyset); free_zone_keys(&ctx->keyset);
#if HAVE_MAXMINDDB geodb_close(ctx->geodb);
MMDB_close(&ctx->db); free(ctx->geodb);
#endif
clear_geo_trie(ctx->geo_trie); clear_geo_trie(ctx->geo_trie);
trie_free(ctx->geo_trie); trie_free(ctx->geo_trie);
} }
...@@ -603,45 +594,21 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt, ...@@ -603,45 +594,21 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt,
} }
if (ctx->mode == MODE_GEODB) { if (ctx->mode == MODE_GEODB) {
#if HAVE_MAXMINDDB geo_view_t remote_view;
int mmdb_error = 0; uint16_t netmask;
MMDB_lookup_result_s res; int ret = geodb_query(ctx->geodb, (struct sockaddr *)remote, ctx->keys, ctx->keyc,
res = MMDB_lookup_sockaddr(&ctx->db, (struct sockaddr *)remote, &mmdb_error); remote_view.geodata, remote_view.geodata_len, &netmask);
if (mmdb_error != MMDB_SUCCESS) { if (ret != 0) {
knotd_mod_log(mod, LOG_ERR, "a lookup error in MMDB occured");
return state;
}
if (!res.found_entry) {
return state; return state;
} }
geo_view_t client_view;
MMDB_entry_data_s entry;
// Set the remote's geo information.
for (uint16_t i = 0; i < ctx->keyc; i++) {
enum geodb_key key = ctx->keys[i];
client_view.geodata[key] = NULL;
mmdb_error = MMDB_aget_value(&res.entry, &entry, paths[key].path);
if (mmdb_error != MMDB_SUCCESS &&
mmdb_error != MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR) {
knotd_mod_log(mod, LOG_ERR, "an entry error in MMDB occured (%s)", geodb_keys[key].name);
return state;
}
if (mmdb_error == MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR ||
!entry.has_data || entry.type != MMDB_DATA_TYPE_UTF8_STRING) {
continue;
}
client_view.geodata[key] = (char *)entry.utf8_string;
client_view.geodata_len[key] = entry.data_size;
}
uint8_t best_depth = 0; uint8_t best_depth = 0;
knot_rrset_t *rr = NULL; knot_rrset_t *rr = NULL;
knot_rrset_t *rrsig = NULL; knot_rrset_t *rrsig = NULL;
// Check whether the remote falls into any geo location. // Check whether the remote falls into any geo location.
for (int i = 0; i < data->count; i++) { for (int i = 0; i < data->count; i++) {
geo_view_t *view = &data->views[i]; geo_view_t *view = &data->views[i];
if (addr_in_geo(ctx, view, &client_view) && view->geodepth >= best_depth) { if (addr_in_geo(ctx, view, &remote_view) && view->geodepth >= best_depth) {
for (int j = 0; j < view->count; j++) { for (int j = 0; j < view->count; j++) {
if (view->rrsets[j].type == qtype) { if (view->rrsets[j].type == qtype) {
best_depth = view->geodepth; best_depth = view->geodepth;
...@@ -657,7 +624,7 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt, ...@@ -657,7 +624,7 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt,
if (rr != NULL) { if (rr != NULL) {
// Update ECS if used. // Update ECS if used.
if (qdata->ecs != NULL) { if (qdata->ecs != NULL) {
qdata->ecs->scope_len = res.netmask; qdata->ecs->scope_len = netmask;
} }
knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, rr, 0); knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, rr, 0);
...@@ -666,7 +633,6 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt, ...@@ -666,7 +633,6 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt,
} }
return KNOTD_IN_STATE_HIT; return KNOTD_IN_STATE_HIT;
} }
#endif
} }
return state; return state;
...@@ -691,14 +657,14 @@ int geoip_load(knotd_mod_t *mod) ...@@ -691,14 +657,14 @@ int geoip_load(knotd_mod_t *mod)
int ret; int ret;
if (ctx->mode == MODE_GEODB) { if (ctx->mode == MODE_GEODB) {
#if HAVE_MAXMINDDB // Initialize geodb if configured. // Initialize geodb.
conf = knotd_conf_mod(mod, MOD_GEODB_FILE); conf = knotd_conf_mod(mod, MOD_GEODB_FILE);
ret = MMDB_open(conf.single.string, MMDB_MODE_MMAP, &ctx->db); ctx->geodb = geodb_open(conf.single.string);
if (ret != MMDB_SUCCESS) { if (ctx->geodb == NULL) {
knotd_mod_log(mod, LOG_ERR, "failed to open Geo DB"); knotd_mod_log(mod, LOG_ERR, "failed to open Geo DB");
return KNOT_EINVAL; return KNOT_EINVAL;
} }
#endif
// Load configured geodb keys. // Load configured geodb keys.
conf = knotd_conf_mod(mod, MOD_GEODB_KEY); conf = knotd_conf_mod(mod, MOD_GEODB_KEY);
ctx->keyc = conf.count; ctx->keyc = conf.count;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment