+Knot Resolver 6.x.y (2026-0m-dd)
+================================
+
+Improvements:
+-------------
+- RPZ now supports *.some.name. CNAME block.page. (!1808)
+
+
Knot Resolver 6.2.0 (2026-02-03)
================================
kr_rule_fwd_flags_t flags;
knot_db_val_t targets_ptr;
};
-enum kr_rule_sub_t {KR_RULE_SUB_EMPTY = 1, KR_RULE_SUB_NXDOMAIN, KR_RULE_SUB_NODATA, KR_RULE_SUB_REDIRECT, KR_RULE_SUB_DNAME};
+enum kr_rule_sub_t {KR_RULE_SUB_EMPTY = 1, KR_RULE_SUB_NXDOMAIN, KR_RULE_SUB_NODATA, KR_RULE_SUB_REDIRECT, KR_RULE_SUB_DNAME, KR_RULE_SUB_DNAME_FLAT};
enum kr_proto {KR_PROTO_INTERNAL, KR_PROTO_UDP53, KR_PROTO_TCP53, KR_PROTO_DOT, KR_PROTO_DOH, KR_PROTO_DOQ, KR_PROTO_DOQ_CONN, KR_PROTO_DOQ_STREAM, KR_PROTO_COUNT};
typedef unsigned char kr_proto_set;
kr_layer_t kr_layer_t_static;
* just files which are *not* automatically reloaded when changed
* rules with ``rpz-*`` labels are ignored, e.g. ``.rpz-client-ip``
.. * ``CNAME *.some.thing`` does not expand the wildcard
- * wildcard support is limited only to blocking subtrees by
- ``*.some.name. CNAME .`` or ``*.some.name. CNAME *.``
+ * wildcard support is limited to left-hand side of CNAME:
+ ``*.some.name. CNAME .`` or ``*.some.name. CNAME *.`` or ``*.some.name. CNAME block.page.``
Advanced rules
--------------
knot_db_val_t zla_lf, uint32_t ttl, knot_db_val_t *val);
static int answer_zla_redirect(struct kr_query *qry, knot_pkt_t *pkt, const char *ruleset_name,
knot_db_val_t zla_lf, uint32_t ttl);
-static int rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type,
- const knot_dname_t *target, uint32_t ttl,
- kr_rule_tags_t tags, kr_rule_opts_t opts);
// LATER: doing tag_names_default() and kr_rule_tag_add() inside a RW transaction would be better.
static int tag_names_default(void)
ret = answer_zla_redirect(qry, pkt, ruleset_name, zla_lf, ttl);
break;
case KR_RULE_SUB_DNAME:
+ case KR_RULE_SUB_DNAME_FLAT:
ret = answer_zla_dname(ztype, qry, pkt, zla_lf, ttl, &val);
break;
default:
static int answer_zla_dname(val_zla_type_t type, struct kr_query *qry, knot_pkt_t *pkt,
const knot_db_val_t zla_lf, uint32_t ttl, knot_db_val_t *val)
{
- if (kr_fails_assert(type == KR_RULE_SUB_DNAME))
+ if (kr_fails_assert(type == KR_RULE_SUB_DNAME || type == KR_RULE_SUB_DNAME_FLAT))
return kr_error(EINVAL);
const knot_dname_t *dname_target = val->data;
CHECK_RET(ret);
const bool hit_apex = knot_dname_is_equal(qry->sname, apex_name);
- if (hit_apex && type == KR_RULE_SUB_DNAME)
+ if (hit_apex)
return kr_error(EAGAIN); // LATER: maybe a type that matches apex
// Start constructing the (pseudo-)packet.
KNOT_CLASS_IN, ttl, &pkt->mm);
if (kr_fails_assert(arrset.set.rr))
return kr_error(ENOMEM);
- const knot_dname_t *cname_target = knot_dname_replace_suffix(qry->sname,
- knot_dname_labels(apex_name, NULL), dname_target, &pkt->mm);
+ const knot_dname_t *cname_target = type == KR_RULE_SUB_DNAME_FLAT ? dname_target :
+ knot_dname_replace_suffix(qry->sname, knot_dname_labels(apex_name, NULL),
+ dname_target, &pkt->mm);
const int rdata_len = knot_dname_size(cname_target);
const bool cname_fits = rdata_len <= KNOT_DNAME_MAXLEN;
if (cname_fits) {
qry->flags.CACHED = true;
qry->flags.NO_MINIMIZE = true;
- VERBOSE_MSG(qry, "=> satisfied by local data (DNAME)\n");
+ VERBOSE_MSG(qry, "=> satisfied by local data (DNAME-like)\n");
return kr_ok();
}
key.len = key_data + KEY_DNAME_END_OFFSET - (uint8_t *)key.data;
return key;
}
-static int rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type,
- const knot_dname_t *target, uint32_t ttl,
- kr_rule_tags_t tags, kr_rule_opts_t opts)
+int rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type,
+ const knot_dname_t *target, uint32_t ttl,
+ kr_rule_tags_t tags, kr_rule_opts_t opts)
{
// type-check
- const bool has_target = (type == KR_RULE_SUB_DNAME);
+ const bool has_target = (type == KR_RULE_SUB_DNAME || type == KR_RULE_SUB_DNAME_FLAT);
switch (type) {
case KR_RULE_SUB_DNAME:
+ case KR_RULE_SUB_DNAME_FLAT:
if (kr_fails_assert(!!target == has_target))
return kr_error(EINVAL);
break;
KR_RULE_SUB_REDIRECT,
/// Act similar to DNAME: rebase everything underneath by generated CNAMEs.
KR_RULE_SUB_DNAME,
+ /// Like _SUB_DNAME but the CNAMEs do not get prefixed.
+ KR_RULE_SUB_DNAME_FLAT,
};
/** Insert a simple sub-tree rule.
*
* - into the default rule-set
* - SOA and NS for generated answers aren't overridable.
- * - type: you can't use _DNAME via this function; insert it by kr_rule_local_data_ins()
+ * - type: you can't use _DNAME* via this function;
+ * internally we have rule_local_subtree() for now; TODO
*/
KR_EXPORT
int kr_rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type,
/** Construct key for a zone-like-apex entry. It's stored in `key_data`. */
knot_db_val_t zla_key(const knot_dname_t *apex, uint8_t key_data[KEY_MAXLEN]);
+/** Like kr_rule_local_subtree() but has `target` to support other kr_rule_sub_t types. */
+int rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type,
+ const knot_dname_t *target, uint32_t ttl,
+ kr_rule_tags_t tags, kr_rule_opts_t opts);
+
/** Almost the whole kr_rule_local_data_answer() */
int rule_local_data_answer(struct kr_query *qry, knot_pkt_t *pkt);
return;
}
int ret = 0;
- if (s->r_data[0] == 0) { // "CNAME ." i.e. NXDOMAIN
- const knot_dname_t *apex = s->r_owner;
- if (knot_dname_is_wildcard(apex))
- apex += 2;
+ knot_dname_t *owner = s->r_owner;
+ const knot_dname_t *target = s->r_data;
+ if (target[0] == 0) { // "CNAME ." i.e. NXDOMAIN
+ if (knot_dname_is_wildcard(owner))
+ owner += 2;
// RPZ_COMPAT: we NXDOMAIN the whole subtree regardless of being wildcard.
// Exact RPZ semantics would be hard here, it makes more sense
// to apply also to a subtree, and corresponding wildcard rule
// usually accompanies this rule anyway.
- ret = kr_rule_local_subtree(apex, KR_RULE_SUB_NXDOMAIN,
+ ret = kr_rule_local_subtree(owner, KR_RULE_SUB_NXDOMAIN,
s->r_ttl, c->tags, c->opts);
- } else if (knot_dname_is_wildcard(s->r_data) && s->r_data[2] == 0) {
+ } else if (knot_dname_is_wildcard(target) && target[2] == 0) {
// "CNAME *." -> NODATA
- knot_dname_t *apex = s->r_owner;
- if (knot_dname_is_wildcard(apex)) {
- apex += 2;
- ret = kr_rule_local_subtree(apex, KR_RULE_SUB_NODATA,
+ if (knot_dname_is_wildcard(owner)) {
+ owner += 2;
+ ret = kr_rule_local_subtree(owner, KR_RULE_SUB_NODATA,
s->r_ttl, c->tags, c->opts);
} else { // using special kr_rule_ semantics of empty CNAME RRset
knot_rrset_t rrs;
- knot_rrset_init(&rrs, apex, KNOT_RRTYPE_CNAME,
+ knot_rrset_init(&rrs, owner, KNOT_RRTYPE_CNAME,
KNOT_CLASS_IN, s->r_ttl);
ret = kr_rule_local_data_ins(&rrs, NULL, c->tags, c->opts);
}
+ } else if (knot_dname_is_wildcard(owner)) {
+ owner += 2;
+ ret = rule_local_subtree(owner, KR_RULE_SUB_DNAME_FLAT, target,
+ s->r_ttl, c->tags, c->opts);
+ // TODO: implement wildcard expansion for target
} else {
- knot_dname_t *target = s->r_owner;
knot_rrset_t rrs;
- knot_rrset_init(&rrs, target, KNOT_RRTYPE_CNAME, KNOT_CLASS_IN, s->r_ttl);
- // TODO: implement wildcard expansion for target
+ knot_rrset_init(&rrs, s->r_owner, KNOT_RRTYPE_CNAME, KNOT_CLASS_IN, s->r_ttl);
ret = knot_rrset_add_rdata(&rrs, s->r_data, s->r_data_length, NULL);
if (!ret) ret = kr_rule_local_data_ins(&rrs, NULL, c->tags, c->opts);
knot_rdataset_clear(&rrs.rrs, NULL);