diff --git a/src/routing_layer/conn_mgr_core.c b/src/routing_layer/conn_mgr_core.c index 864477a1..66c26c45 100644 --- a/src/routing_layer/conn_mgr_core.c +++ b/src/routing_layer/conn_mgr_core.c @@ -76,11 +76,6 @@ int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t tcfg, uint8_t tnat) { return 0; } -#define CM_V6_LL 0 -#define CM_V6_LOC 1 -#define CM_V6_DIR 2 -#define CM_V6_OTH 3 - /* Классификация IPv6-адреса: link-local (fe80), локальный ULA (fc/fd), * глобальный/прямой, другое (loopback, multicast, ::). */ uint8_t cm_classify_v6_addr(const uint8_t addr[16]) { @@ -96,7 +91,7 @@ uint8_t cm_sock_v6_classify(const struct ETCP_SOCKET* s) { if (s->local_addr.ss_family != AF_INET6) return CM_V6_OTH; const uint8_t* a6 = ((const struct sockaddr_in6*)&s->local_addr)->sin6_addr.s6_addr; static const uint8_t z[16]; - if (!memcmp(a6, z, 16)) return CM_V6_DIR; + if (!memcmp(a6, z, 16)) return CM_V6_ANY; return cm_classify_v6_addr(a6); } @@ -110,7 +105,7 @@ void cm_add_v4_link(struct ETCP_CONN* conn, const uint8_t* addr, uint16_t port, void cm_add_v6_link(struct ETCP_CONN* conn, const uint8_t addr[16], uint16_t port, struct ETCP_SOCKET* s) { struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, addr, 16); sin6.sin6_port = htons(port); - if (cm_classify_v6_addr(addr) == CM_V6_LL) { struct sockaddr_in6* our = (struct sockaddr_in6*)&s->local_addr; sin6.sin6_scope_id = our->sin6_scope_id; } + if (cm_classify_v6_addr(addr) == CM_V6_LL) sin6.sin6_scope_id = s->netif_index; struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); etcp_link_new(conn, s, &sa, 0); } @@ -556,7 +551,7 @@ static void cm_direct_add_links(struct ETCP_CONN* conn, struct CONN_MGR_ENTRY* e if (!(a6->protocol&TOPO_PROTO_UDP)) continue; uint8_t tc=cm_classify_v6_addr(a6->addr); if(tc==CM_V6_OTH) continue; struct ETCP_SOCKET* s=entry->mgr->instance->etcp_sockets; - while(s){if(cm_sock_v6_classify(s)==tc){cm_add_v6_link(conn,a6->addr,a6->port,s);any=1;} s=s->next;} + while(s){uint8_t sc=cm_sock_v6_classify(s);if(sc==CM_V6_ANY||sc==tc){cm_add_v6_link(conn,a6->addr,a6->port,s);any=1;} s=s->next;} } if (any) return; @@ -828,6 +823,10 @@ static int cm_invite_tcp_connect(struct cm_invite_pending* inv, const struct TOP if (!(a6->protocol & TOPO_PROTO_TCP)) continue; struct sockaddr_in6 sin6; memset(&sin6,0,sizeof(sin6)); sin6.sin6_family=AF_INET6; memcpy(&sin6.sin6_addr,a6->addr,16); sin6.sin6_port=htons(a6->port); + if (cm_classify_v6_addr(a6->addr) == CM_V6_LL) { + struct ETCP_SOCKET* sv = inv->mgr->instance->etcp_sockets; + while (sv) { if (sv->local_addr.ss_family == AF_INET6 && sv->netif_index) { sin6.sin6_scope_id = sv->netif_index; break; } sv = sv->next; } + } struct sockaddr_storage sa; memcpy(&sa,&sin6,sizeof(sin6)); struct stcp_link_config cfg = {.ua=inv->mgr->instance->ua, .my_keys=&inv->mgr->instance->my_keys, .inst=inv->mgr->instance, .peer_pubkey=ni->public_key, .peer_pubkey_mode=0, .remote_addr=&sa, .remote_port=a6->port}; diff --git a/src/routing_layer/conn_mgr_monitor.c b/src/routing_layer/conn_mgr_monitor.c index d9ddc93b..0df701d4 100644 --- a/src/routing_layer/conn_mgr_monitor.c +++ b/src/routing_layer/conn_mgr_monitor.c @@ -96,10 +96,11 @@ static void cm_bg_ping_to_node(struct CONN_MGR* mgr, struct TOPO_NODE* ni) { if (a6->type != TOPO_ADDR_NAT && a6->type != TOPO_ADDR_INTERFACE) continue; struct sockaddr_in6 sin6; memset(&sin6,0,sizeof(sin6)); sin6.sin6_family=AF_INET6; memcpy(&sin6.sin6_addr,a6->addr,16); sin6.sin6_port=htons(a6->port); - struct sockaddr_storage sa; memcpy(&sa,&sin6,sizeof(sin6)); struct ETCP_SOCKET* s = mgr->instance->etcp_sockets; while (s) { if (s->local_addr.ss_family == AF_INET6) break; s = s->next; } if (!s) break; + if (cm_classify_v6_addr(a6->addr) == CM_V6_LL) sin6.sin6_scope_id = s->netif_index; + struct sockaddr_storage sa; memcpy(&sa,&sin6,sizeof(sin6)); etcp_send_ping_to_socket(mgr->instance, s, ni->public_key, &sa, CONN_PROBE_TIMEOUT_MS, cm_bg_ping_noop_cb, NULL, NULL, 0, 0); return; } diff --git a/src/routing_layer/conn_mgr_priv.h b/src/routing_layer/conn_mgr_priv.h index ac3b8582..dab51d12 100644 --- a/src/routing_layer/conn_mgr_priv.h +++ b/src/routing_layer/conn_mgr_priv.h @@ -177,6 +177,12 @@ int cm_has_local_addr(struct CONN_MGR* mgr, struct TOPO_GROUP_NODE* nq); uint8_t cm_classify_v6_addr(const uint8_t addr[16]); uint8_t cm_sock_v6_classify(const struct ETCP_SOCKET* s); +#define CM_V6_LL 0 +#define CM_V6_LOC 1 +#define CM_V6_DIR 2 +#define CM_V6_OTH 3 +#define CM_V6_ANY 4 + /* indirect */ void cm_exchange_timeout_cb(void* arg); void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CM_EXCHANGE_RESP* resp); diff --git a/src/transport_layer/etcp_connect.c b/src/transport_layer/etcp_connect.c index fb9f6b73..d51c323e 100644 --- a/src/transport_layer/etcp_connect.c +++ b/src/transport_layer/etcp_connect.c @@ -107,12 +107,21 @@ static void connect_create_links_v6(struct ETCP_CONNECT* ctx, struct TOPO_GROUP_ int zero = 1; for (int j = 0; j < 16; j++) if (a->addr[j] != 0) { zero = 0; break; } if (zero) continue; struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, a->addr, 16); sin6.sin6_port = htons(a->port); - struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); + int is_ll = (a->addr[0] == 0xfe && (a->addr[1] & 0xc0) == 0x80); if (!(a->protocol & TOPO_PROTO_TCP)) { struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; - while (s) { if (s->local_addr.ss_family == AF_INET6) etcp_link_new(ctx->conn, s, &sa, 0); s = s->next; } + while (s) { if (s->local_addr.ss_family == AF_INET6) { + if (is_ll) sin6.sin6_scope_id = s->netif_index; + struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); + etcp_link_new(ctx->conn, s, &sa, 0); + } s = s->next; } } if ((a->protocol & TOPO_PROTO_TCP) && !ctx->tcp_link) { + if (is_ll) { struct ETCP_SOCKET* sv = ctx->instance->etcp_sockets; + while (sv) { if (sv->local_addr.ss_family == AF_INET6 && sv->netif_index) + { sin6.sin6_scope_id = sv->netif_index; break; } sv = sv->next; } + } + struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); struct stcp_link_config tcp_cfg = {.ua = ctx->instance->ua, .my_keys = &ctx->instance->my_keys, .inst = ctx->instance, .peer_pubkey = ctx->conn->crypto_ctx.peer_public_key, .peer_pubkey_mode = 0, .remote_addr = &sa, .remote_port = a->port}; diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index 223e5139..004f20ed 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -532,6 +532,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S int family = AF_INET; if (ip) { family = ip->ss_family; + e_sock->netif_index = netif_index; if (family != AF_INET && family != AF_INET6) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Unsupported address family: %d", family); u_free(e_sock); diff --git a/src/transport_layer/etcp_connections.h b/src/transport_layer/etcp_connections.h index 41f61a47..a525af07 100644 --- a/src/transport_layer/etcp_connections.h +++ b/src/transport_layer/etcp_connections.h @@ -144,6 +144,7 @@ struct ETCP_SOCKET { 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 uint8_t only_local; // 1 = only local connections, no forwarding + uint32_t netif_index; // индекс интерфейса для sin6_scope_id (0 = не задан) struct sockaddr_storage interface_addr; // адрес интерфейса: если bind на интерфейс - его IP, если 0.0.0.0 без интерфейса - IP интерфейса через который идет default route, иначе - адрес из конфига struct sockaddr_storage nat_addr; // NAT адрес (network byte order), ss_family=0 = не определён struct ll_queue* links_queue; // хеш-очередь линков, ключ = link_queue_entry.key (19 байт) diff --git a/src/transport_layer/node_conn_direct.c b/src/transport_layer/node_conn_direct.c index 2d0e4558..82d03dd9 100644 --- a/src/transport_layer/node_conn_direct.c +++ b/src/transport_layer/node_conn_direct.c @@ -152,8 +152,10 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni, if (zero) continue; struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, a->addr, 16); sin6.sin6_port = htons(a->port); + struct ETCP_SOCKET* use_sock = socks[rr++ % sock_count]; + if ((a->addr[0] == 0xfe && (a->addr[1] & 0xc0) == 0x80)) sin6.sin6_scope_id = use_sock->netif_index; struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); - if (etcp_link_new(conn, socks[rr++ % sock_count], &sa, 0)) link_count++; + if (etcp_link_new(conn, use_sock, &sa, 0)) link_count++; } } } diff --git a/src/transport_layer/stcp_link.c b/src/transport_layer/stcp_link.c index 37a5655c..3e06519c 100644 --- a/src/transport_layer/stcp_link.c +++ b/src/transport_layer/stcp_link.c @@ -12,6 +12,7 @@ #include "../lib/mem.h" #include #include +#include struct stcp_server { struct stcp_server *srv; // stcp_server from stcp_server.h @@ -142,7 +143,7 @@ struct stcp_link *stcp_link_connect(struct stcp_link_config *cfg) { port = cfg->remote_port ? cfg->remote_port : ntohs(sa->sin_port); } else if (family == AF_INET6) { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)cfg->remote_addr; - inet_ntop(AF_INET6, &sa6->sin6_addr, addr_str, sizeof(addr_str)); + getnameinfo((struct sockaddr*)sa6, sizeof(*sa6), addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST); port = cfg->remote_port ? cfg->remote_port : ntohs(sa6->sin6_port); } else { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "stcp_link: unsupported address family %d", family);