libknot+kdig: support for EDNS DE flag (DELEG-aware signal)

This commit is contained in:
Libor Peltan 2025-12-19 10:43:34 +01:00 committed by Daniel Salzman
parent 44d9404035
commit 57bbf2b059
11 changed files with 78 additions and 6 deletions

View file

@ -177,6 +177,9 @@ Options
**+**\ [\ **no**\ ]\ **dnssec**
Same as **+**\ [\ **no**\ ]\ **doflag**
**+**\ [\ **no**\ ]\ **deflag**
Set the DE flag.
**+**\ [\ **no**\ ]\ **all**
Show all packet sections.

View file

@ -261,7 +261,7 @@ static int answer_edns_init(const knot_pkt_t *query, knot_pkt_t *resp,
/* Set DO bit if set (DNSSEC requested). */
if (knot_pkt_has_dnssec(query)) {
knot_edns_set_do(&qdata->opt_rr);
}
} // TODO: also echo back DE bit if we are DELEG-aware?
/* Append NSID if requested and available. */
if (knot_pkt_edns_option(query, KNOT_EDNS_OPTION_NSID) != NULL) {

View file

@ -364,6 +364,15 @@ static inline bool knot_pkt_has_dnssec(const knot_pkt_t *pkt)
return knot_pkt_has_edns(pkt) && knot_edns_do(pkt->opt_rr);
}
/*!
* \brief Checks if DE bit is set in the packet's OPT RR.
*/
static inline bool knot_pkt_has_deleg_aware(const knot_pkt_t *pkt)
{
assert(pkt);
return knot_pkt_has_edns(pkt) && knot_edns_de(pkt->opt_rr);
}
/*!
* \brief Get specific EDNS option from a parsed packet.
*/

View file

