From 154682db4ab832a8f5a5ea54a6196978c6259ffd Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 12 Jul 2026 20:42:56 +0200 Subject: [PATCH] Add 30-second idle and 60-second pre-request deadlines, updates activity timestamps during TCP/TLS progress, and apply receive timeouts to emulation sockets. This prevents incomplete plaintext or TLS requests from occupying a connection indefinitely, including byte-trickle attempts. Signed-off-by: Pol Henarejos --- src/usb/lwip/rest_server.c | 30 +++++++++++++++++++++++++++++- src/usb/lwip/rest_server.h | 2 ++ src/usb/lwip/rest_server_tls.c | 10 ++++++++-- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/usb/lwip/rest_server.c b/src/usb/lwip/rest_server.c index ee763c0..13ca575 100644 --- a/src/usb/lwip/rest_server.c +++ b/src/usb/lwip/rest_server.c @@ -52,6 +52,7 @@ typedef int socket_t; #include #include #include +#include #include #endif #else @@ -61,6 +62,8 @@ typedef int socket_t; #define REST_SESSION_TIMEOUT_INACTIVITY_MS (10 * 60 * 1000) // 10 minutes #define REST_SESSION_TIMEOUT_TOTAL_MS (2 * 60 * 60 * 1000) // 2 hours +#define REST_CONN_TIMEOUT_MS (30 * 1000) +#define REST_CONN_TOTAL_TIMEOUT_MS (60 * 1000) #ifndef ENABLE_EMULATION static struct tcp_pcb *listener_pcb = NULL; @@ -287,6 +290,8 @@ static rest_conn_t *alloc_conn( if (!conns[i].in_use) { memset(&conns[i], 0, sizeof(conns[i])); conns[i].in_use = true; + conns[i].opened_ms = board_millis(); + conns[i].last_progress_ms = board_millis(); #ifdef ENABLE_EMULATION conns[i].sock = sock; struct sockaddr_in addr; @@ -1214,6 +1219,7 @@ static err_t rest_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err } pbuf_copy_partial(p, buffer + *len, p->tot_len, 0); *len += p->tot_len; + conn->last_progress_ms = board_millis(); tcp_recved(pcb, p->tot_len); pbuf_free(p); if (conn->conn_type == REST_CONN_TLS) { @@ -1226,6 +1232,15 @@ static err_t rest_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err static err_t rest_poll(void *arg, struct tcp_pcb *pcb) { rest_conn_t *conn = (rest_conn_t *)arg; LWIP_UNUSED_ARG(pcb); + if (conn == NULL) { + return ERR_OK; + } + uint32_t now = board_millis(); + if (now - conn->last_progress_ms >= REST_CONN_TIMEOUT_MS || + (!conn->request_dispatched && now - conn->opened_ms >= REST_CONN_TOTAL_TIMEOUT_MS)) { + rest_close_conn(conn); + return ERR_ABRT; + } if (conn != NULL && conn->tx_pending) { return rest_lwip_continue_send(conn); } @@ -1379,15 +1394,27 @@ static void *rest_emulation_thread(void *arg) { (void)close(accepted); continue; } +#ifndef _MSC_VER + { + struct timeval timeout = { .tv_sec = REST_CONN_TIMEOUT_MS / 1000, .tv_usec = 0 }; + (void)setsockopt(accepted, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + } +#endif if (conn->conn_type == REST_CONN_TLS) { mbedtls_ssl_init(&conn->ssl); if (mbedtls_ssl_setup(&conn->ssl, &tls_conf) != 0) { rest_close_conn(conn); continue; } - mbedtls_ssl_set_bio(&conn->ssl, &conn->sock, tls_send_cb, tls_recv_cb, NULL); + mbedtls_ssl_set_bio(&conn->ssl, conn, tls_send_cb, tls_recv_cb, NULL); } while (conn->in_use) { + uint32_t now = board_millis(); + if (now - conn->last_progress_ms >= REST_CONN_TIMEOUT_MS || + (!conn->request_dispatched && now - conn->opened_ms >= REST_CONN_TOTAL_TIMEOUT_MS)) { + rest_close_conn(conn); + break; + } if (conn->conn_type == REST_CONN_TLS) { /* TLS on emulation reads directly from socket through mbedtls BIO callbacks. */ if (tls_progress_conn(conn) != ERR_OK) { @@ -1402,6 +1429,7 @@ static void *rest_emulation_thread(void *arg) { break; } conn->request_len += (size_t)n; + conn->last_progress_ms = board_millis(); if (conn->request_len > REST_MAX_REQUEST_SIZE) { send_json_error(conn, 413, "payload_too_large"); break; diff --git a/src/usb/lwip/rest_server.h b/src/usb/lwip/rest_server.h index 8707dc2..f5fbe44 100644 --- a/src/usb/lwip/rest_server.h +++ b/src/usb/lwip/rest_server.h @@ -57,6 +57,8 @@ typedef struct { struct tcp_pcb *pcb; #endif size_t request_len; + uint32_t opened_ms; + uint32_t last_progress_ms; rest_conn_type_t conn_type; #ifdef _MSC_VER char _padding[sizeof(void *) - sizeof(rest_conn_type_t)]; diff --git a/src/usb/lwip/rest_server_tls.c b/src/usb/lwip/rest_server_tls.c index 51ac356..551bbe2 100644 --- a/src/usb/lwip/rest_server_tls.c +++ b/src/usb/lwip/rest_server_tls.c @@ -191,9 +191,11 @@ int emulation_rest_tls_port(void) { } int tls_send_cb(void *ctx, const unsigned char *buf, size_t len) { - const socket_t fd = (socket_t)(*(const intptr_t *)ctx); + rest_conn_t *conn = (rest_conn_t *)ctx; + const socket_t fd = conn->sock; ssize_t r = send(fd, (const char *)buf, (int)len, 0); if (r >= 0) { + conn->last_progress_ms = board_millis(); return (int)r; } #ifdef _MSC_VER @@ -212,9 +214,11 @@ int tls_send_cb(void *ctx, const unsigned char *buf, size_t len) { } int tls_recv_cb(void *ctx, unsigned char *buf, size_t len) { - const socket_t fd = (socket_t)(*(const intptr_t *)ctx); + rest_conn_t *conn = (rest_conn_t *)ctx; + const socket_t fd = conn->sock; ssize_t r = recv(fd, (char *)buf, (int)len, 0); if (r > 0) { + conn->last_progress_ms = board_millis(); return (int)r; } if (r == 0) { @@ -313,6 +317,7 @@ err_t tls_progress_conn(rest_conn_t *conn) { return ERR_ABRT; } conn->handshake_done = true; + conn->last_progress_ms = board_millis(); } while (!conn->request_complete) { @@ -326,6 +331,7 @@ err_t tls_progress_conn(rest_conn_t *conn) { return ERR_ABRT; } conn->request_len += (size_t)ret; + conn->last_progress_ms = board_millis(); conn->request[conn->request_len] = '\0'; ret = request_is_complete(conn->request, conn->request_len, &payload_offset, &payload_len); if (ret < 0) {