Commit f4e6b90a authored by Mark Karpilovskij's avatar Mark Karpilovskij

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
parent 543af38b
......@@ -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
......
......@@ -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);
......
......@@ -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;
......
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