]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
geoip: multiple improvements
authorMark Karpilovskij <mark.karpilovskij@nic.cz>
Fri, 20 Jul 2018 10:06:17 +0000 (12:06 +0200)
committerMark Karpilovskij <mark.karpilovskij@nic.cz>
Mon, 23 Jul 2018 08:49:26 +0000 (10:49 +0200)
- DNSSEC RRs forbidden in geo config
- exit processing if query answered by previous module
- use lookup format of dnames in trie
- check the correct "geo" or "net" key in config
- unify log messages
- set AA bit if the query is processed succesfuly
- add geodb avilability check

src/knot/modules/geoip/geodb.c
src/knot/modules/geoip/geodb.h
src/knot/modules/geoip/geoip.c

index e4ffbaf657d0895500d92ff8360aa0a3238a6876..1c910f30d54b0b355d03cd1df7be183b25bdfae0 100644 (file)
@@ -112,6 +112,15 @@ int parse_geodb_data(const char *input, void **geodata, uint32_t *geodata_len,
        return 0;
 }
 
+bool geodb_available(void)
+{
+#if HAVE_MAXMINDDB
+       return true;
+#else
+       return false;
+#endif
+}
+
 geodb_t *geodb_open(const char *filename)
 {
 #if HAVE_MAXMINDDB
index a5f9cc1ecb1cd9363fea7b29cbcc8d369d3fd98e..80940d3ec55d250b9e88de6fbb251b07f79d9057 100644 (file)
@@ -53,6 +53,8 @@ int parse_geodb_path(geodb_path_t *path, const char *input);
 int parse_geodb_data(const char *input, void **geodata, uint32_t *geodata_len,
                      uint8_t *geodepth, geodb_path_t *path, uint16_t path_cnt);
 
+bool geodb_available(void);
+
 geodb_t *geodb_open(const char *filename);
 
 geodb_data_t *geodb_alloc_entries(uint16_t count);
index 1a6f1085afc16176c4ffffa159f7a146526c4619..4a026a9c19796454c04ad3857f37f1fa5c1e8b7b 100644 (file)
@@ -23,7 +23,6 @@
 #include "knot/modules/geoip/geodb.h"
 #include "libknot/libknot.h"
 #include "contrib/qp-trie/trie.h"
-#include "contrib/mempattern.h"
 #include "contrib/ucw/lists.h"
 #include "contrib/sockaddr.h"
 #include "contrib/string.h"
@@ -43,10 +42,15 @@ enum operation_mode {
 
 static const knot_lookup_t modes[] = {
        { MODE_SUBNET, "subnet" },
-       { MODE_GEODB, "geodb" },
+       { MODE_GEODB,  "geodb" },
        { 0, NULL }
 };
 
+static const char* mode_key[] = {
+       [MODE_SUBNET] = "net",
+       [MODE_GEODB]  = "geo"
+};
+
 const yp_item_t geoip_conf[] = {
        { MOD_CONFIG_FILE, YP_TSTR, YP_VNONE },
        { MOD_TTL,         YP_TINT, YP_VINT = { 0, UINT32_MAX, 60, YP_STIME } },
@@ -58,7 +62,6 @@ const yp_item_t geoip_conf[] = {
 
 int geoip_conf_check(knotd_conf_check_args_t *args)
 {
-
        knotd_conf_t conf = knotd_conf_check_item(args, MOD_CONFIG_FILE);
        if (conf.count == 0) {
                args->err_str = "no configuration file specified";
@@ -66,6 +69,10 @@ int geoip_conf_check(knotd_conf_check_args_t *args)
        }
        conf = knotd_conf_check_item(args, MOD_MODE);
        if (conf.count == 1 && conf.single.option == MODE_GEODB) {
+               if (!geodb_available()) {
+                       args->err_str = "geodb mode not available";
+                       return KNOT_EINVAL;
+               }
                conf = knotd_conf_check_item(args, MOD_GEODB_FILE);
                if (conf.count == 0) {
                        args->err_str = "no geodb file specified while in geodb mode";
@@ -110,8 +117,12 @@ static int add_view_to_trie(knot_dname_t *owner, geo_view_t *view, geoip_ctx_t *
        int ret = KNOT_EOK;
 
        // Find the node belonging to the owner.
-       trie_val_t *val = trie_get_ins(ctx->geo_trie, (char *)owner, knot_dname_size(owner));
+       knot_dname_storage_t lf_storage;
+       uint8_t *lf = knot_dname_lf(owner, lf_storage);
+       assert(lf);
+       trie_val_t *val = trie_get_ins(ctx->geo_trie, (char *)lf + 1, *lf);
        geo_trie_val_t *cur_val = *val;
+
        if (cur_val == NULL) {
                // Create new node value.
                geo_trie_val_t *new_val = calloc(1, sizeof(geo_trie_val_t));
@@ -277,6 +288,14 @@ static int parse_view(knotd_mod_t *mod, geoip_ctx_t *ctx, yp_parser_t *yp, geo_v
                return ret;
        }
 
+       // Check view type syntax.
+       int key_len = strlen(mode_key[ctx->mode]);
+       if (yp->key_len != key_len || memcmp(yp->key, mode_key[ctx->mode], key_len) != 0) {
+               knotd_mod_log(mod, LOG_ERR, "invalid key type (%s) on line %zu",
+                             yp->key, yp->line_count);
+               return KNOT_EINVAL;
+       }
+
        // Parse geodata/subnet.
        if (ctx->mode == MODE_GEODB) {
                if (parse_geodb_data((char *)yp->data, view->geodata, view->geodata_len,
@@ -342,8 +361,14 @@ static int parse_rr(knotd_mod_t *mod, yp_parser_t *yp, zs_scanner_t *scanner,
 {
        uint16_t rr_type = KNOT_RRTYPE_A;
        if (knot_rrtype_from_string(yp->key, &rr_type) != 0) {
-               knotd_mod_log(mod, LOG_ERR, "invalid RR type in config on line %zu",
-                             yp->line_count);
+               knotd_mod_log(mod, LOG_ERR, "invalid RR type (%s) on line %zu",
+                             yp->key, yp->line_count);
+               return KNOT_EINVAL;
+       }
+
+       if (knot_rrtype_is_dnssec(rr_type)) {
+               knotd_mod_log(mod, LOG_ERR, "DNSSEC record (%s) not allowed on line %zu",
+                             yp->key, yp->line_count);
                return KNOT_EINVAL;
        }
 
@@ -437,7 +462,8 @@ static int geo_conf_yparse(knotd_mod_t *mod, geoip_ctx_t *ctx)
                        goto cleanup;
                }
                if (ret != KNOT_EOK) {
-                       knotd_mod_log(mod, LOG_ERR, "failed to parse configuration file (%s)", knot_strerror(ret));
+                       knotd_mod_log(mod, LOG_ERR, "failed to parse configuration file (%s)",
+                                     knot_strerror(ret));
                        goto cleanup;
                }
 
@@ -454,7 +480,8 @@ static int geo_conf_yparse(knotd_mod_t *mod, geoip_ctx_t *ctx)
                        owner = knot_dname_from_str(owner_buff, yp->key, sizeof(owner_buff));
                        if (owner == NULL) {
                                ret = KNOT_EINVAL;
-                               knotd_mod_log(mod, LOG_ERR, "invalid domain name in config on line %zu", yp->line_count);
+                               knotd_mod_log(mod, LOG_ERR, "invalid domain name in config on line %zu",
+                                             yp->line_count);
                                goto cleanup;
                        }
                        ret = parse_origin(yp, scanner);
@@ -528,15 +555,24 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt,
 {
        assert(pkt && qdata && mod);
 
+       // Nothing to do if the query was already resolved by a previous module.
+       if (state == KNOTD_IN_STATE_HIT) {
+               return state;
+       }
+
        geoip_ctx_t *ctx = (geoip_ctx_t *)knotd_mod_ctx(mod);
 
        // Save the query type.
        uint16_t qtype = knot_pkt_qtype(qdata->query);
 
        // Check if geolocation is available for given query.
-       knot_dname_t *qname = knot_pkt_qname(qdata->query);
-       size_t qname_len = knot_dname_size(qname);
-       trie_val_t *val = trie_get_try(ctx->geo_trie, (char *)qname, qname_len);
+       knot_dname_storage_t lf_storage;
+       uint8_t *lf = knot_dname_lf(knot_pkt_qname(qdata->query), lf_storage);
+       // Exit if no qname.
+       if (lf == NULL) {
+               return state;
+       }
+       trie_val_t *val = trie_get_try(ctx->geo_trie, (char *)lf + 1, *lf);
        if (val == NULL) {
                // Nothing to do in this module.
                return state;
@@ -628,6 +664,10 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt,
                if (ctx->dnssec && knot_pkt_has_dnssec(qdata->query) && rrsig != NULL) {
                        knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, rrsig, 0);
                }
+
+               // We've got an answer, set the AA bit.
+               knot_wire_set_aa(pkt->wire);
+
                return KNOTD_IN_STATE_HIT;
        }
 
@@ -659,7 +699,7 @@ int geoip_load(knotd_mod_t *mod)
                conf = knotd_conf_mod(mod, MOD_GEODB_FILE);
                ctx->geodb = geodb_open(conf.single.string);
                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");
                        free_geoip_ctx(ctx);
                        return KNOT_EINVAL;
                }
@@ -668,7 +708,8 @@ int geoip_load(knotd_mod_t *mod)
                conf = knotd_conf_mod(mod, MOD_GEODB_KEY);
                ctx->path_count = conf.count;
                if (ctx->path_count > GEODB_MAX_DEPTH) {
-                       knotd_mod_log(mod, LOG_ERR, "maximal number of geodb-key items (%d) exceeded", GEODB_MAX_DEPTH);
+                       knotd_mod_log(mod, LOG_ERR, "maximal number of geodb-key items (%d) exceeded",
+                                     GEODB_MAX_DEPTH);
                        knotd_conf_free(&conf);
                        free_geoip_ctx(ctx);
                        return KNOT_EINVAL;