]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/selection{,_iter}.c: allow switching back to UDP
authorŠtěpán Balážik <stepan.balazik@nic.cz>
Thu, 18 Feb 2021 11:10:26 +0000 (12:10 +0100)
committerŠtěpán Balážik <stepan.balazik@nic.cz>
Thu, 18 Feb 2021 15:51:57 +0000 (16:51 +0100)
Switching to TCP instead of querying very slow servers over UDP has had
unwanted side effect – we would sometimes get stuck with a server
permanently switched to TCP. And if the server happens to not reply over
TCP we were in trouble.

Therefore after we TCP connect fails or timeouts we provide one last
chance for the server over UDP. This will not prevent the next request
to try TCP again on this server again, but we don't care because
DNS MUST ******* work over TCP.

lib/selection.c
lib/selection.h
lib/selection_iter.c

index 1f47e159b602e06b0a1e5bae3848ae60c3e48d0d..5a829bb18c66f2d35f240903a5d504621270a699 100644 (file)
@@ -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);
index 59e478bca7c814206a2f5edaf8222300b91ddd0a..5b7bf15f99a676f2ab9fc302b15b902d1b980d25 100644 (file)
@@ -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.*/
 };
 
index 61e1080df451042d555e8285e81485c9a532320f..97feead5604f585283892f16dc2a5d3265aa75bd 100644 (file)
@@ -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) {