From 09195b2f61cbe1856845545d78a5216b0f955e5e Mon Sep 17 00:00:00 2001 From: Evgeny Date: Mon, 13 Apr 2026 20:40:16 +0300 Subject: [PATCH] Add IPv6 support for sockets and connections - Add get_node_v6_sockets() function in route_node - Add local_defaultroute_ip6 field to ETCP_SOCKET - Fix IPv6 address logging in bind, init, new connection - Fix socket lookup for IPv6 in init_connections - Fix route_ping_handle_req to support both v4 and v6 sockets --- src/etcp_connections.c | 36 +++++++++++--- src/etcp_connections.h | 1 + src/route_node.c | 18 +++++++ src/route_node.h | 9 ++++ src/route_ping.c | 108 +++++++++++++++++++++++++---------------- 5 files changed, 124 insertions(+), 48 deletions(-) diff --git a/src/etcp_connections.c b/src/etcp_connections.c index 79aa31fb..995df57f 100644 --- a/src/etcp_connections.c +++ b/src/etcp_connections.c @@ -115,6 +115,9 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset) { if (link->remote_addr.ss_family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)&link->remote_addr; DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] INIT sending to %s:%d, link=%p, rst_req=%d", ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port), link, reset); + } else if (link->remote_addr.ss_family == AF_INET6) { + struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&link->remote_addr; + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] INIT sending to %s:%d, link=%p, rst_req=%d", ip_to_str(&sin6->sin6_addr, AF_INET6).str, ntohs(sin6->sin6_port), link, reset); } etcp_encrypt_send(dgram); @@ -518,15 +521,24 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S if (ip->ss_family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)ip; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[ETCP] Failed to bind to %s:%d", ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); + } else if (ip->ss_family == AF_INET6) { + struct sockaddr_in6* sin6 = (struct sockaddr_in6*)ip; + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[ETCP] Failed to bind to %s:%d", ip_to_str(&sin6->sin6_addr, AF_INET6).str, ntohs(sin6->sin6_port)); } socket_close_wrapper(e_sock->fd); u_free(e_sock); return NULL; } - struct sockaddr_in* sin = (struct sockaddr_in*)ip; - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Successfully bound socket to local address, family=%d %s:%d", ip->ss_family, ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); - DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Listen socket initialized: name=%s fd=%d addr=%s:%d", e_sock->name, e_sock->fd, ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); + if (ip->ss_family == AF_INET) { + struct sockaddr_in* sin = (struct sockaddr_in*)ip; + 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)); + DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Listen socket initialized: name=%s fd=%d addr=%s:%d", e_sock->name, e_sock->fd, ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); + } else if (ip->ss_family == AF_INET6) { + struct sockaddr_in6* sin6 = (struct sockaddr_in6*)ip; + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Successfully bound socket to local address, family=AF_INET6 %s:%d", ip_to_str(&sin6->sin6_addr, AF_INET6).str, ntohs(sin6->sin6_port)); + DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Listen socket initialized: name=%s fd=%d addr=%s:%d", e_sock->name, e_sock->fd, ip_to_str(&sin6->sin6_addr, AF_INET6).str, ntohs(sin6->sin6_port)); + } } e_sock->instance = instance; e_sock->errorcode = 0; @@ -1235,7 +1247,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) { conn->peer_node_id=peer_id; etcp_update_log_name(conn); DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "New connection received on socket %s: log_name=%s peer_id=%lu", e_sock->name, conn->log_name, (unsigned long)peer_id); - DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "New connection from %s peer_id=%ld etcp=%p", ip_to_str(&((struct sockaddr_in *)&addr)->sin_addr.s_addr, addr.ss_family).str, peer_id, conn); + DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "New connection from %s peer_id=%ld etcp=%p", ip_to_str(&addr, addr.ss_family).str, peer_id, conn); conn->next = e_sock->instance->connections; e_sock->instance->connections = conn; e_sock->instance->connections_count++; @@ -1546,10 +1558,12 @@ int init_sockets(struct UTUN_INSTANCE* instance) { struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, server); if (e_sock && default_ip != 0) { - struct in_addr addr; - addr.s_addr = default_ip; - DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Server %s type %d ip=%s", server->name, server->type, ip_to_str(&addr, AF_INET).str); e_sock->local_defaultroute_ip = default_ip; + if (server->ip.ss_family == AF_INET) { + struct in_addr addr; + addr.s_addr = default_ip; + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Server %s type %d ip=%s", server->name, server->type, ip_to_str(&addr, AF_INET).str); + } } if (!e_sock) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create socket for server %s", server->name); @@ -1669,6 +1683,14 @@ int init_connections(struct UTUN_INSTANCE* instance) { e_sock = sock; break; } + } else if (sock->local_addr.ss_family == AF_INET6) { + struct sockaddr_in6* sock_addr6 = (struct sockaddr_in6*)&sock->local_addr; + struct sockaddr_in6* srv_addr6 = (struct sockaddr_in6*)&local_server->ip; + if (memcmp(&sock_addr6->sin6_addr, &srv_addr6->sin6_addr, 16) == 0 && + sock_addr6->sin6_port == srv_addr6->sin6_port) { + e_sock = sock; + break; + } } } sock = sock->next; diff --git a/src/etcp_connections.h b/src/etcp_connections.h index e1ff3b99..44808db7 100644 --- a/src/etcp_connections.h +++ b/src/etcp_connections.h @@ -69,6 +69,7 @@ struct ETCP_SOCKET { void* socket_id; // Socket ID from uasync_add_socket uint8_t type; // CFG_SERVER_TYPE_PUBLIC/NAT/PRIVATE uint32_t local_defaultroute_ip; // auto-detected IPv4 for public servers (network byte order) + uint8_t local_defaultroute_ip6[16]; // auto-detected IPv6 for public servers }; // ETCP Link - одно динамическое соединение (один путь) diff --git a/src/route_node.c b/src/route_node.c index 09fee4cf..73153515 100644 --- a/src/route_node.c +++ b/src/route_node.c @@ -42,6 +42,24 @@ int get_node_v4_sockets(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SOCK return (int)info->local_v4_sockets; } +int get_node_v6_sockets(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_SOCKET **out_sockets) { + if (!node || !out_sockets) { + return -1; + } + *out_sockets = NULL; + const struct NODEINFO *info = &node->node; + if (info->local_v6_sockets == 0) { + return 0; + } + const uint8_t *dynamic = (const uint8_t *)&node->node + sizeof(struct NODEINFO); + dynamic += info->node_name_len; + dynamic += info->local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET); + *out_sockets = (const struct NODEINFO_IPV6_SOCKET *)dynamic; + DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "get_node_v6_sockets: returned %u IPv6 sockets from node %p", + (unsigned)info->local_v6_sockets, (void*)node); + return (int)info->local_v6_sockets; +} + int get_node_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SUBNET **out_subnets) { if (!node || !out_subnets) { return -1; diff --git a/src/route_node.h b/src/route_node.h index 1f4b1d51..76bb9c24 100644 --- a/src/route_node.h +++ b/src/route_node.h @@ -103,4 +103,13 @@ int get_node_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SUBNET * */ int get_node_v4_sockets(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SOCKET **out_sockets); +/** + * @brief Получает указатель на массив IPv6-сокетов узла. + * + * @param node Указатель на NODEINFO_Q + * @param out_sockets [out] указатель на первый элемент массива NODEINFO_IPV6_SOCKET + * @return количество сокетов (>= 0) или -1 при ошибке + */ +int get_node_v6_sockets(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_SOCKET **out_sockets); + #endif // ROUTE_NODE_H diff --git a/src/route_ping.c b/src/route_ping.c index 5050929f..43b9a3b3 100644 --- a/src/route_ping.c +++ b/src/route_ping.c @@ -296,10 +296,13 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, c } return; } - const struct NODEINFO_IPV4_SOCKET* sockets; - int sock_count = get_node_v4_sockets(target, &sockets); - if (sock_count <= 0 || !sockets) { - DEBUG_WARN(DEBUG_CATEGORY_BGP, "route_ping_handle_req: no IPv4 sockets for node %016llx", + const struct NODEINFO_IPV4_SOCKET* sockets_v4 = NULL; + const struct NODEINFO_IPV6_SOCKET* sockets_v6 = NULL; + int sock_count_v4 = get_node_v4_sockets(target, &sockets_v4); + int sock_count_v6 = get_node_v6_sockets(target, &sockets_v6); + + if ((sock_count_v4 <= 0 || !sockets_v4) && (sock_count_v6 <= 0 || !sockets_v6)) { + DEBUG_WARN(DEBUG_CATEGORY_BGP, "route_ping_handle_req: no sockets for node %016llx", (unsigned long long)req_pkt->node_id); struct route_ping_req* req = u_calloc(1, sizeof(struct route_ping_req)); if (req) { @@ -311,15 +314,19 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, c } return; } - // считаем подходящие локальные сокеты AF_INET - uint8_t local_count = 0; + + // считаем подходящие локальные сокеты (v4 + v6) + uint8_t local_v4_count = 0; + uint8_t local_v6_count = 0; struct ETCP_SOCKET* ls = bgp->instance->etcp_sockets; while (ls) { - if (ls->local_addr.ss_family == AF_INET) local_count++; + if (ls->local_addr.ss_family == AF_INET) local_v4_count++; + else if (ls->local_addr.ss_family == AF_INET6) local_v6_count++; ls = ls->next; } + uint8_t local_count = local_v4_count + local_v6_count; if (local_count == 0) { - DEBUG_WARN(DEBUG_CATEGORY_BGP, "route_ping_handle_req: no local IPv4 sockets"); + DEBUG_WARN(DEBUG_CATEGORY_BGP, "route_ping_handle_req: no local sockets"); struct route_ping_req* req = u_calloc(1, sizeof(struct route_ping_req)); if (req) { req->reply_conn = from_conn; @@ -340,47 +347,66 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, c req->target_node = target; req->timeout_ms = req_pkt->timeout_ms; req->socket_count = local_count; - // заполняем target_addr из первого сокета узла (можно расширить на все) - struct sockaddr_storage target_addr; - memset(&target_addr, 0, sizeof(target_addr)); - struct sockaddr_in* sin = (struct sockaddr_in*)&target_addr; - sin->sin_family = AF_INET; - memcpy(&sin->sin_addr, sockets[0].addr, 4); - sin->sin_port = htons(sockets[0].port); + ls = bgp->instance->etcp_sockets; uint8_t idx = 0; while (ls) { + struct sockaddr_storage target_addr; + memset(&target_addr, 0, sizeof(target_addr)); + if (ls->local_addr.ss_family == AF_INET) { - req->sockets[idx].local_sock = ls; - struct route_ping_series* series = u_calloc(1, sizeof(struct route_ping_series)); - if (series) { - series->req = req; - series->sock_ctx = &req->sockets[idx]; - series->local_sock = ls; - series->target_addr = target_addr; - memcpy(series->pubkey, target->node.public_key, SC_PUBKEY_SIZE); - series->count_total = req_pkt->count; - series->count_sent = 0; - series->count_ok = 0; - series->rtt_sum = 0; - series->timeout_ms = req_pkt->timeout_ms; - series->interval_ms = req_pkt->interval_ms; - int ret = etcp_send_ping_to_socket(bgp->instance, ls, target->node.public_key, - &target_addr, req_pkt->timeout_ms, route_ping_cb, series, NULL, 0); - if (ret != 0) { - // сразу считаем fail - series->sock_ctx->avg_rtt = req_pkt->timeout_ms * 10; - series->sock_ctx->count_sent = req_pkt->count; - req->completed_count++; - u_free(series); - } + if (sock_count_v4 > 0 && sockets_v4) { + struct sockaddr_in* sin = (struct sockaddr_in*)&target_addr; + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr, sockets_v4[0].addr, 4); + sin->sin_port = htons(sockets_v4[0].port); + } else { + ls = ls->next; + continue; + } + } else if (ls->local_addr.ss_family == AF_INET6) { + if (sock_count_v6 > 0 && sockets_v6) { + struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&target_addr; + sin6->sin6_family = AF_INET6; + memcpy(&sin6->sin6_addr, sockets_v6[0].addr, 16); + sin6->sin6_port = htons(sockets_v6[0].port); } else { - req->sockets[idx].avg_rtt = req_pkt->timeout_ms * 10; - req->sockets[idx].count_sent = req_pkt->count; + ls = ls->next; + continue; + } + } else { + ls = ls->next; + continue; + } + + req->sockets[idx].local_sock = ls; + struct route_ping_series* series = u_calloc(1, sizeof(struct route_ping_series)); + if (series) { + series->req = req; + series->sock_ctx = &req->sockets[idx]; + series->local_sock = ls; + series->target_addr = target_addr; + memcpy(series->pubkey, target->node.public_key, SC_PUBKEY_SIZE); + series->count_total = req_pkt->count; + series->count_sent = 0; + series->count_ok = 0; + series->rtt_sum = 0; + series->timeout_ms = req_pkt->timeout_ms; + series->interval_ms = req_pkt->interval_ms; + int ret = etcp_send_ping_to_socket(bgp->instance, ls, target->node.public_key, + &target_addr, req_pkt->timeout_ms, route_ping_cb, series, NULL, 0); + if (ret != 0) { + series->sock_ctx->avg_rtt = req_pkt->timeout_ms * 10; + series->sock_ctx->count_sent = req_pkt->count; req->completed_count++; + u_free(series); } - idx++; + } else { + req->sockets[idx].avg_rtt = req_pkt->timeout_ms * 10; + req->sockets[idx].count_sent = req_pkt->count; + req->completed_count++; } + idx++; ls = ls->next; } if (req->completed_count >= req->socket_count) {