]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
geoip: move mmdb logic to separate file
authorMark Karpilovskij <mark.karpilovskij@nic.cz>
Wed, 11 Jul 2018 08:34:09 +0000 (10:34 +0200)
committerMark Karpilovskij <mark.karpilovskij@nic.cz>
Sun, 22 Jul 2018 21:44:56 +0000 (23:44 +0200)
Knot.files
src/knot/modules/geoip/geodb.h [new file with mode: 0644]
src/knot/modules/geoip/geoip.c

index b00ad8a193368415e138767ae27d59d3feb19edb..590ad1ad6ba5b6911a58170d040d409d2669ccdd 100644 (file)
@@ -144,6 +144,7 @@ src/knot/journal/serialization.h
 src/knot/modules/cookies/cookies.c
 src/knot/modules/dnsproxy/dnsproxy.c
 src/knot/modules/dnstap/dnstap.c
+src/knot/modules/geoip/geodb.h
 src/knot/modules/geoip/geoip.c
 src/knot/modules/noudp/noudp.c
 src/knot/modules/onlinesign/nsec_next.c
diff --git a/src/knot/modules/geoip/geodb.h b/src/knot/modules/geoip/geodb.h
new file mode 100644 (file)
index 0000000..a339eeb
--- /dev/null
@@ -0,0 +1,104 @@
+/*  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;
+}
index 37049ab08c479f97cfacdf4531cf576a20fee2fc..84b572813cedebb9ab1fc761e53b7f68e67f462e 100644 (file)
@@ -24,6 +24,7 @@
 #include "contrib/openbsd/strlcpy.h"
 #include "contrib/string.h"
 #include "libzscanner/scanner.h"
+#include "geodb.h"
 
 // Next dependecies force static module!
 #include "knot/dnssec/rrset-sign.h"
@@ -51,13 +52,6 @@ static const knot_lookup_t modes[] = {
        { 0, NULL }
 };
 
-enum geodb_key {
-       CONTINENT,
-       COUNTRY,
-       CITY,
-       ISP
-};
-
 static const knot_lookup_t geodb_keys[] = {
        { CONTINENT, "continent" },
        { COUNTRY, "country" },
@@ -104,9 +98,7 @@ typedef struct {
        zone_keyset_t keyset;
        kdnssec_ctx_t kctx;
 
-#if HAVE_MAXMINDDB
-       MMDB_s db;
-#endif
+       void *geodb;
 } geoip_ctx_t;
 
 typedef struct {
@@ -534,9 +526,8 @@ void clear_geo_ctx(geoip_ctx_t *ctx)
 {
        kdnssec_ctx_deinit(&ctx->kctx);
        free_zone_keys(&ctx->keyset);
-#if HAVE_MAXMINDDB
-       MMDB_close(&ctx->db);
-#endif
+       geodb_close(ctx->geodb);
+       free(ctx->geodb);
        clear_geo_trie(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,
        }
 
        if (ctx->mode == MODE_GEODB) {
-#if HAVE_MAXMINDDB
-               int mmdb_error = 0;
-               MMDB_lookup_result_s res;
-               res = MMDB_lookup_sockaddr(&ctx->db, (struct sockaddr *)remote, &mmdb_error);
-               if (mmdb_error != MMDB_SUCCESS) {
-                       knotd_mod_log(mod, LOG_ERR, "a lookup error in MMDB occured");
-                       return state;
-               }
-               if (!res.found_entry) {
+               geo_view_t remote_view;
+               uint16_t netmask;
+               int ret = geodb_query(ctx->geodb, (struct sockaddr *)remote, ctx->keys, ctx->keyc,
+                                     remote_view.geodata, remote_view.geodata_len, &netmask);
+               if (ret != 0) {
                        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;
                knot_rrset_t *rr = NULL;
                knot_rrset_t *rrsig = NULL;
                // Check whether the remote falls into any geo location.
                for (int i = 0; i < data->count; 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++) {
                                        if (view->rrsets[j].type == qtype) {
                                                best_depth = view->geodepth;
@@ -657,7 +624,7 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt,
                if (rr != NULL) {
                        // Update ECS if used.
                        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);
@@ -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;
                }
-#endif
        }
 
        return state;
@@ -691,14 +657,14 @@ int geoip_load(knotd_mod_t *mod)
        int ret;
 
        if (ctx->mode == MODE_GEODB) {
-#if HAVE_MAXMINDDB // Initialize geodb if configured.
+               // Initialize geodb.
                conf = knotd_conf_mod(mod, MOD_GEODB_FILE);
-               ret = MMDB_open(conf.single.string, MMDB_MODE_MMAP, &ctx->db);
-               if (ret != MMDB_SUCCESS) {
+               ctx->geodb = geodb_open(conf.single.string);
+               if (ctx->geodb == NULL) {
                        knotd_mod_log(mod, LOG_ERR, "failed to open Geo DB");
                        return KNOT_EINVAL;
                }
-#endif
+
                // Load configured geodb keys.
                conf = knotd_conf_mod(mod, MOD_GEODB_KEY);
                ctx->keyc = conf.count;