diff --git a/lib/selection.c b/lib/selection.c index 1f47e159b602e06b0a1e5bae3848ae60c3e48d0d..5a829bb18c66f2d35f240903a5d504621270a699 100644 --- a/lib/selection.c +++ b/lib/selection.c @@ -230,7 +230,7 @@ static void check_tls_capable(struct address_state *address_state, /* TODO: uncomment these once we actually use the information it collects. */ /** * Check if there is a existing TCP connection to this address. - * + * * @p req has to have the selection_context properly initiazed. */ void check_tcp_connections(struct address_state *address_state, struct kr_request *req, struct sockaddr *address) { @@ -567,6 +567,11 @@ void error(struct kr_query *qry, struct address_state *addr_state, qry->flags.NO_MINIMIZE = true; } break; + case KR_SELECTION_TCP_CONNECT_FAILED: + case KR_SELECTION_TCP_CONNECT_TIMEOUT: + qry->server_selection.local_state->force_udp = true; + qry->flags.NO_0X20 = false; + break; case KR_SELECTION_NOTIMPL: case KR_SELECTION_OTHER_RCODE: case KR_SELECTION_DNSSEC_ERROR: @@ -576,8 +581,6 @@ void error(struct kr_query *qry, struct address_state *addr_state, addr_state->broken = true; break; case KR_SELECTION_TLS_HANDSHAKE_FAILED: - case KR_SELECTION_TCP_CONNECT_FAILED: - case KR_SELECTION_TCP_CONNECT_TIMEOUT: /* These might get resolved by retrying. */ break; default: @@ -587,7 +590,7 @@ void error(struct kr_query *qry, struct address_state *addr_state, addr_state->error_count++; addr_state->errors[sel_error]++; - + WITH_VERBOSE(qry) { KR_DNAME_GET_STR(ns_name, transport->ns_name); diff --git a/lib/selection.h b/lib/selection.h index 59e478bca7c814206a2f5edaf8222300b91ddd0a..5b7bf15f99a676f2ab9fc302b15b902d1b980d25 100644 --- a/lib/selection.h +++ b/lib/selection.h @@ -81,6 +81,8 @@ struct local_state { /** Force resolution of a new NS name (if possible) * Done by selection.c:error in some cases. */ bool force_resolve; + /** Used to work around auths with broken TCP. */ + bool force_udp; void *private; /**< Inner state of the implementation.*/ }; diff --git a/lib/selection_iter.c b/lib/selection_iter.c index 61e1080df451042d555e8285e81485c9a532320f..97feead5604f585283892f16dc2a5d3265aa75bd 100644 --- a/lib/selection_iter.c +++ b/lib/selection_iter.c @@ -99,7 +99,7 @@ static void unpack_state_from_zonecut(struct iter_local_state *local_state, name_state->a_state = RECORD_UNKNOWN; name_state->aaaa_state = RECORD_UNKNOWN; } - + /* Iterate over all addresses of this NS (if any). */ for (uint8_t *obj = pack_head(*addresses); obj != pack_tail(*addresses); obj = pack_obj_next(obj)) { @@ -284,6 +284,14 @@ void iter_choose_transport(struct kr_query *qry, struct kr_transport **transport assert(0); break; } + + if (*transport && + (*transport)->protocol==KR_TRANSPORT_TCP && + !qry->server_selection.local_state->truncated && + qry->server_selection.local_state->force_udp) { + // Last chance on broken TCP. + (*transport)->protocol = KR_TRANSPORT_UDP; + } } if (*transport == NULL && local_state->last_error == KR_SELECTION_DNSSEC_ERROR) {