From 9cd1f88bfc76004e21f8c97abdec6e3c8dede4d9 Mon Sep 17 00:00:00 2001 From: Mock Date: Thu, 2 Apr 2026 20:56:36 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BD=93=E5=89=8D=20relay=20=E5=BE=88?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E5=8F=AA=E8=AE=B0=E4=BD=8F=E4=BA=86=E2=80=9C?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E4=B8=8B=E6=B8=B8=20UDP=20=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server_udp_relay.c | 84 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/src/server_udp_relay.c b/src/server_udp_relay.c index ecf0eca..e36ce41 100644 --- a/src/server_udp_relay.c +++ b/src/server_udp_relay.c @@ -5,6 +5,13 @@ #define UDP_RELAY_BUF_SIZE (64U * 1024U) +typedef struct udp_relay_client_entry { + struct udp_relay_client_entry *next; + uint32_t conv; + struct sockaddr_storage addr; + socklen_t addr_len; +} udp_relay_client_entry_t; + struct udp_relay { int downstream_fd; int upstream_fd; @@ -12,9 +19,10 @@ struct udp_relay { socklen_t upstream_addr_len; char downstream_local_addr[OMNI_MAX_ADDR_TEXT]; char upstream_local_addr[OMNI_MAX_ADDR_TEXT]; - struct sockaddr_storage client_addr; - socklen_t client_addr_len; - int has_client; + struct sockaddr_storage last_client_addr; + socklen_t last_client_addr_len; + int has_last_client; + udp_relay_client_entry_t *clients; pthread_mutex_t lock; pthread_mutex_t log_mu; pthread_mutex_t state_mu; @@ -131,22 +139,55 @@ static void udp_relay_note_result(udp_relay_t *relay, int rc, int errnum) { pthread_mutex_unlock(&relay->state_mu); } -static void udp_relay_record_client(udp_relay_t *relay, const struct sockaddr_storage *addr, socklen_t addr_len) { +static udp_relay_client_entry_t *udp_relay_find_client_locked(udp_relay_t *relay, uint32_t conv) { + udp_relay_client_entry_t *entry; + + for (entry = relay->clients; entry != NULL; entry = entry->next) { + if (entry->conv == conv) { + return entry; + } + } + return NULL; +} + +static void udp_relay_record_client(udp_relay_t *relay, int has_conv, uint32_t conv, const struct sockaddr_storage *addr, socklen_t addr_len) { pthread_mutex_lock(&relay->lock); - memcpy(&relay->client_addr, addr, sizeof(*addr)); - relay->client_addr_len = addr_len; - relay->has_client = 1; + memcpy(&relay->last_client_addr, addr, sizeof(*addr)); + relay->last_client_addr_len = addr_len; + relay->has_last_client = 1; + if (has_conv) { + udp_relay_client_entry_t *entry = udp_relay_find_client_locked(relay, conv); + if (entry == NULL) { + entry = (udp_relay_client_entry_t *) calloc(1, sizeof(*entry)); + if (entry != NULL) { + entry->conv = conv; + entry->next = relay->clients; + relay->clients = entry; + } + } + if (entry != NULL) { + memcpy(&entry->addr, addr, sizeof(*addr)); + entry->addr_len = addr_len; + } + } pthread_mutex_unlock(&relay->lock); } -static int udp_relay_copy_client(udp_relay_t *relay, struct sockaddr_storage *addr, socklen_t *addr_len) { - int has_client; +static int udp_relay_copy_client(udp_relay_t *relay, int has_conv, uint32_t conv, struct sockaddr_storage *addr, socklen_t *addr_len) { + int has_client = 0; pthread_mutex_lock(&relay->lock); - has_client = relay->has_client; - if (has_client) { - memcpy(addr, &relay->client_addr, sizeof(*addr)); - *addr_len = relay->client_addr_len; + if (has_conv) { + udp_relay_client_entry_t *entry = udp_relay_find_client_locked(relay, conv); + if (entry != NULL) { + memcpy(addr, &entry->addr, sizeof(*addr)); + *addr_len = entry->addr_len; + has_client = 1; + } + } else if (relay->has_last_client) { + memcpy(addr, &relay->last_client_addr, sizeof(*addr)); + *addr_len = relay->last_client_addr_len; + has_client = 1; } pthread_mutex_unlock(&relay->lock); return has_client; @@ -160,6 +201,8 @@ static void *udp_relay_forward_downstream_to_upstream(void *arg) { struct sockaddr_storage source; socklen_t source_len = sizeof(source); ssize_t n = recvfrom(relay->downstream_fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &source, &source_len); + int has_conv = 0; + uint32_t conv = 0; if (n < 0) { int errnum = errno; @@ -174,7 +217,8 @@ static void *udp_relay_forward_downstream_to_upstream(void *arg) { return NULL; } - udp_relay_record_client(relay, &source, source_len); + udp_relay_parse_kcp_summary(buffer, (size_t) n, &has_conv, &conv, NULL); + udp_relay_record_client(relay, has_conv, conv, &source, source_len); udp_relay_print_packet(relay, "relay_downstream_rx", relay->downstream_local_addr, &source, source_len, buffer, (size_t) n); for (;;) { if (send(relay->upstream_fd, buffer, (size_t) n, 0) >= 0) { @@ -205,6 +249,8 @@ static void *udp_relay_forward_upstream_to_downstream(void *arg) { struct sockaddr_storage client_addr; socklen_t client_addr_len = 0; ssize_t n = recv(relay->upstream_fd, buffer, sizeof(buffer), 0); + int has_conv = 0; + uint32_t conv = 0; if (n < 0) { int errnum = errno; @@ -220,7 +266,8 @@ static void *udp_relay_forward_upstream_to_downstream(void *arg) { } udp_relay_print_packet(relay, "relay_upstream_rx", relay->upstream_local_addr, &relay->upstream_addr, relay->upstream_addr_len, buffer, (size_t) n); - if (!udp_relay_copy_client(relay, &client_addr, &client_addr_len)) { + udp_relay_parse_kcp_summary(buffer, (size_t) n, &has_conv, &conv, NULL); + if (!udp_relay_copy_client(relay, has_conv, conv, &client_addr, &client_addr_len)) { udp_relay_print_packet(relay, "relay_upstream_drop_no_client", relay->upstream_local_addr, &relay->upstream_addr, relay->upstream_addr_len, buffer, (size_t) n); continue; } @@ -404,11 +451,18 @@ int udp_relay_close(udp_relay_t *relay) { } void udp_relay_free(udp_relay_t *relay) { + udp_relay_client_entry_t *entry; + udp_relay_client_entry_t *next; + if (relay == NULL) { return; } udp_relay_close(relay); udp_relay_join_threads(relay); + for (entry = relay->clients; entry != NULL; entry = next) { + next = entry->next; + free(entry); + } pthread_mutex_destroy(&relay->lock); pthread_mutex_destroy(&relay->log_mu); pthread_cond_destroy(&relay->state_cond);