From 4fcde646b9c220451aafa9bcc1dcb6f485b8720d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20Roff=C3=A9?= Date: Sun, 29 Mar 2026 12:21:46 +0200 Subject: [PATCH] fix(windows): enable dual-stack IPv6 sockets by default (#3988) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(windows): enable dual-stack IPv6 sockets by default On Windows, IPV6_V6ONLY defaults to true, so binding to [::] only accepts IPv6 connections. Set it to false so that IPv6 listeners also accept IPv4 traffic, matching the default Linux behavior. * chore: add test --------- Co-authored-by: Romain Roffé Co-authored-by: Yuki Okushi --- actix-web/CHANGES.md | 1 + actix-web/src/server.rs | 16 +++++++++++ actix-web/tests/test_httpserver.rs | 45 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/actix-web/CHANGES.md b/actix-web/CHANGES.md index 59901dfd4..72f541653 100644 --- a/actix-web/CHANGES.md +++ b/actix-web/CHANGES.md @@ -2,6 +2,7 @@ ## Unreleased +- Enable dual-stack IPv6 sockets on Windows when possible so that Actix-created listeners bound to `[::]` also accept IPv4 connections. - Panic when calling `Route::to()` or `Route::service()` after `Route::wrap()` to prevent silently dropping route middleware. [#3944] - Fix `HttpRequest::{match_pattern,match_name}` reporting path-only matches when route guards disambiguate overlapping resources. [#3346] - Fix `Readlines` handling of lines split across payload chunks so combined line limits are enforced and complete lines are yielded. diff --git a/actix-web/src/server.rs b/actix-web/src/server.rs index c0bec7f05..2f52b21fb 100644 --- a/actix-web/src/server.rs +++ b/actix-web/src/server.rs @@ -445,6 +445,14 @@ where /// Using a bind address of `0.0.0.0`, which signals to use all interfaces, may also multiple /// the number of instantiations in a similar way. /// + /// # Dual-Stack IPv6 + /// + /// On Windows, when this method creates an IPv6 listener (e.g., for `[::]:8080`), this + /// attempts to enable dual-stack mode so the socket can accept both IPv4 and IPv6 + /// connections. On Linux and macOS, dual-stack is typically already the OS default. If you + /// need IPv6-only behavior on Windows, create the listener manually and pass it to + /// [`listen()`](Self::listen()). + /// /// # Typical Usage /// /// In general, use `127.0.0.1:` when testing locally and `0.0.0.0:` when deploying @@ -1259,6 +1267,14 @@ fn create_tcp_listener(addr: net::SocketAddr, backlog: u32) -> io::Result