Don't stash a packet with mismatching QNAME+QTYPE.
When receiving an NXDOMAIN or NODATA packet in an insecure zone,
it would get cached with KR_RANK_INSECURE regardless of mismatch
in QNAME. If the 0x20 pattern was preserved in the fake QNAME,
such packet would then be used to answer queries with matching QNAME,
even if there's no proof that this QNAME is insecure.
Knot Resolver 4.x.y (2019-0m-dd)
================================
+Security
+--------
+- fix CVE-2019-10191: caching negative answer with forged QNAME+QTYPE
+
Improvements
------------
- DNS-over-HTTPS: answers include `access-control-allow-origin: *` (!823)
_Bool DNS64_MARK : 1;
_Bool CACHE_TRIED : 1;
_Bool NO_NS_FOUND : 1;
+ _Bool PKT_IS_SANE : 1;
};
typedef struct {
knot_rrset_t **at;
/* LATER(optim.): typically we also have corresponding NS record in the list,
* so we might save a cache operation. */
- if (check_dname_for_lf(knot_pkt_qname(pkt), qry)) {
+ if (qry->flags.PKT_IS_SANE && check_dname_for_lf(knot_pkt_qname(pkt), qry)) {
stash_pkt(pkt, qry, req, needs_pkt);
}
uint16_t qtype = query->stype;
const knot_dname_t *qname = minimized_qname(query, &qtype);
+ /* ID should already match, thanks to session_tasklist_del_msgid()
+ * in worker_submit(), but it won't hurt to check again. */
return query->id == knot_wire_get_id(answer->wire) &&
knot_wire_get_qdcount(answer->wire) > 0 &&
query->sclass == knot_pkt_qclass(answer) &&
if (!query) {
return ctx->state;
}
+ query->flags.PKT_IS_SANE = false;
WITH_VERBOSE(query) {
if (query->flags.TRACE) {
return KR_STATE_CONSUME;
}
+ /* If exiting above here, there's no sense to put it into packet cache.
+ * The most important part is to check for spoofing: is_paired_to_query() */
+ query->flags.PKT_IS_SANE = true;
+
#ifndef NOVERBOSELOG
const knot_lookup_t *rcode = knot_lookup_by_id(knot_rcode_names, knot_wire_get_rcode(pkt->wire));
#endif
bool DNS64_MARK : 1; /**< Internal mark for dns64 module. */
bool CACHE_TRIED : 1; /**< Internal to cache module. */
bool NO_NS_FOUND : 1; /**< No valid NS found during last PRODUCE stage. */
+ bool PKT_IS_SANE : 1; /**< Set by iterator in consume phase to indicate whether
+ * some basic aspects of the packet are OK, e.g. QNAME. */
};
/** Combine flags together. This means set union for simple flags. */