#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"
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 } },
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";
}
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";
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));
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,
{
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;
}
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;
}
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);
{
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;
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;
}
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;
}
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;