]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
hints: implement .use_nodata(true) and .ttl
authorVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 7 Feb 2022 12:29:50 +0000 (13:29 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 12 Jun 2023 08:32:27 +0000 (10:32 +0200)
fixes modules/dns64 test

lib/rules/api.c
lib/rules/api.h
modules/dns64/dns64.test.lua
modules/hints/README.rst
modules/hints/hints.c

index 1650e6e7a8f8db71e706843e45e40d0f818fa2d6..010751d5a47d03cea654ac6b08c08fc34e24ff91 100644 (file)
@@ -307,6 +307,14 @@ int kr_rule_local_data_answer(struct kr_query *qry, knot_pkt_t *pkt)
        return kr_error(ENOENT);
 }
 
+/** SOA RDATA content, used as default in negative answers.
+ *
+ * It's as recommended except for using a fixed mname (for simplicity):
+       https://tools.ietf.org/html/rfc6303#section-3
+ */
+static const uint8_t soa_rdata[] = "\x09localhost\0\6nobody\7invalid\0"
+       "\0\0\0\1\0\0\x0e\x10\0\0\4\xb0\0\x09\x3a\x80\0\0\x2a\x30";
+
 #define CHECK_RET(ret) do { \
        if ((ret) < 0) { kr_assert(false); return kr_error((ret)); } \
 } while (false)
