From: Mark Karpilovskij Date: Fri, 20 Jul 2018 10:06:17 +0000 (+0200) Subject: geoip: multiple improvements X-Git-Tag: v2.7.0~24^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f4e6b90a076586bfb6cc646d74c8ff4b8bec12ca;p=thirdparty%2Fknot-dns.git geoip: multiple improvements - 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 --- diff --git a/src/knot/modules/geoip/geodb.c b/src/knot/modules/geoip/geodb.c index e4ffbaf657..1c910f30d5 100644 --- a/src/knot/modules/geoip/geodb.c +++ b/src/knot/modules/geoip/geodb.c @@ -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 diff --git a/src/knot/modules/geoip/geodb.h b/src/knot/modules/geoip/geodb.h index a5f9cc1ecb..80940d3ec5 100644 --- a/src/knot/modules/geoip/geodb.h +++ b/src/knot/modules/geoip/geodb.h @@ -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); diff --git a/src/knot/modules/geoip/geoip.c b/src/knot/modules/geoip/geoip.c index 1a6f1085af..4a026a9c19 100644 --- a/src/knot/modules/geoip/geoip.c +++ b/src/knot/modules/geoip/geoip.c @@ -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;