fix: 当前的 relay 实现原来只记了一个“最后发包的下游客户端地址”

This commit is contained in:
Mock
2026-04-10 12:13:19 +08:00
parent 6c5d410bdc
commit 6cedf859db
2 changed files with 145 additions and 2 deletions

View File

@@ -15,6 +15,7 @@ struct udp_relay {
struct sockaddr_storage client_addr;
socklen_t client_addr_len;
int has_client;
struct udp_relay_route *routes;
pthread_mutex_t lock;
pthread_mutex_t log_mu;
pthread_mutex_t state_mu;
@@ -29,6 +30,13 @@ struct udp_relay {
int closed;
};
typedef struct udp_relay_route {
struct udp_relay_route *next;
uint32_t conv;
struct sockaddr_storage client_addr;
socklen_t client_addr_len;
} udp_relay_route_t;
static void udp_relay_parse_kcp_summary(const uint8_t *packet, size_t len, int *has_conv, uint32_t *conv, size_t *segment_count) {
size_t offset = 0;
size_t count = 0;
@@ -139,6 +147,38 @@ static void udp_relay_record_client(udp_relay_t *relay, const struct sockaddr_st
pthread_mutex_unlock(&relay->lock);
}
static int udp_relay_record_route(udp_relay_t *relay, uint32_t conv, const struct sockaddr_storage *addr, socklen_t addr_len) {
udp_relay_route_t *route;
if (relay == NULL || addr == NULL || addr_len == 0) {
errno = EINVAL;
return -1;
}
pthread_mutex_lock(&relay->lock);
for (route = relay->routes; route != NULL; route = route->next) {
if (route->conv == conv) {
memcpy(&route->client_addr, addr, sizeof(*addr));
route->client_addr_len = addr_len;
pthread_mutex_unlock(&relay->lock);
return 0;
}
}
route = (udp_relay_route_t *) calloc(1, sizeof(*route));
if (route == NULL) {
pthread_mutex_unlock(&relay->lock);
return -1;
}
route->conv = conv;
memcpy(&route->client_addr, addr, sizeof(*addr));
route->client_addr_len = addr_len;
route->next = relay->routes;
relay->routes = route;
pthread_mutex_unlock(&relay->lock);
return 0;
}
static int udp_relay_copy_client(udp_relay_t *relay, struct sockaddr_storage *addr, socklen_t *addr_len) {
int has_client;
@@ -152,6 +192,42 @@ static int udp_relay_copy_client(udp_relay_t *relay, struct sockaddr_storage *ad
return has_client;
}
static int udp_relay_copy_route(udp_relay_t *relay, uint32_t conv, struct sockaddr_storage *addr, socklen_t *addr_len) {
udp_relay_route_t *route;
pthread_mutex_lock(&relay->lock);
for (route = relay->routes; route != NULL; route = route->next) {
if (route->conv == conv) {
memcpy(addr, &route->client_addr, sizeof(*addr));
*addr_len = route->client_addr_len;
pthread_mutex_unlock(&relay->lock);
return 1;
}
}
pthread_mutex_unlock(&relay->lock);
return 0;
}
static void udp_relay_clear_routes(udp_relay_t *relay) {
udp_relay_route_t *route;
udp_relay_route_t *next;
if (relay == NULL) {
return;
}
pthread_mutex_lock(&relay->lock);
route = relay->routes;
relay->routes = NULL;
pthread_mutex_unlock(&relay->lock);
while (route != NULL) {
next = route->next;
free(route);
route = next;
}
}
static void *udp_relay_forward_downstream_to_upstream(void *arg) {
udp_relay_t *relay = (udp_relay_t *) arg;
uint8_t buffer[UDP_RELAY_BUF_SIZE];
@@ -160,6 +236,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;
@@ -175,6 +253,10 @@ static void *udp_relay_forward_downstream_to_upstream(void *arg) {
}
udp_relay_record_client(relay, &source, source_len);
udp_relay_parse_kcp_summary(buffer, (size_t) n, &has_conv, &conv, NULL);
if (has_conv) {
(void) udp_relay_record_route(relay, 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 +287,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 +304,9 @@ 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 ((has_conv && !udp_relay_copy_route(relay, conv, &client_addr, &client_addr_len)) &&
!udp_relay_copy_client(relay, &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;
}
@@ -409,6 +495,7 @@ void udp_relay_free(udp_relay_t *relay) {
}
udp_relay_close(relay);
udp_relay_join_threads(relay);
udp_relay_clear_routes(relay);
pthread_mutex_destroy(&relay->lock);
pthread_mutex_destroy(&relay->log_mu);
pthread_cond_destroy(&relay->state_cond);