@@ -334,22 +342,37 @@ static int answer_exact_match(struct kr_query *qry, knot_pkt_t *pkt, uint16_t ty
                return kr_error(ENOMEM);
        ret = rdataset_materialize(&arrset.set.rr->rrs, data, data_bound, &pkt->mm);
        CHECK_RET(ret);
-       const size_t data_off = ret;
+       data += ret;
        arrset.set.rank = KR_RANK_SECURE | KR_RANK_AUTH; // local data has high trust
        arrset.set.expiring = false;
        /* Materialize the RRSIG RRset for the answer in (pseudo-)packet.
         * (There will almost never be any RRSIG.) */
-       ret = rdataset_materialize(&arrset.sig_rds, data + data_off, data_bound, &pkt->mm);
+       ret = rdataset_materialize(&arrset.sig_rds, data, data_bound, &pkt->mm);
        CHECK_RET(ret);
+       data += ret;
 
        /* Sanity check: we consumed exactly all data. */
-       const int unused_bytes = data_bound - data - data_off - ret;
+       const int unused_bytes = data_bound - data;
        if (kr_fails_assert(unused_bytes == 0)) {
                kr_log_error(RULES, "ERROR: unused bytes: %d\n", unused_bytes);
                return kr_error(EILSEQ);
        }
 
+       /* Special NODATA sub-case. */
+       knot_rrset_t *rr = arrset.set.rr;
+       const int is_nodata = rr->rrs.count == 0;
+       if (is_nodata) {
+               if (kr_fails_assert(type == KNOT_RRTYPE_CNAME && arrset.sig_rds.count == 0))
+                       return kr_error(EILSEQ);
+               rr->type = KNOT_RRTYPE_SOA;
+               ret = knot_rrset_add_rdata(rr, soa_rdata, sizeof(soa_rdata) - 1, &pkt->mm);
+               CHECK_RET(ret);
+               ret = knot_pkt_begin(pkt, KNOT_AUTHORITY);
+               CHECK_RET(ret);
+       }
+
        /* Put links to the materialized data into the pkt. */
+       knot_wire_set_rcode(pkt->wire, KNOT_RCODE_NOERROR);
        ret = pkt_append(pkt, &arrset);
        CHECK_RET(ret);
 
@@ -358,13 +381,15 @@ static int answer_exact_match(struct kr_query *qry, knot_pkt_t *pkt, uint16_t ty
        qry->flags.CACHED = true;
        qry->flags.NO_MINIMIZE = true;
 
-       VERBOSE_MSG(qry, "=> satisfied by local data (positive)\n");
+       VERBOSE_MSG(qry, "=> satisfied by local data (%s)\n",
+                       is_nodata ? "no data" : "positive");
        return kr_ok();
 }
 
 int kr_rule_local_data_ins(const knot_rrset_t *rrs, const knot_rdataset_t *sig_rds,
                                kr_rule_tags_t tags)
 {
+       // Construct the DB key.
        uint8_t key_data[KEY_MAXLEN];
        knot_db_val_t key;
        key.data = key_dname_lf(rrs->owner, key_data);
@@ -381,6 +406,7 @@ int kr_rule_local_data_ins(const knot_rrset_t *rrs, const knot_rdataset_t *sig_r
        key.len = key_data + KEY_DNAME_END_OFFSET + 2 + sizeof(rrs->type)
                - (uint8_t *)key.data;
 
+       // Allocate the data in DB.
        const int rr_ssize = rdataset_dematerialize_size(&rrs->rrs);
        const int to_alloc = sizeof(tags) + sizeof(rrs->ttl) + rr_ssize
                        + rdataset_dematerialize_size(sig_rds);
@@ -388,6 +414,7 @@ int kr_rule_local_data_ins(const knot_rrset_t *rrs, const knot_rdataset_t *sig_r
        int ret = ruledb_op(write, &key, &val, 1);
        CHECK_RET(ret);
 
+       // Write all the data.
        memcpy(val.data, &tags, sizeof(tags));
        val.data += sizeof(tags);
        memcpy(val.data, &rrs->ttl, sizeof(rrs->ttl));
@@ -418,12 +445,7 @@ static int answer_zla_empty(struct kr_query *qry, knot_pkt_t *pkt,
        struct answer_rrset arrset;
        memset(&arrset, 0, sizeof(arrset));
 
-       /* Construct SOA or NS data (hardcoded content).  The SOA content is
-        * as recommended except for using a fixed mname (for simplicity):
-               https://tools.ietf.org/html/rfc6303#section-3
-        */
-       static const uint8_t soa_rdata[] = "\x09localhost\0\6nobody\7invalid\0"
-               "\0\0\0\1\0\0\x0e\x10\0\0\4\xb0\0\x09\x3a\x80\0\0\x2a\x30";
+       /* Construct SOA or NS data (hardcoded content). */
        const bool name_matches = knot_dname_is_equal(qry->sname, apex_name);
        const bool want_NS = name_matches && qry->stype == KNOT_RRTYPE_NS;
        arrset.set.rr = knot_rrset_new(apex_name, want_NS ? KNOT_RRTYPE_NS : KNOT_RRTYPE_SOA,
index 4173d75080a99cf06e47eb642f462a09aeaa3718..1f9a25f411b2e9abc2c766fb3818e1c40b7bf3b2 100644 (file)
@@ -25,7 +25,9 @@ void kr_rules_deinit(void);
 int kr_rule_local_data_answer(struct kr_query *qry, struct knot_pkt *pkt);
 
 /** Insert/overwrite a local data rule.
- * Into the default rule-set ATM. */
+ *
+ * Into the default rule-set ATM.
+ * Special NODATA case: use a CNAME type with zero records (TTL matters). */
 KR_EXPORT
 int kr_rule_local_data_ins(const knot_rrset_t *rrs, const knot_rdataset_t *sig_rds,
                                kr_rule_tags_t tags);
index 45956a4c16f0881de5275ef8bfb5a421f2d57a2a..0686ecc0d9ce79b01611685578d940744d4b8eb3 100644 (file)
@@ -3,9 +3,9 @@ local condition = require('cqueues.condition')
 
 -- setup resolver
 modules = { 'hints', 'dns64' }
-hints['dns64.example'] = '192.168.1.1'
 hints.use_nodata(true) -- Respond NODATA to AAAA query
 hints.ttl(60)
+hints['dns64.example'] = '192.168.1.1'
 dns64.config('fe80::21b:77ff:0:0')
 
 -- helper to wait for query resolution
index c2deb5a93bcb822ed2661db690cdfacd703eb0e7..7d7751882b397d1e282e563a2a290dc419664b8f 100644 (file)
@@ -136,6 +136,8 @@ Properties
 
   If set to true (the default), NODATA will be synthesised for matching hint name, but mismatching type (e.g. AAAA query when only A hint exists).
 
+  The setting is (now) per-entry, so you want to set it before any address-name pairs.
+
 .. function:: hints.ttl([new_ttl])
 
   :param int new_ttl: new TTL to set (optional)
@@ -143,3 +145,5 @@ Properties
 
   This function allows to read and write the TTL value used for records generated by the hints module.
 
+  The setting is (now) per-entry, so you want to set it before any address-name pairs.
+
index a8746a1415aef51a0e10b72bd7e3ab89de7449c7..03569bde223b9892c3043135900222fafe2b4a11 100644 (file)
@@ -245,7 +245,7 @@ static int add_pair_root(struct kr_zonecut *hints, const char *name, const char
        return kr_zonecut_add(hints, key, kr_inaddr(&ia.ip), kr_inaddr_len(&ia.ip));
 }
 
-static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr)
+static int add_pair(const struct hints_data *data, const char *name, const char *addr)
 {
        /* Build key */
        knot_dname_t key[KNOT_DNAME_MAXLEN];
@@ -261,22 +261,28 @@ static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr
 
        uint16_t rrtype = ia.ip.sa_family == AF_INET6 ? KNOT_RRTYPE_AAAA : KNOT_RRTYPE_A;
        knot_rrset_t rrs;
-       knot_rrset_init(&rrs, key, rrtype, KNOT_CLASS_IN, HINTS_TTL_DEFAULT/*FIXME*/);
+       knot_rrset_init(&rrs, key, rrtype, KNOT_CLASS_IN, data->ttl);
        int ret;
        if (ia.ip.sa_family == AF_INET6) {
                ret = knot_rrset_add_rdata(&rrs, (const uint8_t *)&ia.ip6.sin6_addr, 16, NULL);
        } else {
                ret = knot_rrset_add_rdata(&rrs, (const uint8_t *)&ia.ip4.sin_addr, 4, NULL);
        }
-       if (ret == KNOT_EOK) {
+       if (!ret) ret = kr_rule_local_data_ins(&rrs, NULL, KR_RULE_TAGS_ALL);
+       if (!ret && data->use_nodata) {
+               rrs.type = KNOT_RRTYPE_CNAME;
+               rrs.rrs.count = 0;
+               rrs.rrs.size = 0;
                ret = kr_rule_local_data_ins(&rrs, NULL, KR_RULE_TAGS_ALL);
        }
+
        knot_rdataset_clear(&rrs.rrs, NULL);
        return ret;
 }
 
 static int add_reverse_pair(struct kr_zonecut *hints, const char *name, const char *addr)
 {
+       // FIXME: implement via new policy?
        const knot_dname_t *key = addr2reverse(addr);
 
        if (key == NULL) {
@@ -380,7 +386,7 @@ static int load_file(struct kr_module *module, const char *path)
                 * we add canonical name as the last one. */
                const char *name_tok;
                while ((name_tok = strtok_r(NULL, " \t\n", &saveptr)) != NULL) {
-                       ret = add_pair(&data->hints, name_tok, addr);
+                       ret = add_pair(data, name_tok, addr);
                        if (!ret) {
                                ret = add_reverse_pair(&data->reverse_hints, name_tok, addr);
                        }
@@ -390,7 +396,7 @@ static int load_file(struct kr_module *module, const char *path)
                        }
                        count += 1;
                }
-               ret = add_pair(&data->hints, canonical_name, addr);
+               ret = add_pair(data, canonical_name, addr);
                if (!ret) {
                        ret = add_reverse_pair(&data->reverse_hints, canonical_name, addr);
                }
@@ -442,7 +448,7 @@ static char* hint_set(void *env, struct kr_module *module, const char *args)
                if (ret) {
                        del_pair(data, args_copy, addr);
                } else {
-                       ret = add_pair(&data->hints, args_copy, addr);
+                       ret = add_pair(data, args_copy, addr);
                }
        }
 
@@ -644,6 +650,7 @@ int hints_init(struct kr_module *module)
 
        static const struct kr_prop props[] = {
            { &hint_set,    "set", "Set {name, address} hint.", },
+       // TODO: _del, _get etc. with new policy
            { &hint_del,    "del", "Delete one {name, address} hint or all addresses for the name.", },
            { &hint_get,    "get", "Retrieve hint for given name.", },
            { &hint_ttl,    "ttl", "Set/get TTL used for the hints.", },