@ -85,6 +85,7 @@ int knot_probe_data_set(knot_probe_data_t *data, knot_probe_proto_t proto,
data->query_edns.version = knot_edns_get_version(query->opt_rr);
data->query_edns.present = 1;
data->query_edns.flag_do = knot_edns_do(query->opt_rr);
data->query_edns.flag_de = knot_edns_de(query->opt_rr);
if (query->edns_opts != NULL) {
for (int i = 0; i <= KNOT_EDNS_MAX_OPTION_CODE; i++) {
if (query->edns_opts->ptr[i] != NULL) {

View file

@ -72,7 +72,8 @@ typedef struct {
uint8_t version; /*!< EDNS version. */
uint8_t present : 1; /*!< EDNS presence indication. */
uint8_t flag_do : 1; /*!< DO flag indication. */
uint8_t reserved : 6; /*!< Unused. */
uint8_t flag_de : 1; /*!< DE flag indication. */
uint8_t reserved : 5; /*!< Unused. */
} query_edns;
struct {

View file

@ -987,6 +987,8 @@ static void wire_ednsflags_to_str(rrset_dump_params_t *p)
if ((mask & KNOT_EDNS_DO_MASK)) {
dump_string(p, "DO");
} else if ((mask & KNOT_EDNS_DE_MASK)) {
dump_string(p, "DE");
} else {
dump_str_uint(p, "BIT", i);
}

View file

@ -28,6 +28,7 @@ enum {
/*! \brief Bit mask for DO bit. */
KNOT_EDNS_DO_MASK = (uint32_t)(1 << 15),
KNOT_EDNS_DE_MASK = (uint32_t)(1 << 13),
/*! \brief Minimal UDP payload with EDNS enabled. */
KNOT_EDNS_MIN_UDP_PAYLOAD = 512,
@ -259,6 +260,12 @@ bool knot_edns_do(const knot_rrset_t *opt_rr)
assert(opt_rr != NULL);
return opt_rr->ttl & KNOT_EDNS_DO_MASK;
}
static inline
bool knot_edns_de(const knot_rrset_t *opt_rr)
{
assert(opt_rr != NULL);
return opt_rr->ttl & KNOT_EDNS_DE_MASK;
}
/*!
* \brief Sets the DO bit in the OPT RR.
@ -274,6 +281,12 @@ void knot_edns_set_do(knot_rrset_t *opt_rr)
assert(opt_rr != NULL);
opt_rr->ttl |= KNOT_EDNS_DO_MASK;
}
static inline
void knot_edns_set_de(knot_rrset_t *opt_rr)
{
assert(opt_rr != NULL);
opt_rr->ttl |= KNOT_EDNS_DE_MASK;
}
/*!
* \brief Add EDNS option into the package with empty (zeroed) content.

View file

@ -336,9 +336,22 @@ static void print_section_opt(const knot_pkt_t *packet, const style_t *style)
ercode_str = unknown_ercode;
}
printf(";; Version: %u; flags: %s; UDP size: %u B; ext-rcode: %s\n",
char flags[96] = " ", *flend = flags;
for (uint32_t mask = 1 << 15, bit = 1; mask; mask >>= 1, bit++) {
if (packet->opt_rr->ttl & mask) {
if (mask & KNOT_EDNS_DO_MASK) {
flend += snprintf(flend, 4, " do");
} else if (mask & KNOT_EDNS_DE_MASK) {
flend += snprintf(flend, 4, " de");
} else {
flend += snprintf(flend, 7, " bit%u", bit);
}
}
}
printf(";; Version: %u; flags:%s; UDP size: %u B; ext-rcode: %s\n",
knot_edns_get_version(packet->opt_rr),
(knot_edns_do(packet->opt_rr) != 0) ? "do" : "",
flags,
knot_edns_get_payload(packet->opt_rr),
ercode_str);
@ -851,6 +864,8 @@ static void json_print_edns(jsonw_t *w, const knot_pkt_t *pkt)
if ((flags & mask)) {
if ((mask & KNOT_EDNS_DO_MASK)) {
jsonw_str(w, NULL, "DO");
} else if ((mask & KNOT_EDNS_DE_MASK)) {
jsonw_str(w, NULL, "DE");
} else {
(void)snprintf(tmp, sizeof(tmp), "BIT%d", i);
jsonw_str(w, NULL, tmp);

View file

@ -242,6 +242,9 @@ static int add_query_edns(knot_pkt_t *packet, const query_t *query, uint16_t max
if (query->flags.do_flag) {
knot_edns_set_do(&opt_rr);
}
if (query->flags.de_flag) {
knot_edns_set_de(&opt_rr);
}
/* Append NSID. */
if (query->nsid) {
@ -356,7 +359,7 @@ static bool use_edns(const query_t *query)
return query->edns > -1 || query->udp_size > -1 || query->nsid ||
query->zoneversion || query->subnet.family != AF_UNSPEC ||
query->flags.do_flag || query->cc.len > 0 || do_padding(query) ||
!ednsopt_list_empty(&query->edns_opts);
query->flags.de_flag || !ednsopt_list_empty(&query->edns_opts);
}
static knot_pkt_t *create_query_packet(const query_t *query)

View file

@ -40,7 +40,8 @@ static const flags_t DEFAULT_FLAGS_DIG = {
.z_flag = false,
.ad_flag = true,
.cd_flag = false,
.do_flag = false
.do_flag = false,
.de_flag = false,
};
static const style_t DEFAULT_STYLE_DIG = {
@ -275,6 +276,24 @@ static int opt_nodoflag(const char *arg, void *query)
return KNOT_EOK;
}
static int opt_deflag(const char *arg, void *query)
{
query_t *q = query;
q->flags.de_flag = true;
return KNOT_EOK;
}
static int opt_nodeflag(const char *arg, void *query)
{
query_t *q = query;
q->flags.de_flag = false;
return KNOT_EOK;
}
static int opt_all(const char *arg, void *query)
{
query_t *q = query;
@ -1550,6 +1569,9 @@ static const param_t kdig_opts2[] = {
{ "dnssec", ARG_NONE, opt_doflag }, // Alias.
{ "nodnssec", ARG_NONE, opt_nodoflag },
{ "deflag", ARG_NONE, opt_deflag },
{ "nodeflag", ARG_NONE, opt_nodeflag },
{ "all", ARG_NONE, opt_all },
{ "noall", ARG_NONE, opt_noall },
@ -2377,6 +2399,7 @@ static void print_help(void)
" +[no]cdflag Set CD flag.\n"
" +[no]doflag Set DO flag.\n"
" +[no]dnssec Same as +[no]doflag.\n"
" +[no]deflag Set DE flag.\n"
" +[no]all Show all packet sections.\n"
" +[no]qr Show query packet.\n"
" +[no]header * Show packet header.\n"

View file

@ -48,6 +48,8 @@ typedef struct {
bool cd_flag;
/*!< DNSSEC OK flag. */
bool do_flag;
/*!< DELEG-aware flag. */
bool de_flag;
} flags_t;
/*! \brief Basic parameters for DNS query. */