Browse Source

chatgui: IPv4+IPv6 dual-stack listen by default

- Default config creates [server:lan] (0.0.0.0) + [server:lan6] ([::])
- Network settings save also writes [server:lan6] section
- Sets IPV6_V6ONLY=1 on IPv6 sockets to avoid conflict with IPv4
- interface_addr for [::] bind prefers permanent IPv6 over temporary
topo_upd
evgeny 2 months ago
parent
commit
af3e2ee869
  1. 38
      src/transport_layer/etcp_connections.c
  2. 5
      tools/chatgui/src/networksettingspage.cpp
  3. 4
      tools/chatgui/transport/node_config.cpp

38
src/transport_layer/etcp_connections.c

@ -557,6 +557,13 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S
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) {
socket_set_mark(e_sock->fd, so_mark);
@ -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);
}
}
}
}

5
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) {

4
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();

Loading…
Cancel
Save