]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon/io: penalize servers that close without reply
authorVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 19 Jan 2023 17:54:11 +0000 (18:54 +0100)
committerAleš Mrázek <ales.mrazek@nic.cz>
Thu, 26 Jan 2023 12:06:39 +0000 (12:06 +0000)
daemon/io.c
daemon/session.c
daemon/session.h
daemon/worker.c
daemon/worker.h

index 47aecccb148504018ef1e4ed42ccbaa6fbd04b22..48bfed301554a1ddc2e93f11c09df315447ad7b5 100644 (file)
@@ -337,6 +337,33 @@ void tcp_timeout_trigger(uv_timer_t *timer)
        }
 }
 
+static void tcp_disconnect(struct session *s, int errcode)
+{
+       if (kr_log_is_debug(IO, NULL)) {
+               struct sockaddr *peer = session_get_peer(s);
+               char *peer_str = kr_straddr(peer);
+               kr_log_debug(IO, "=> connection to '%s' closed by peer (%s)\n",
+                              peer_str ? peer_str : "",
+                              uv_strerror(errcode));
+       }
+
+       if (!session_was_useful(s) && session_flags(s)->outgoing) {
+               /* We want to penalize the IP address, if a task is asking a query.
+                * It might not be the right task, but that doesn't matter so much
+                * for attributing the useless session to the IP address. */
+               struct qr_task *t = session_tasklist_get_first(s);
+               struct kr_query *qry = NULL;
+               if (t) {
+                       struct kr_request *req = worker_task_request(t);
+                       qry = array_tail(req->rplan.pending);
+               }
+               if (qry) /* We reuse the error for connection, as it's quite similar. */
+                       qry->server_selection.error(qry, worker_task_get_transport(t),
+                                                       KR_SELECTION_TCP_CONNECT_FAILED);
+       }
+       worker_end_tcp(s);
+}
+
 static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
 {
        struct session *s = handle->data;
@@ -354,14 +381,7 @@ static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
        }
 
        if (nread < 0 || !buf->base) {
-               if (kr_log_is_debug(IO, NULL)) {
-                       struct sockaddr *peer = session_get_peer(s);
-                       char *peer_str = kr_straddr(peer);
-                       kr_log_debug(IO, "=> connection to '%s' closed by peer (%s)\n",
-                                      peer_str ? peer_str : "",
-                                      uv_strerror(nread));
-               }
-               worker_end_tcp(s);
+               tcp_disconnect(s, nread);
                return;
        }
 
index 97256be24374e4247a98d24c12acb72d0f3f00a7..a1f22072b0ccf89a01262ab397d6abbf507358c1 100644 (file)
@@ -51,6 +51,7 @@ struct session {
        ssize_t wire_buf_end_idx;     /**< Data end offset in wire_buf. */
        uint64_t last_activity;       /**< Time of last IO activity (if any occurs).
                                       *   Otherwise session creation time. */
+       bool was_useful;              /**< I.e. produced a DNS message at some point. */
 };
 
 static void on_session_close(uv_handle_t *handle)
@@ -122,6 +123,11 @@ void session_close(struct session *session)
        }
 }
 
+bool session_was_useful(const struct session *session)
+{
+       return session->was_useful;
+}
+
 int session_start_read(struct session *session)
 {
        return io_start_read(session->handle);
@@ -628,7 +634,7 @@ knot_pkt_t *session_produce_packet(struct session *session, knot_mm_t *mm)
                return NULL;
        }
 
-
+       session->was_useful = true;
        knot_pkt_t *pkt = knot_pkt_new(msg_start, msg_size, mm);
        session->sflags.wirebuf_error = (pkt == NULL);
        return pkt;
index eccf45b5f0e98cd8d5841cb61858351a7182147e..603d7cb450f2cc72f90839d9ad26e4570fb2890e 100644 (file)
@@ -91,6 +91,8 @@ int session_tasklist_finalize_expired(struct session *session);
 /** Both of task lists (associated & waiting). */
 /** Check if empty. */
 bool session_is_empty(const struct session *session);
+/** Return whether session seems to have done something useful. */
+bool session_was_useful(const struct session *session);
 /** Get pointer to session flags */
 struct session_flags *session_flags(struct session *session);
 /** Get pointer to peer address. */
index c8feb16ac0888d6c1e4ac5e035b6edb50c531cb4..8b6b49e67338d4ff709695aec6d23855eabdec32 100644 (file)
@@ -2111,6 +2111,11 @@ struct request_ctx *worker_task_get_request(struct qr_task *task)
        return task->ctx;
 }
 
+struct kr_transport *worker_task_get_transport(struct qr_task *task)
+{
+       return task->transport;
+}
+
 struct session *worker_request_get_source_session(const struct kr_request *req)
 {
        static_assert(offsetof(struct request_ctx, req) == 0,
index 8885aebb57f1e8d129786678abb57314e4e163f4..fd9b1f3a00a81f5bd69dd2f325d05a9c0a9da9b8 100644 (file)
@@ -108,6 +108,8 @@ knot_pkt_t *worker_task_get_pktbuf(const struct qr_task *task);
 
 struct request_ctx *worker_task_get_request(struct qr_task *task);
 
+struct kr_transport *worker_task_get_transport(struct qr_task *task);
+
 /** Note: source session is NULL in case the request hasn't come over network. */
 KR_EXPORT struct session *worker_request_get_source_session(const struct kr_request *req);