diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index 64713fc1..223e5139 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -556,6 +556,13 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S if (socket_set_nonblocking(e_sock->fd) != 0) { DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "Failed to set non-blocking mode"); } + + if (family == AF_INET6) { + int v6only = 1; + if (setsockopt(e_sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) < 0) { + DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "Failed to set IPV6_V6ONLY: %s", socket_strerror(socket_get_error())); + } + } // Set socket mark if specified (Linux only) if (so_mark > 0) { @@ -637,15 +644,28 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S } else if (ip->ss_family == AF_INET6) { struct sockaddr_in6* sin6 = (struct sockaddr_in6*)ip; if (memcmp(&sin6->sin6_addr, &in6addr_any, sizeof(struct in6_addr)) == 0) { - // :: — определяем через default route - struct sockaddr_storage remote; - memset(&remote, 0, sizeof(remote)); - struct sockaddr_in6* rem_sin6 = (struct sockaddr_in6*)&remote; - rem_sin6->sin6_family = AF_INET6; - rem_sin6->sin6_port = htons(53); - inet_pton(AF_INET6, "2001:4860:4860::8888", &rem_sin6->sin6_addr); - if (get_outgoing_local_ip(ip, &remote, &e_sock->interface_addr) != 0) { - DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "Failed to detect outgoing local IPv6 for socket %s", e_sock->name); + // :: — приоритет: permanent > temporary > get_outgoing_local_ip + uint16_t v6if = (netif_index > 0) ? netif_index : get_default_route_netif_index(AF_INET6); + if (v6if > 0) { + uint8_t v6addr[16]; + int got = get_interface_ipv6_by_index(v6if, 0, v6addr); + if (got != 0) got = get_interface_ipv6_by_index(v6if, 1, v6addr); + if (got == 0) { + struct sockaddr_in6* if6 = (struct sockaddr_in6*)&e_sock->interface_addr; + if6->sin6_family = AF_INET6; + memcpy(&if6->sin6_addr, v6addr, 16); + } + } + if (e_sock->interface_addr.ss_family == 0) { + struct sockaddr_storage remote; + memset(&remote, 0, sizeof(remote)); + struct sockaddr_in6* rem_sin6 = (struct sockaddr_in6*)&remote; + rem_sin6->sin6_family = AF_INET6; + rem_sin6->sin6_port = htons(53); + inet_pton(AF_INET6, "2001:4860:4860::8888", &rem_sin6->sin6_addr); + if (get_outgoing_local_ip(ip, &remote, &e_sock->interface_addr) != 0) { + DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "Failed to detect outgoing local IPv6 for socket %s", e_sock->name); + } } } } diff --git a/tools/chatgui/src/networksettingspage.cpp b/tools/chatgui/src/networksettingspage.cpp index 2396ca73..5e084042 100644 --- a/tools/chatgui/src/networksettingspage.cpp +++ b/tools/chatgui/src/networksettingspage.cpp @@ -140,6 +140,11 @@ void NetworkSettingsPage::saveToConfig(const QString& configPath) const { config_update_option(configPath, SECTION, "transport", m_protoCombo->currentText().toLower(), CONFIG_UPDATE_REPLACE); + + // IPv6 dual-stack: always add [server:lan6] with same port + config_update_option(configPath, "server:lan6", "addr", + QString("[::]:%1").arg(m_portSpin->value()), + CONFIG_UPDATE_REPLACE); } void NetworkSettingsPage::onInterfaceChanged(int index) { diff --git a/tools/chatgui/transport/node_config.cpp b/tools/chatgui/transport/node_config.cpp index 50fea78e..836c497b 100644 --- a/tools/chatgui/transport/node_config.cpp +++ b/tools/chatgui/transport/node_config.cpp @@ -177,8 +177,10 @@ bool NodeConfig::create(const QString& nodeName, quint16 listenPort) { m_controlAddr = "127.0.0.1:9999"; m_servers.clear(); m_clients.clear(); - if (listenPort > 0) + if (listenPort > 0) { m_servers.append({"lan", QString("0.0.0.0:%1").arg(listenPort)}); + m_servers.append({"lan6", QString("[::]:%1").arg(listenPort)}); + } if (m_dbPath.isEmpty()) m_dbPath = "chat_data"; return save();