Browse Source

platform_compat: выбирать глобальный IPv6 (2000::/3) вместо ULA при выборе адреса интерфейса

v2
evgeny 3 weeks ago
parent
commit
94136564ee
  1. 63
      lib/platform_compat.c

63
lib/platform_compat.c

@ -60,6 +60,12 @@ int random_bytes(uint8_t *buffer, size_t len) {
#endif
}
/* Глобальный unicast IPv6 (2000::/3). При выборе адреса интерфейса предпочитаем его
* ULA (fc00::/7) и link-local (fe80::/10). */
static int ipv6_is_global_unicast(const uint8_t* a) {
return (a[0] & 0xe0) == 0x20;
}
#ifndef _WIN32
uint32_t get_interface_ip_by_index(uint32_t netif_index) {
struct ifaddrs *ifaddr, *ifa;
@ -89,7 +95,8 @@ int get_interface_ipv6_by_index(uint32_t netif_index, int temporary, uint8_t* ad
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1) return -1;
int found = 0;
uint8_t global_match[16], local_match[16];
int has_global = 0, has_local = 0;
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL) continue;
if (ifa->ifa_name == NULL) continue;
@ -100,20 +107,18 @@ int get_interface_ipv6_by_index(uint32_t netif_index, int temporary, uint8_t* ad
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)ifa->ifa_addr;
if ((sin6->sin6_addr.s6_addr[0] & 0xfe) == 0xfe && sin6->sin6_addr.s6_addr[1] == 0x80) continue;
int is_temporary = (ifa->ifa_flags & IFA_F_TEMPORARY) ? 1 : 0;
if (temporary && is_temporary) {
memcpy(addr_out, &sin6->sin6_addr, 16);
found = 1;
break;
}
if (!temporary && !is_temporary) {
memcpy(addr_out, &sin6->sin6_addr, 16);
found = 1;
break;
if ((temporary && !is_temporary) || (!temporary && is_temporary)) continue;
if (ipv6_is_global_unicast(sin6->sin6_addr.s6_addr)) {
if (!has_global) { memcpy(global_match, &sin6->sin6_addr, 16); has_global = 1; }
} else {
if (!has_local) { memcpy(local_match, &sin6->sin6_addr, 16); has_local = 1; }
}
}
freeifaddrs(ifaddr);
return found ? 0 : -1;
if (has_global) { memcpy(addr_out, global_match, 16); return 0; }
if (has_local) { memcpy(addr_out, local_match, 16); return 0; }
return -1;
}
#ifdef __linux__
@ -151,8 +156,8 @@ int get_interface_ipv6_addr_nl(uint32_t netif_index, int prefer_stable, uint8_t*
if (send(nl_sock, &req, req.nlh.nlmsg_len, 0) < 0) { close(nl_sock); return -1; }
uint8_t fallback[16], stable_addr[16], temp_addr[16];
int has_fallback = 0, has_stable = 0, has_temp = 0;
uint8_t fallback[16], g_stable[16], g_temp[16], l_stable[16], l_temp[16];
int has_fallback = 0, has_g_stable = 0, has_g_temp = 0, has_l_stable = 0, has_l_temp = 0;
char buf[8192];
int done = 0;
@ -181,19 +186,32 @@ int get_interface_ipv6_addr_nl(uint32_t netif_index, int prefer_stable, uint8_t*
int is_temp = (ifa_flags & IFA_F_TEMPORARY) != 0;
int is_mngtmp = (ifa_flags & IFA_F_MANAGETEMPADDR) != 0;
int is_global = ipv6_is_global_unicast(addr);
if (!has_fallback) { memcpy(fallback, addr, 16); has_fallback = 1; }
if (!has_stable && (!is_temp || is_mngtmp)) { memcpy(stable_addr, addr, 16); has_stable = 1; }
if (!has_temp && is_temp && !is_mngtmp) { memcpy(temp_addr, addr, 16); has_temp = 1; }
if (is_global) {
if (!has_g_stable && (!is_temp || is_mngtmp)) { memcpy(g_stable, addr, 16); has_g_stable = 1; }
if (!has_g_temp && is_temp && !is_mngtmp) { memcpy(g_temp, addr, 16); has_g_temp = 1; }
} else {
if (!has_l_stable && (!is_temp || is_mngtmp)) { memcpy(l_stable, addr, 16); has_l_stable = 1; }
if (!has_l_temp && is_temp && !is_mngtmp) { memcpy(l_temp, addr, 16); has_l_temp = 1; }
}
}
}
close(nl_sock);
if (prefer_stable && has_stable) { memcpy(addr_out, stable_addr, 16); return 0; }
if (!prefer_stable && has_temp) { memcpy(addr_out, temp_addr, 16); return 0; }
if (has_stable) { memcpy(addr_out, stable_addr, 16); return 0; }
if (has_temp) { memcpy(addr_out, temp_addr, 16); return 0; }
if (prefer_stable) {
if (has_g_stable) { memcpy(addr_out, g_stable, 16); return 0; }
if (has_g_temp) { memcpy(addr_out, g_temp, 16); return 0; }
if (has_l_stable) { memcpy(addr_out, l_stable, 16); return 0; }
if (has_l_temp) { memcpy(addr_out, l_temp, 16); return 0; }
} else {
if (has_g_temp) { memcpy(addr_out, g_temp, 16); return 0; }
if (has_g_stable) { memcpy(addr_out, g_stable, 16); return 0; }
if (has_l_temp) { memcpy(addr_out, l_temp, 16); return 0; }
if (has_l_stable) { memcpy(addr_out, l_stable, 16); return 0; }
}
if (has_fallback) { memcpy(addr_out, fallback, 16); return 0; }
return -1;
}
@ -335,6 +353,7 @@ int get_interface_ipv6_addr_nl(uint32_t netif_index, int prefer_stable, uint8_t*
PIP_ADAPTER_ADDRESSES adapters = plat_win_get_adapters(AF_INET6);
if (!adapters) return -1;
int found = 0;
uint8_t local_match[16]; int has_local = 0;
PIP_ADAPTER_ADDRESSES a = plat_win_find_adapter(adapters, netif_index);
if (a) {
for (PIP_ADAPTER_UNICAST_ADDRESS u = a->FirstUnicastAddress; u; u = u->Next) {
@ -344,12 +363,12 @@ int get_interface_ipv6_addr_nl(uint32_t netif_index, int prefer_stable, uint8_t*
{ static const uint8_t lb[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
if (memcmp(b, lb, 16) == 0) continue; } /* loopback */
{ static const uint8_t z[16]; if (memcmp(b, z, 16) == 0) continue; } /* :: */
memcpy(addr_out, b, 16);
found = 1;
break;
if (ipv6_is_global_unicast(b)) { memcpy(addr_out, b, 16); found = 1; break; }
if (!has_local) { memcpy(local_match, b, 16); has_local = 1; }
}
}
free(adapters);
if (!found && has_local) { memcpy(addr_out, local_match, 16); found = 1; }
return found ? 0 : -1;
}

Loading…
Cancel
Save