]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon: fix assertion errors on duplicate peers
authorOto Šťáva <oto.stava@nic.cz>
Wed, 22 Mar 2023 09:07:08 +0000 (10:07 +0100)
committerOto Šťáva <oto.stava@nic.cz>
Wed, 22 Mar 2023 09:07:08 +0000 (10:07 +0100)
Not sure if this is completely correct.

daemon/http.c
daemon/session2.c
daemon/tls.c
daemon/worker.c

index d028113be9393905c9fca9df99fcc81863db590e..2d51b7dab09cfeeb06587967380c46507e3ec27d 100644 (file)
@@ -934,7 +934,7 @@ static enum protolayer_iter_cb_result pl_http_unwrap(
        ssize_t ret = 0;
 
        if (!http->h2)
-               return kr_error(ENOSYS);
+               return protolayer_break(ctx, kr_error(ENOSYS));
 
        struct protolayer_payload pld = ctx->payload;
        if (pld.type == PROTOLAYER_PAYLOAD_WIRE_BUF) {
index 278e74895def768be22983392eaf01e97d59d7bf..5df2dfcf258dfef19c900714cb61a9fcf3f00af6 100644 (file)
@@ -436,6 +436,11 @@ static int protolayer_step(struct protolayer_iter_ctx *ctx)
                protolayer_iter_cb cb = (ctx->direction == PROTOLAYER_UNWRAP)
                        ? globals->unwrap : globals->wrap;
 
+               if (ctx->manager->session->closing) {
+                       return protolayer_iter_ctx_finish(
+                                       ctx, kr_error(ECANCELED));
+               }
+
                if (cb) {
                        struct protolayer_data *sess_data = protolayer_sess_data_get(
                                        ctx->manager, ctx->layer_ix);
index 74092c5d6eeef3429c0da25b9114b07da25bf8ab..6cddfb132802cbc3c87070ef8059e659df1ee160 100644 (file)
@@ -286,7 +286,10 @@ static int tls_handshake(struct pl_tls_sess_data *tls, struct session2 *session)
                                gnutls_strerror_name(err), err);
                /* Notify the peer about handshake failure via an alert. */
                gnutls_alert_send_appropriate(tls->tls_session, err);
-               session2_event(session, PROTOLAYER_EVENT_CONNECT_FAIL,
+               enum protolayer_event_type etype = (tls->first_handshake_done)
+                       ? PROTOLAYER_EVENT_DISCONNECT
+                       : PROTOLAYER_EVENT_CONNECT_FAIL;
+               session2_event(session, etype,
                                (void *)KR_SELECTION_TLS_HANDSHAKE_FAILED);
                return kr_error(EIO);
        } else if (err == GNUTLS_E_WARNING_ALERT_RECEIVED) {
index db63f0259f421eebb622a77b237313cdf3336bd5..2e8fcfe300afd5dd6d7b90ca6a597468bdf15513 100644 (file)
@@ -1420,8 +1420,8 @@ static int trie_add_tcp_session(trie_t *trie, const struct sockaddr *addr,
        if (keylen < 0)
                return keylen;
        trie_val_t *val = trie_get_ins(trie, key.bytes, keylen);
-       if (kr_fails_assert(*val == NULL))
-               return kr_error(EINVAL);
+       if (*val != NULL)
+               return kr_error(EEXIST);
        *val = session;
        return kr_ok();
 }
@@ -1883,10 +1883,8 @@ static enum protolayer_event_cb_result pl_dns_stream_resolution_timeout(
                        char *peer_str = kr_straddr(peer);
                        kr_log_debug(IO, "=> closing connection to '%s'\n",
                                       peer_str ? peer_str : "");
-                       if (s->outgoing) {
-                               worker_del_tcp_waiting(peer);
-                               worker_del_tcp_connected(peer);
-                       }
+                       worker_del_tcp_waiting(peer);
+                       worker_del_tcp_connected(peer);
                        session2_close(s);
                }
        }
@@ -1904,18 +1902,26 @@ static enum protolayer_event_cb_result pl_dns_stream_connected(
 
        struct sockaddr *peer = session2_get_peer(session);
        if (session->outgoing && worker_del_tcp_waiting(peer) != 0) {
-               /* session isn't in list of waiting queries, *
+               /* session isn't in list of waiting queries,
                 * something gone wrong */
-               session2_waitinglist_finalize(session, KR_STATE_FAIL);
-               kr_assert(session2_tasklist_is_empty(session));
-               session2_close(session);
-               return PROTOLAYER_EVENT_CONSUME;
+               goto fail;
        }
 
-       worker_add_tcp_connected(peer, session);
+       int err = worker_add_tcp_connected(peer, session);
+       if (err) {
+               /* Could not add session to the list of connected, something
+                * went wrong. */
+               goto fail;
+       }
 
        send_waiting(session);
        return PROTOLAYER_EVENT_PROPAGATE;
+
+fail:
+       session2_waitinglist_finalize(session, KR_STATE_FAIL);
+       kr_assert(session2_tasklist_is_empty(session));
+       session2_close(session);
+       return PROTOLAYER_EVENT_CONSUME;
 }
 
 static enum protolayer_event_cb_result pl_dns_stream_connection_fail(
@@ -1967,12 +1973,13 @@ static enum protolayer_event_cb_result pl_dns_stream_connection_fail(
 static enum protolayer_event_cb_result pl_dns_stream_disconnected(
                struct session2 *session)
 {
-       if (!session->connected)
-               return PROTOLAYER_EVENT_PROPAGATE;
-
        struct sockaddr *peer = session2_get_peer(session);
        worker_del_tcp_waiting(peer);
        worker_del_tcp_connected(peer);
+
+       if (!session->connected)
+               return PROTOLAYER_EVENT_PROPAGATE;
+
        session->connected = false;
 
        while (!session2_waitinglist_is_empty(session)) {
@@ -2025,25 +2032,31 @@ static enum protolayer_event_cb_result pl_dns_stream_event_unwrap(
        if (session->closing)
                return PROTOLAYER_EVENT_PROPAGATE;
 
-       if (event == PROTOLAYER_EVENT_GENERAL_TIMEOUT) {
+       switch (event) {
+       case PROTOLAYER_EVENT_GENERAL_TIMEOUT:
                return pl_dns_stream_resolution_timeout(manager->session);
-       } else if (event == PROTOLAYER_EVENT_CONNECT_TIMEOUT) {
+
+       case PROTOLAYER_EVENT_CONNECT_TIMEOUT:
                return pl_dns_stream_connection_fail(manager->session,
                                KR_SELECTION_TCP_CONNECT_TIMEOUT);
-       } else if (event == PROTOLAYER_EVENT_CONNECT) {
+
+       case PROTOLAYER_EVENT_CONNECT:
                return pl_dns_stream_connected(session);
-       } else if (event == PROTOLAYER_EVENT_DISCONNECT
-                       || event == PROTOLAYER_EVENT_CLOSE
-                       || event == PROTOLAYER_EVENT_FORCE_CLOSE) {
-               return pl_dns_stream_disconnected(session);
-       } else if (event == PROTOLAYER_EVENT_CONNECT_FAIL) {
+
+       case PROTOLAYER_EVENT_CONNECT_FAIL:;
                enum kr_selection_error err = (*baton)
                        ? *(enum kr_selection_error *)baton
                        : KR_SELECTION_TCP_CONNECT_FAILED;
                return pl_dns_stream_connection_fail(manager->session, err);
-       }
 
-       return PROTOLAYER_EVENT_PROPAGATE;
+       case PROTOLAYER_EVENT_DISCONNECT:
+       case PROTOLAYER_EVENT_CLOSE:
+       case PROTOLAYER_EVENT_FORCE_CLOSE:
+               return pl_dns_stream_disconnected(session);
+
+       default:
+               return PROTOLAYER_EVENT_PROPAGATE;
+       }
 }
 
 static knot_pkt_t *stream_produce_packet(struct session2 *session,