}
}
+static void ede_passthru(const knot_pkt_t *pkt, struct kr_request *req)
+{
+ const uint8_t *ede_raw = pkt->edns_opts ?
+ pkt->edns_opts->ptr[KNOT_EDNS_OPTION_EDE] : NULL;
+ if (!ede_raw) return;
+ kr_require(ede_raw[0] * 256 + ede_raw[1] == KNOT_EDNS_OPTION_EDE);
+ uint16_t ede_len = ede_raw[2] * 256 + ede_raw[3];
+ if (ede_len < 2) return;
+ uint16_t ede_code = ede_raw[4] * 256 + ede_raw[5];
+ if (ede_code >= KNOT_EDNS_EDE_INDETERMINATE // long range of DNSSEC codes
+ && ede_code <= KNOT_EDNS_EDE_NSEC_MISS) {
+ kr_request_set_extended_error(req, ede_code, "V5T7: forwarded EDE code");
+ }
+}
+
/** Resolve input query or continue resolution with followups.
*
* This roughly corresponds to RFC1034, 5.3.3 4a-d.
}
ret = KR_STATE_FAIL;
selection_error = KR_SELECTION_SERVFAIL;
+ if (query->flags.FORWARD) {
+ /* additionally pass some of the EDE codes through */
+ ede_passthru(pkt, req);
+ }
break;
case KNOT_RCODE_FORMERR:
ret = KR_STATE_FAIL;
break;
case KR_SELECTION_REFUSED:
case KR_SELECTION_SERVFAIL:
+ if (qry->flags.FORWARD || qry->flags.STUB) {
+ /* The NS might not be broken, but this state is just for this query
+ * and it doesn't make sense to retry on the same NS immediately. */
+ addr_state->broken = true;
+ break;
+ }
+ /* For authoritative servers we try some fallback workarounds. */
if (qry->flags.NO_MINIMIZE && qry->flags.NO_0X20 && qry->flags.TCP) {
addr_state->broken = true;
} else if (qry->flags.NO_MINIMIZE) {
update_address_state(addr_state, address, addr_len, qry);
- if (addr_state->generation == -1) {
+ if (addr_state->generation == -1 || addr_state->broken) {
continue;
}
addr_state->choice_array_index = i;