Browse Source

ipv6: fix sin6_scope_id and socket classification for link-local addresses

- CM_V6_ANY for :: socket (matches all v6 addr classes)
- sin6_scope_id from s->netif_index (not from local_addr where :: has scope=0)
- getnameinfo in stcp_link_connect to preserve scope_id in addr string
- scope_id in cm_invite_tcp_connect, ncd_create_links, connect_create_links_v6, cm_bg_ping_to_node
topo_upd
evgeny 2 months ago
parent
commit
f67bc23cd3
  1. 15
      src/routing_layer/conn_mgr_core.c
  2. 3
      src/routing_layer/conn_mgr_monitor.c
  3. 6
      src/routing_layer/conn_mgr_priv.h
  4. 13
      src/transport_layer/etcp_connect.c
  5. 1
      src/transport_layer/etcp_connections.c
  6. 1
      src/transport_layer/etcp_connections.h
  7. 4
      src/transport_layer/node_conn_direct.c
  8. 3
      src/transport_layer/stcp_link.c

15
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; 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), /* Классификация IPv6-адреса: link-local (fe80), локальный ULA (fc/fd),
* глобальный/прямой, другое (loopback, multicast, ::). */ * глобальный/прямой, другое (loopback, multicast, ::). */
uint8_t cm_classify_v6_addr(const uint8_t addr[16]) { 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; 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; const uint8_t* a6 = ((const struct sockaddr_in6*)&s->local_addr)->sin6_addr.s6_addr;
static const uint8_t z[16]; 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); 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) { 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; 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); 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)); struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6));
etcp_link_new(conn, s, &sa, 0); 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; if (!(a6->protocol&TOPO_PROTO_UDP)) continue;
uint8_t tc=cm_classify_v6_addr(a6->addr); if(tc==CM_V6_OTH) 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; 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; 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; if (!(a6->protocol & TOPO_PROTO_TCP)) continue;
struct sockaddr_in6 sin6; memset(&sin6,0,sizeof(sin6)); sin6.sin6_family=AF_INET6; 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); 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 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, 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}; .peer_pubkey=ni->public_key, .peer_pubkey_mode=0, .remote_addr=&sa, .remote_port=a6->port};

3
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; 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; 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); 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; struct ETCP_SOCKET* s = mgr->instance->etcp_sockets;
while (s) { if (s->local_addr.ss_family == AF_INET6) break; s = s->next; } while (s) { if (s->local_addr.ss_family == AF_INET6) break; s = s->next; }
if (!s) break; 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); 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; return;
} }

6
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_classify_v6_addr(const uint8_t addr[16]);
uint8_t cm_sock_v6_classify(const struct ETCP_SOCKET* s); 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 */ /* indirect */
void cm_exchange_timeout_cb(void* arg); void cm_exchange_timeout_cb(void* arg);
void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CM_EXCHANGE_RESP* resp); void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CM_EXCHANGE_RESP* resp);

13
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; 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; 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); 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)) { if (!(a->protocol & TOPO_PROTO_TCP)) {
struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; 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 ((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, 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, .peer_pubkey = ctx->conn->crypto_ctx.peer_public_key, .peer_pubkey_mode = 0,
.remote_addr = &sa, .remote_port = a->port}; .remote_addr = &sa, .remote_port = a->port};

1
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; int family = AF_INET;
if (ip) { if (ip) {
family = ip->ss_family; family = ip->ss_family;
e_sock->netif_index = netif_index;
if (family != AF_INET && family != AF_INET6) { if (family != AF_INET && family != AF_INET6) {
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Unsupported address family: %d", family); DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Unsupported address family: %d", family);
u_free(e_sock); u_free(e_sock);

1
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) 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 local_defaultroute_ip6[16]; // auto-detected IPv6 for public servers
uint8_t only_local; // 1 = only local connections, no forwarding 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 interface_addr; // адрес интерфейса: если bind на интерфейс - его IP, если 0.0.0.0 без интерфейса - IP интерфейса через который идет default route, иначе - адрес из конфига
struct sockaddr_storage nat_addr; // NAT адрес (network byte order), ss_family=0 = не определён struct sockaddr_storage nat_addr; // NAT адрес (network byte order), ss_family=0 = не определён
struct ll_queue* links_queue; // хеш-очередь линков, ключ = link_queue_entry.key (19 байт) struct ll_queue* links_queue; // хеш-очередь линков, ключ = link_queue_entry.key (19 байт)

4
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; if (zero) continue;
struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; 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); 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)); 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++;
} }
} }
} }

3
src/transport_layer/stcp_link.c

@ -12,6 +12,7 @@
#include "../lib/mem.h" #include "../lib/mem.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <netdb.h>
struct stcp_server { struct stcp_server {
struct stcp_server *srv; // stcp_server from stcp_server.h 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); port = cfg->remote_port ? cfg->remote_port : ntohs(sa->sin_port);
} else if (family == AF_INET6) { } else if (family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)cfg->remote_addr; 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); port = cfg->remote_port ? cfg->remote_port : ntohs(sa6->sin6_port);
} else { } else {
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "stcp_link: unsupported address family %d", family); DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "stcp_link: unsupported address family %d", family);

Loading…
Cancel
Save