For now this relates to logging/dry-run of local-data rules.
_Bool xdp : 1;
};
typedef unsigned long kr_rule_tags_t;
+struct kr_rule_opts {
+ uint8_t score : 4;
+ _Bool log_ip : 1;
+ _Bool log_name : 1;
+ uint8_t log_level : 2;
+ uint8_t ede_code : 2;
+ uint8_t ede_sub : 3;
+};
+typedef struct kr_rule_opts kr_rule_opts_t;
struct kr_rule_zonefile_config {
const char *filename;
const char *input_str;
kr_rule_tags_t tags;
const char *origin;
uint32_t ttl;
+ kr_rule_opts_t opts;
};
struct kr_rule_fwd_flags {
_Bool is_auth : 1;
_Bool stale_accounted;
_Bool ratelimited;
uint8_t rank;
+ uint8_t rule_score_apply;
+ uint8_t rule_score_log;
struct kr_rplan rplan;
trace_log_f trace_log;
trace_callback_f trace_finish;
_Bool kr_dbg_assertion_abort;
int kr_dbg_assertion_fork;
const uint32_t KR_RULE_TTL_DEFAULT;
+const kr_rule_opts_t KR_RULE_OPTS_DEFAULT;
typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type,
const struct kr_query *qry);
int kr_view_insert_action(const char *, const char *, kr_proto_set, const char *);
int kr_view_select_action(const struct kr_request *, knot_db_val_t *);
int kr_rule_tag_add(const char *, kr_rule_tags_t *);
-int kr_rule_local_subtree(const knot_dname_t *, enum kr_rule_sub_t, uint32_t, kr_rule_tags_t);
+int kr_rule_local_subtree(const knot_dname_t *, enum kr_rule_sub_t, uint32_t, kr_rule_tags_t, kr_rule_opts_t);
int kr_rule_zonefile(const struct kr_rule_zonefile_config *);
int kr_rule_forward(const knot_dname_t *, kr_rule_fwd_flags_t, const struct sockaddr **);
-int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t);
-int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t);
+int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t, kr_rule_opts_t);
+int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t, kr_rule_opts_t);
struct tls_credentials;
typedef struct {
int sock_type;
struct kr_rplan
struct kr_request_qsource_flags
kr_rule_tags_t
+ struct kr_rule_opts
+ typedef kr_rule_opts_t
struct kr_rule_zonefile_config
struct kr_rule_fwd_flags
typedef kr_rule_fwd_flags_t
kr_dbg_assertion_abort
kr_dbg_assertion_fork
KR_RULE_TTL_DEFAULT
+ KR_RULE_OPTS_DEFAULT
EOF
printf "
KR_EXPORT void kr_misc_unused(void)
{
kr_rule_zonefile(NULL);
- kr_rule_local_address(NULL, NULL, false, 0, 0);
+ kr_rule_local_address(NULL, NULL, false, 0, 0, KR_RULE_OPTS_DEFAULT);
}
struct args the_args_value; /** Static allocation for the_args singleton. */
array_init(req->selection_context.forwarding_targets);
array_reserve_mm(req->selection_context.forwarding_targets, 1, kr_memreserve, &req->pool);
+ req->rule_score_log = KR_RULE_SCORE_LOG;
+ req->rule_score_apply = KR_RULE_SCORE_APPLY;
+
the_worker->stats.rconcurrent += 1;
return ctx;
* Return the number of bytes consumed or an error code. */
int rdataset_materialize(knot_rdataset_t * restrict rds, const uint8_t * const data,
const uint8_t *data_bound, knot_mm_t *pool);
+static inline int rdataset_materialize_val(knot_rdataset_t * restrict rds,
+ knot_db_val_t *val, knot_mm_t *pool)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpointer-arith"
+ int ret = rdataset_materialize(rds, val->data, val->data + val->len, pool);
+ if (unlikely(ret < 0)) return ret;
+ val->data += ret;
+ val->len -= ret;
+ return ret;
+#pragma GCC diagnostic pop
+}
/** Partially constructed answer when gathering RRsets from cache. */
*/
uint8_t rank;
+ uint8_t rule_score_apply;
+ uint8_t rule_score_log;
+
struct kr_rplan rplan;
trace_log_f trace_log; /**< Logging tracepoint */
trace_callback_f trace_finish; /**< Request finish tracepoint */
#include <stdlib.h>
+
struct kr_rules *the_rules = NULL;
/* The default TTL value is a compromise and probably of little practical impact.
*/
const uint32_t KR_RULE_TTL_DEFAULT = 300;
+const kr_rule_opts_t KR_RULE_OPTS_DEFAULT = { .score = KR_RULE_SCORE_DEFAULT, /*and zeros*/ };
+
/* DB key-space summary
- "\0" starts special keys like "\0rulesets" or "\0stamp"
static const uint8_t KEY_VIEW_SRC4[1] = "4";
static const uint8_t KEY_VIEW_SRC6[1] = "6";
+
+/// Returns for functions below: RET_ANSWERED, RET_CONTINUE, negative error codes for bugs
+// FIXME: doc-comment for kr_rule_local_data_answer(), etc.
+enum ret_codes_ {
+ RET_CONT_CACHE = 0,
+ RET_ANSWERED = 1,
+ RET_CONTINUE,
+};
+
static int answer_exact_match(struct kr_query *qry, knot_pkt_t *pkt, uint16_t type,
- const uint8_t *data, const uint8_t *data_bound);
+ knot_db_val_t *val);
static int answer_zla_empty(val_zla_type_t type, struct kr_query *qry, knot_pkt_t *pkt,
knot_db_val_t zla_lf, uint32_t ttl);
static int answer_zla_dname(val_zla_type_t type, struct kr_query *qry, knot_pkt_t *pkt,
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);
+ 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)
+/// Log that we apply a local-data rule (if desired)
+// TODO: we might parametrize by some log string that expresses e.g. the type of rule
+static void log_rule(kr_rule_opts_t opts, const struct kr_query *qry)
+{
+ const struct kr_request *req = qry->request;
+ const int level = map_log_level(opts.log_level);
+ bool do_log = opts.score >= req->rule_score_log
+ && (kr_log_is_debug(RULES, req) || KR_LOG_LEVEL_IS(level));
+ if (!do_log)
+ return;
+ bool applied = opts.score >= req->rule_score_apply;
+
+ //// Let's construct the log message, piece by piece in `s**` variables.
+ const char * s1a = "=> local data ",
+ *s1b = applied ? "applied" : "dry-run";
+
+ const char *s2a = "";
+ char s2b[INET6_ADDRSTRLEN + 1] = "";
+ if (opts.log_ip) {
+ s2a = ", user: ";
+ const struct sockaddr *addr = req->qsource.addr;
+ if (addr) {
+ bool ok = inet_ntop(addr->sa_family, kr_inaddr(addr), s2b, sizeof(s2b));
+ kr_assert(ok);
+ } else {
+ strcpy(s2b, "internal");
+ }
+ }
+
+ const char *s3a = "";
+ char s3b[KR_DNAME_STR_MAXLEN] = "";
+ if (opts.log_name) {
+ s3a = ", name: ";
+ knot_dname_to_str(s3b, qry->sname, sizeof(s3b));
+ s3b[sizeof(s3b) - 1] = 0;
+ }
+
+ kr_log_fmt(LOG_GRP_RULES, level, SD_JOURNAL_METADATA,
+ "[%-6s] %s%s%s%s%s%s\n",
+ LOG_GRP_RULES_TAG, s1a, s1b, s2a, s2b, s3a, s3b);
+}
+
/** Add name lookup format on the fixed end-position inside key_data.
*
* Note: key_data[KEY_DNAME_END_OFFSET] = '\0' even though
int rule_local_data_answer(struct kr_query *qry, knot_pkt_t *pkt)
{
- // return shorthands; see doc-comment for kr_rule_local_data_answer()
- static const int RET_CONT_CACHE = 0;
- static const int RET_ANSWERED = 1;
-
kr_require(the_rules);
// TODO: implement EDE codes somehow
continue;
// We found a rule that applies to the dname+rrtype+req.
- ret = answer_exact_match(qry, pkt, types[i],
- val.data, val.data + val.len);
- return ret ? kr_error(ret) : RET_ANSWERED;
+ ret = answer_exact_match(qry, pkt, types[i], &val);
+ if (ret != RET_CONTINUE)
+ return ret;
}
if (kr_fails_assert(ret == 0 || ret == -ENOENT))
return kr_error(ret);
qry->data_src.rule_depth = knot_dname_labels(apex_name, NULL);
return RET_CONT_CACHE;
}
- // The other types optionally specify TTL.
+
+ // Process opts.
+ kr_rule_opts_t opts;
+ if (deserialize_fails_assert(&val, &opts))
+ return kr_error(EILSEQ);
+ log_rule(opts, qry);
+ if (opts.score < qry->request->rule_score_apply)
+ goto shorten; // continue looking for rules
+
+ // The non-forward types optionally specify TTL.
uint32_t ttl = KR_RULE_TTL_DEFAULT;
if (val.len >= sizeof(ttl)) // allow omitting -> can't kr_assert
deserialize_fails_assert(&val, &ttl);
} while (false)
static int answer_exact_match(struct kr_query *qry, knot_pkt_t *pkt, uint16_t type,
- const uint8_t *data, const uint8_t *data_bound)
+ knot_db_val_t *val)
{
- /* Extract ttl from data. */
+ /* Process opts. */
+ kr_rule_opts_t opts;
+ if (deserialize_fails_assert(val, &opts))
+ return kr_error(EILSEQ);
+ log_rule(opts, qry);
+ if (opts.score < qry->request->rule_score_apply)
+ return RET_CONTINUE;
+
uint32_t ttl;
- if (kr_fails_assert(data + sizeof(ttl) <= data_bound))
+ if (deserialize_fails_assert(val, &ttl))
return kr_error(EILSEQ);
- memcpy(&ttl, data, sizeof(ttl));
- data += sizeof(ttl);
/* Start constructing the (pseudo-)packet. */
int ret = pkt_renew(pkt, qry->sname, qry->stype);
arrset.set.rr = knot_rrset_new(qry->sname, type, KNOT_CLASS_IN, ttl, &pkt->mm);
if (kr_fails_assert(arrset.set.rr))
return kr_error(ENOMEM);
- ret = rdataset_materialize(&arrset.set.rr->rrs, data, data_bound, &pkt->mm);
+ ret = rdataset_materialize_val(&arrset.set.rr->rrs, val, &pkt->mm);
CHECK_RET(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_bound, &pkt->mm);
+ ret = rdataset_materialize_val(&arrset.sig_rds, val, &pkt->mm);
CHECK_RET(ret);
- data += ret;
/* Sanity check: we consumed exactly all data. */
- 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);
+ if (kr_fails_assert(val->len == 0)) {
+ kr_log_error(RULES, "ERROR: unused bytes: %zu\n", val->len);
return kr_error(EILSEQ);
}
qry->flags.EXPIRING = false;
qry->flags.CACHED = true;
qry->flags.NO_MINIMIZE = true;
-
- VERBOSE_MSG(qry, "=> satisfied by local data (%s)\n",
- is_nodata ? "no data" : "positive");
- return kr_ok();
+ return RET_ANSWERED;
}
knot_db_val_t local_data_key(const knot_rrset_t *rrs, uint8_t key_data[KEY_MAXLEN],
return key;
}
int kr_rule_local_data_ins(const knot_rrset_t *rrs, const knot_rdataset_t *sig_rds,
- kr_rule_tags_t tags)
+ kr_rule_tags_t tags, kr_rule_opts_t opts)
{
ENSURE_the_rules;
// Construct the DB key.
uint8_t key_data[KEY_MAXLEN];
knot_db_val_t key = local_data_key(rrs, key_data, RULESET_DEFAULT);
- return local_data_ins(key, rrs, sig_rds, tags);
+ return local_data_ins(key, rrs, sig_rds, tags, opts);
}
-int local_data_ins(knot_db_val_t key, const knot_rrset_t *rrs,
- const knot_rdataset_t *sig_rds, kr_rule_tags_t tags)
+int local_data_ins(knot_db_val_t key, const knot_rrset_t *rrs, const knot_rdataset_t *sig_rds,
+ kr_rule_tags_t tags, kr_rule_opts_t opts)
{
// Prepare the data into a temporary buffer.
const int rr_ssize = rdataset_dematerialize_size(&rrs->rrs);
- const int val_len = sizeof(tags) + sizeof(rrs->ttl) + rr_ssize
+ const int val_len = sizeof(tags) + sizeof(opts) + sizeof(rrs->ttl) + rr_ssize
+ rdataset_dematerialize_size(sig_rds);
uint8_t buf[val_len], *data = buf;
memcpy(data, &tags, sizeof(tags));
data += sizeof(tags);
+ memcpy(data, &opts, sizeof(opts));
+ data += sizeof(opts);
memcpy(data, &rrs->ttl, sizeof(rrs->ttl));
data += sizeof(rrs->ttl);
rdataset_dematerialize(&rrs->rrs, data);
if (kr_fails_assert(rrs->rrs.count))
return kr_error(EINVAL);
return rule_local_subtree(rrs->owner, KR_RULE_SUB_DNAME,
- knot_dname_target(rrs->rrs.rdata), rrs->ttl, tags);
+ knot_dname_target(rrs->rrs.rdata), rrs->ttl, tags, opts);
}
int kr_rule_local_data_del(const knot_rrset_t *rrs, kr_rule_tags_t tags)
{
knot_db_val_t key = local_data_key(rrs, key_data, RULESET_DEFAULT);
return ruledb_op(remove, &key, 1);
}
-int kr_rule_local_data_merge(const knot_rrset_t *rrs, const kr_rule_tags_t tags)
+int kr_rule_local_data_merge(const knot_rrset_t *rrs, const kr_rule_tags_t tags, kr_rule_opts_t opts)
{
ENSURE_the_rules;
// Construct the DB key.
kr_rule_tags_t tags_old;
if (deserialize_fails_assert(&val, &tags_old) || tags_old != tags)
goto fallback;
+ kr_rule_opts_t opts_old;
+ if (deserialize_fails_assert(&val, &opts_old))
+ goto fallback;
// merge TTLs
uint32_t ttl;
if (deserialize_fails_assert(&val, &ttl))
return kr_error(ret);
}
// everything is ready to insert the merged RRset
- ret = local_data_ins(key, &rrs_new, NULL, tags);
+ ret = local_data_ins(key, &rrs_new, NULL, tags, opts);
mm_ctx_delete(mm);
return ret;
fallback:
- return local_data_ins(key, rrs, NULL, tags);
+ return local_data_ins(key, rrs, NULL, tags, opts);
}
/** Empty or NXDOMAIN or NODATA. Returning kr_error(EAGAIN) means the rule didn't match. */
knot_db_val_t val;
// Multiple variants are possible, with different tags.
for (ret = ruledb_op(it_first, &key, &val); ret == 0; ret = ruledb_op(it_next, &val)) {
- if (kr_rule_consume_tags(&val, qry->request))
- return answer_exact_match(qry, pkt, qry->stype,
- val.data, val.data + val.len);
+ if (kr_rule_consume_tags(&val, qry->request)) {
+ int ret2 = answer_exact_match(qry, pkt, qry->stype, &val);
+ if (ret2 != RET_CONTINUE)
+ return ret2;
+ }
}
if (ret && ret != -ENOENT)
return ret;
}
int kr_rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type,
- uint32_t ttl, kr_rule_tags_t tags)
+ uint32_t ttl, kr_rule_tags_t tags, kr_rule_opts_t opts)
{
- return rule_local_subtree(apex, type, NULL, ttl, tags);
+ return rule_local_subtree(apex, type, NULL, ttl, tags, opts);
}
knot_db_val_t zla_key(const knot_dname_t *apex, uint8_t key_data[KEY_MAXLEN])
{
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)
+ 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);
// Prepare the data into a temporary buffer.
const int target_len = has_target ? knot_dname_size(target) : 0;
const bool has_ttl = ttl != KR_RULE_TTL_DEFAULT || has_target;
- const int val_len = sizeof(tags) + sizeof(ztype) + (has_ttl ? sizeof(ttl) : 0)
- + target_len;
+ const int val_len = sizeof(tags) + sizeof(ztype) + sizeof(opts)
+ + (has_ttl ? sizeof(ttl) : 0) + target_len;
uint8_t buf[val_len], *data = buf;
memcpy(data, &tags, sizeof(tags));
data += sizeof(tags);
memcpy(data, &ztype, sizeof(ztype));
data += sizeof(ztype);
+ memcpy(data, &opts, sizeof(opts));
+ data += sizeof(opts);
if (has_ttl) {
memcpy(data, &ttl, sizeof(ttl));
data += sizeof(ttl);
struct kr_request;
struct knot_pkt;
struct sockaddr;
+#include <syslog.h>
+#include <lib/utils.h>
#include <libknot/db/db.h>
/// Storage for a tag-set. It's a bitmap, so 64 tags are supported now.
/// Tags "capacity", i.e. numbered from 0 to _CAP - 1.
#define KR_RULE_TAGS_CAP (sizeof(kr_rule_tags_t) * 8)
+/// Extra options for a rule (not for forwarding)
+struct kr_rule_opts {
+ /// Degree of severity for the rule; FIXME: granularity, defaults, etc.
+ uint8_t score : 4;
+
+ bool log_ip : 1, log_name : 1;
+ // +maybe log rule/QNAME/something
+ /// Log level: 0 = debug, 1 = info, ...
+ uint8_t log_level : 2;
+
+ /** Maybe 2 bits: (unset), blocked, censored, filtered
+ https://www.rfc-editor.org/rfc/rfc8914.html#name-extended-dns-error-code-15-
+ */
+ uint8_t ede_code : 2;
+ /** Maybe 3 bits: (unset), Malware, Phishing, ... from
+ https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-structured-dns-error#name-new-registry-for-dns-sub-er
+ */
+ uint8_t ede_sub : 3;
+};
+typedef struct kr_rule_opts kr_rule_opts_t;
+static_assert(sizeof(kr_rule_opts_t) == 2, "kr_rule_opts_t size changed unexpectedly");
+/// Default opts; in particular used for the RFC-mandated special-use names
+KR_EXPORT extern const kr_rule_opts_t KR_RULE_OPTS_DEFAULT;
+enum { // Default minimal score of a rule to log/apply it.
+ KR_RULE_SCORE_LOG = 3,
+ KR_RULE_SCORE_APPLY = 6,
+ KR_RULE_SCORE_DEFAULT = 10,
+};
+
+static inline int map_log_level(uint8_t ll)
+{
+ switch (ll) {
+ case 0: return LOG_DEBUG;
+ case 1: return LOG_INFO;
+ case 2: return LOG_NOTICE;
+ case 3: return LOG_WARNING;
+ }
+ return LOG_DEBUG; // shouldn't happen
+}
+
/** Open the rule DB.
*
* You can call this to override the path or size (NULL/0 -> default)
/** Try answering the query from local data; WIP: otherwise determine data source overrides.
*
- * \return kr_error() on errors, >0 if answered, 0 otherwise (also when forwarding)
+ * \return kr_error() on errors, >0 if answered FIXME, 0 otherwise (also when forwarding)
*
* FIXME: we probably want to ensure AA flags in answer as appropriate.
* Perhaps approach it like AD? Tweak flags in ranked_rr_array_entry
* 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);
+ kr_rule_tags_t tags, kr_rule_opts_t opts);
/** Merge RRs into a local data rule.
*
* - FIXME: with multiple tags variants for the same name-type pair,
* - RRSIGs get dropped, if any were attached.
* - We assume that this is called with a RW transaction open already,
* which is always true in normal usage (long RW txn covering whole config).
+ * - TODO: what if opts don't match?
*/
KR_EXPORT
-int kr_rule_local_data_merge(const knot_rrset_t *rrs, kr_rule_tags_t tags);
+int kr_rule_local_data_merge(const knot_rrset_t *rrs, kr_rule_tags_t tags, kr_rule_opts_t opts);
/** Add a name-address pair into rules.
*
* - NODATA is optionally inserted
*/
KR_EXPORT
-int kr_rule_local_address(const char *name, const char *addr,
- bool use_nodata, uint32_t ttl, kr_rule_tags_t tags);
+int kr_rule_local_address(const char *name, const char *addr, bool use_nodata,
+ uint32_t ttl, kr_rule_tags_t tags, kr_rule_opts_t opts);
/** For a given name, remove one address ##or all of them (if == NULL).
*
* Same as kr_rule_data_address() but from a file.
*/
KR_EXPORT
-int kr_rule_local_hosts(const char *path, bool use_nodata, uint32_t ttl, kr_rule_tags_t tags);
+int kr_rule_local_hosts(const char *path, bool use_nodata, uint32_t ttl,
+ kr_rule_tags_t tags, kr_rule_opts_t opts);
/** Remove a local data rule.
*
*/
KR_EXPORT
int kr_rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type,
- uint32_t ttl, kr_rule_tags_t tags);
+ uint32_t ttl, kr_rule_tags_t tags, kr_rule_opts_t opts);
/** Insert a view action into the default ruleset.
*
kr_rule_tags_t tags; /// tag-set for the generated rule
const char *origin; /// NULL or zone origin if known
uint32_t ttl; /// default TTL
+ kr_rule_opts_t opts; /// options for these rules
};
/** Load rules from some zonefile format, e.g. RPZ. Code in ./zonefile.c */
KR_EXPORT
const knot_dname_t *dname =
knot_dname_from_str(name_buf, names[i], sizeof(name_buf));
int ret = kr_rule_local_subtree(dname, KR_RULE_SUB_EMPTY,
- TTL, KR_RULE_TAGS_ALL);
+ TTL, KR_RULE_TAGS_ALL, KR_RULE_OPTS_DEFAULT);
CHECK_RET(ret);
/* The double conversion is perhaps a bit wasteful, but it should be rare. */
/* LATER: add extra info with explanation? policy module had an ADDITIONAL
knot_dname_t localhost_dname[] = "\x09localhost\0";
{ // forward localhost
int ret = kr_rule_local_subtree(localhost_dname, KR_RULE_SUB_REDIRECT,
- TTL, KR_RULE_TAGS_ALL);
+ TTL, KR_RULE_TAGS_ALL, KR_RULE_OPTS_DEFAULT);
CHECK_RET(ret);
knot_rrset_t rr = {
};
rr.type = KNOT_RRTYPE_A;
ret = knot_rrset_add_rdata(&rr, (const uint8_t *)"\x7f\0\0\1", 4, NULL);
- if (!ret) ret = kr_rule_local_data_ins(&rr, NULL, KR_RULE_TAGS_ALL);
+ if (!ret) ret = kr_rule_local_data_ins(&rr, NULL,
+ KR_RULE_TAGS_ALL, KR_RULE_OPTS_DEFAULT);
knot_rdataset_clear(&rr.rrs, NULL);
CHECK_RET(ret);
ret = knot_rrset_add_rdata(&rr,
(const uint8_t *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1",
16, NULL);
- if (!ret) ret = kr_rule_local_data_ins(&rr, NULL, KR_RULE_TAGS_ALL);
+ if (!ret) ret = kr_rule_local_data_ins(&rr, NULL,
+ KR_RULE_TAGS_ALL, KR_RULE_OPTS_DEFAULT);
knot_rdataset_clear(&rr.rrs, NULL);
CHECK_RET(ret);
rr.type = KNOT_RRTYPE_NS;
ret = knot_rrset_add_rdata(&rr, localhost_dname, 1+9+1, NULL);
- if (!ret) ret = kr_rule_local_data_ins(&rr, NULL, KR_RULE_TAGS_ALL);
+ if (!ret) ret = kr_rule_local_data_ins(&rr, NULL,
+ KR_RULE_TAGS_ALL, KR_RULE_OPTS_DEFAULT);
knot_rdataset_clear(&rr.rrs, NULL);
CHECK_RET(ret);
}
.additional = NULL,
};
int ret = knot_rrset_add_rdata(&rr, localhost_dname, 1+9+1, NULL);
- if (!ret) ret = kr_rule_local_data_ins(&rr, NULL, KR_RULE_TAGS_ALL);
+ if (!ret) ret = kr_rule_local_data_ins(&rr, NULL,
+ KR_RULE_TAGS_ALL, KR_RULE_OPTS_DEFAULT);
knot_dname_t name_buf[KNOT_DNAME_MAXLEN];
rr.owner = knot_dname_from_str(name_buf,
"1.0.0.127.in-addr.arpa.",
sizeof(name_buf));
- if (!ret) ret = kr_rule_local_data_ins(&rr, NULL, KR_RULE_TAGS_ALL);
+ if (!ret) ret = kr_rule_local_data_ins(&rr, NULL,
+ KR_RULE_TAGS_ALL, KR_RULE_OPTS_DEFAULT);
rr.owner = knot_dname_from_str(name_buf,
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.",
sizeof(name_buf));
- if (!ret) ret = kr_rule_local_data_ins(&rr, NULL, KR_RULE_TAGS_ALL);
+ if (!ret) ret = kr_rule_local_data_ins(&rr, NULL,
+ KR_RULE_TAGS_ALL, KR_RULE_OPTS_DEFAULT);
knot_rdataset_clear(&rr.rrs, NULL);
CHECK_RET(ret);
knot_db_val_t local_data_key(const knot_rrset_t *rrs, uint8_t key_data[KEY_MAXLEN],
const char *ruleset_name);
/** Same as kr_rule_local_data_ins() but with precomputed `key`. */
-int local_data_ins(knot_db_val_t key, const knot_rrset_t *rrs,
- const knot_rdataset_t *sig_rds, kr_rule_tags_t tags);
+int local_data_ins(knot_db_val_t key, const knot_rrset_t *rrs, const knot_rdataset_t *sig_rds,
+ kr_rule_tags_t tags, kr_rule_opts_t opts);
/** 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]);
}
static int add_pair(const char *name, const char *addr,
- bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
+ bool use_nodata, uint32_t ttl, kr_rule_tags_t tags, kr_rule_opts_t opts)
{
/* Build key */
knot_dname_t key[KNOT_DNAME_MAXLEN];
} else {
ret = knot_rrset_add_rdata(&rrs, (const uint8_t *)&ia.ip4.sin_addr, 4, NULL);
}
- if (!ret) ret = kr_rule_local_data_merge(&rrs, tags);
+ if (!ret) ret = kr_rule_local_data_merge(&rrs, tags, opts);
if (!ret && use_nodata) {
rrs.type = KNOT_RRTYPE_CNAME;
rrs.rrs.count = 0;
rrs.rrs.size = 0;
// no point in the _merge() variant here
- ret = kr_rule_local_data_ins(&rrs, NULL, tags);
+ ret = kr_rule_local_data_ins(&rrs, NULL, tags, opts);
}
knot_rdataset_clear(&rrs.rrs, NULL);
}
static int add_reverse_pair(const char *name, const char *addr,
- bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
+ bool use_nodata, uint32_t ttl, kr_rule_tags_t tags, kr_rule_opts_t opts)
{
const knot_dname_t *key = addr2reverse(addr);
if (!key)
if (!ret) {
// We use _merge(). Using multiple PTR RRs is not recommended generally,
// but here it seems better than choosing any "arbitrarily".
- ret = kr_rule_local_data_merge(&rrs, tags);
+ ret = kr_rule_local_data_merge(&rrs, tags, opts);
knot_rdataset_clear(&rrs.rrs, NULL);
}
return ret;
}
-int kr_rule_local_address(const char *name, const char *addr,
- bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
+int kr_rule_local_address(const char *name, const char *addr, bool use_nodata,
+ uint32_t ttl, kr_rule_tags_t tags, kr_rule_opts_t opts)
{
- int ret = add_reverse_pair(name, addr, use_nodata, ttl, tags);
+ int ret = add_reverse_pair(name, addr, use_nodata, ttl, tags, opts);
if (ret) return ret;
- return add_pair(name, addr, use_nodata, ttl, tags);
+ return add_pair(name, addr, use_nodata, ttl, tags, opts);
}
int kr_rule_local_address_del(const char *name, const char *addr,
return ret < 0 ? ret : kr_ok();
}
-int kr_rule_local_hosts(const char *path, bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
+int kr_rule_local_hosts(const char *path, bool use_nodata, uint32_t ttl,
+ kr_rule_tags_t tags, kr_rule_opts_t opts)
{
auto_fclose FILE *fp = fopen(path, "r");
if (fp == NULL) {
}
const char *name_tok;
while ((name_tok = strtok_r(NULL, " \t\n", &saveptr)) != NULL) {
- ret = add_pair(name_tok, addr, use_nodata, ttl, tags);
+ ret = add_pair(name_tok, addr, use_nodata, ttl, tags, opts);
if (ret)
goto error;
count += 1;
}
- ret = add_pair(canonical_name, addr, use_nodata, ttl, tags);
+ ret = add_pair(canonical_name, addr, use_nodata, ttl, tags, opts);
if (!ret) // PTR only to the canonical name
- ret = add_reverse_pair(canonical_name, addr, use_nodata, ttl, tags);
+ ret = add_reverse_pair(canonical_name, addr, use_nodata, ttl, tags, opts);
if (ret)
goto error;
count += 1;
const knot_db_val_t key = { .data = (void *)key_data, .len = key_len };
const knot_rrset_t *rr = *rr_p;
const struct kr_rule_zonefile_config *c = config;
- return local_data_ins(key, rr, NULL, c->tags);
+ return local_data_ins(key, rr, NULL, c->tags, c->opts);
//TODO: check error logging path here (LMDB)
}
// 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, s->r_ttl, c->tags);
+ ret = kr_rule_local_subtree(apex, 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) {
// "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,
- s->r_ttl, c->tags);
+ 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_CLASS_IN, s->r_ttl);
- ret = kr_rule_local_data_ins(&rrs, NULL, c->tags);
+ ret = kr_rule_local_data_ins(&rrs, NULL, c->tags, c->opts);
}
} else {
knot_dname_t *target = s->r_owner;
knot_rrset_init(&rrs, target, KNOT_RRTYPE_CNAME, KNOT_CLASS_IN, s->r_ttl);
// TODO: implement wildcard expansion for target
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);
+ if (!ret) ret = kr_rule_local_data_ins(&rrs, NULL, c->tags, c->opts);
knot_rdataset_clear(&rrs.rrs, NULL);
}
if (ret)
struct hints_data {
bool use_nodata; /**< See hint_use_nodata() description, exposed via lua. */
uint32_t ttl; /**< TTL used for the hints, exposed via lua. */
+ kr_rule_opts_t opts; /**< Options used for local-data rules. Not overridable yet. */
};
/** Useful for returning from module properties. */
if (!args)
args = "/etc/hosts";
const struct hints_data *data = module->data;
- int err = kr_rule_local_hosts(args, data->use_nodata, data->ttl, KR_RULE_TAGS_ALL);
+ int err = kr_rule_local_hosts(args, data->use_nodata, data->ttl,
+ KR_RULE_TAGS_ALL, data->opts);
return bool2jsonstr(err == kr_ok());
}
*addr = '\0';
++addr;
ret = kr_rule_local_address(args_copy, addr,
- data->use_nodata, data->ttl, KR_RULE_TAGS_ALL);
+ data->use_nodata, data->ttl, KR_RULE_TAGS_ALL, data->opts);
}
return bool2jsonstr(ret == 0);
return kr_error(ENOMEM);
data->use_nodata = true;
data->ttl = KR_RULE_TTL_DEFAULT;
+ data->opts = KR_RULE_OPTS_DEFAULT;
module->data = data;
return kr_ok();
if (conf && conf[0]) {
const struct hints_data *data = module->data;
return kr_rule_local_hosts(conf,
- data->use_nodata, data->ttl, KR_RULE_TAGS_ALL);
+ data->use_nodata, data->ttl, KR_RULE_TAGS_ALL, data->opts);
}
return kr_ok();
}
{% macro kr_rule_local_address(name, address, nodata, ttl, tags=none) -%}
assert(C.kr_rule_local_address('{{ name }}', '{{ address }}',
- {{ boolean(nodata) }}, {{ local_data_ttl(ttl)}}, {{ policy_get_tagset(tags) }}) == 0)
+ {{ boolean(nodata) }}, {{ local_data_ttl(ttl)}}, {{ policy_get_tagset(tags) }}) == 0,
+ C.KR_RULE_OPTS_DEFAULT)
{%- endmacro -%}
{% macro kr_rule_local_hosts(file, nodata, ttl, tags=none) -%}
assert(C.kr_rule_local_hosts('{{ file }}', {{ boolean(nodata) }},
- {{ local_data_ttl(ttl)}}, {{ policy_get_tagset(tags) }}) == 0)
+ {{ local_data_ttl(ttl)}}, {{ policy_get_tagset(tags) }}) == 0, C.KR_RULE_OPTS_DEFAULT)
{%- endmacro %}
{{ id }}.tags = {{ policy_get_tagset(tags) }}
{{ id }}.nodata = {{ boolean(nodata) }}
{{ id }}.is_rpz = {{ boolean(is_rpz) }}
+{{ id }}.opts = C.KR_RULE_OPTS_DEFAULT
{% if is_rpz -%}
{{ id }}.filename = '{{ input_str }}'
{% else %}
{% macro kr_rule_local_subtree(name, type, ttl, tags=none) -%}
assert(C.kr_rule_local_subtree(todname('{{ name }}'),
- C.KR_RULE_SUB_{{ type.upper() }}, {{ local_data_ttl(ttl) }}, {{ policy_get_tagset(tags) }}) == 0)
+ C.KR_RULE_SUB_{{ type.upper() }}, {{ local_data_ttl(ttl) }}, {{ policy_get_tagset(tags) }}) == 0,
+ C.KR_RULE_OPTS_DEFAULT)
{%- endmacro %}