diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index efa21285..d9c39764 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -777,6 +777,14 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S u_free(e_sock); return NULL; } + socklen_t bound_len = sizeof(e_sock->local_addr); + if (getsockname(e_sock->fd, (struct sockaddr*)&e_sock->local_addr, &bound_len) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socket %s: cannot read bound address: %s", + name, socket_strerror(socket_get_error())); + socket_close_wrapper(e_sock->fd); u_free(e_sock); return NULL; + } + // Порт 0 выбирает ОС; NODEINFO и подбор сокетов должны видеть фактический адрес. + e_sock->interface_addr = e_sock->local_addr; if (bind_addr->ss_family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)bind_addr; DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Successfully bound socket to local address, family=AF_INET %s:%d", ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); diff --git a/src/transport_layer/stcp_link.c b/src/transport_layer/stcp_link.c index 29da9d8b..95ddc3a8 100644 --- a/src/transport_layer/stcp_link.c +++ b/src/transport_layer/stcp_link.c @@ -179,12 +179,28 @@ struct stcp_server *stcp_server_listen(struct stcp_link_config *cfg, uint16_t po ss->srv = stcp_server_create(cfg->inst->ua, port, &cfg->inst->my_keys, cfg->inst->my_ed25519_pubkey, cfg->inst, server_accept_cb, ss, NULL, NULL, cfg->listen_family); if (!ss->srv) { u_free(ss); return NULL; } + uint16_t bound_port = stcp_server_get_port(ss->srv); + if (!bound_port) { stcp_server_destroy(ss->srv); u_free(ss); return NULL; } + if (tcp_sock) { + if (tcp_sock->local_addr.ss_family == AF_INET) { + ((struct sockaddr_in*)&tcp_sock->local_addr)->sin_port = htons(bound_port); + ((struct sockaddr_in*)&tcp_sock->interface_addr)->sin_port = htons(bound_port); + } else if (tcp_sock->local_addr.ss_family == AF_INET6) { + ((struct sockaddr_in6*)&tcp_sock->local_addr)->sin6_port = htons(bound_port); + ((struct sockaddr_in6*)&tcp_sock->interface_addr)->sin6_port = htons(bound_port); + } + } if (cfg->reality_enabled && cfg->inst && cfg->inst->config) stcp_server_set_reality(ss->srv, &cfg->inst->config->global.reality); - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "port=%u", port); + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "listen requested_port=%u bound_port=%u", port, bound_port); return ss; } +uint16_t stcp_link_server_get_port(const struct stcp_server *ss) { + if (!ss || !ss->srv) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp link server: missing listener"); return 0; } + return stcp_server_get_port(ss->srv); +} + void stcp_link_server_destroy(struct stcp_server *ss) { if (!ss) return; if (ss->srv) stcp_server_destroy(ss->srv); diff --git a/src/transport_layer/stcp_link.h b/src/transport_layer/stcp_link.h index 35dd5ae3..5a7030f7 100644 --- a/src/transport_layer/stcp_link.h +++ b/src/transport_layer/stcp_link.h @@ -38,6 +38,8 @@ typedef void (*stcp_server_on_link_cb)(struct stcp_link *link, struct ETCP_SOCKE struct stcp_server *stcp_server_listen(struct stcp_link_config *cfg, uint16_t port, stcp_server_on_link_cb on_link, struct ETCP_SOCKET *tcp_sock); void stcp_link_server_destroy(struct stcp_server *srv); +// Фактический порт слушателя адаптера (включая listen с port=0); 0 при ошибке. +uint16_t stcp_link_server_get_port(const struct stcp_server *srv); /* Server list management (multiple servers per instance) */ void stcp_server_list_add(struct UTUN_INSTANCE *inst, struct stcp_server *srv); diff --git a/tests/test_ncd_config.c b/tests/test_ncd_config.c index c8ea2572..af1f25e8 100644 --- a/tests/test_ncd_config.c +++ b/tests/test_ncd_config.c @@ -7,6 +7,7 @@ #include "transport_layer/etcp.h" #include "transport_layer/etcp_connections.h" #include "transport_layer/node_conn_direct.h" +#include "transport_layer/stcp_link.h" #include "../lib/u_async.h" #include "../lib/debug_config.h" @@ -33,6 +34,19 @@ int main(void) { "[server: udp]\naddr=127.0.0.1:0\ntype=public\n" "[server: tcp]\naddr=127.0.0.1:0\ntype=public\ntransport=tcp\n"); assert(inst && utun_instance_init(inst) >= 0); + for (struct ETCP_SOCKET* sock = inst->etcp_sockets; sock; sock = sock->next) { + uint16_t port; + if (sock->is_tcp) { + struct stcp_server* listener = stcp_server_list_find_by_sock(inst, sock); assert(listener); + port = stcp_link_server_get_port(listener); + } else { + struct sockaddr_storage bound; socklen_t size = sizeof(bound); + assert(getsockname(sock->fd, (struct sockaddr*)&bound, &size) == 0); + port = ss_get_port(&bound); + } + assert(port && ss_get_port(&sock->local_addr) == port && ss_get_port(&sock->interface_addr) == port); + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "ephemeral %s socket=%s actual_port=%u verified", sock->is_tcp ? "TCP" : "UDP", sock->name, port); + } struct CFG_SERVER *udp = NULL, *tcp = NULL; for (struct CFG_SERVER* s = inst->config->servers; s; s = s->next) { if (!strcmp(s->name, "udp")) udp = s;