]> Cypherpunks repositories - gostls13.git/commitdiff
net: fix WriteMsgUDPAddrPort addr handling on IPv4 sockets
authordatabase64128 <free122448@hotmail.com>
Fri, 25 Jul 2025 07:14:16 +0000 (15:14 +0800)
committerSean Liao <sean@liao.dev>
Fri, 8 Aug 2025 16:58:19 +0000 (09:58 -0700)
Accept IPv4-mapped IPv6 destination addresses on IPv4 UDP sockets.

Fixes #74737.

Change-Id: I4624b9b8f861aedcae29e51d5298d23ce1c0f2c7
Reviewed-on: https://go-review.googlesource.com/c/go/+/689976
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mark Freeman <markfreeman@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
src/net/ipsock_posix.go
src/net/udpsock_test.go

index 2aeabd44873f223f49aadb73ead56b6ef9b4dc6b..52712f932f7530e8f62cb41cccffc994d4e9b7be 100644 (file)
@@ -237,8 +237,12 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 func addrPortToSockaddrInet4(ap netip.AddrPort) (syscall.SockaddrInet4, error) {
        // ipToSockaddrInet4 has special handling here for zero length slices.
        // We do not, because netip has no concept of a generic zero IP address.
+       //
+       // addr is allowed to be an IPv4-mapped IPv6 address.
+       // As4 will unmap it to an IPv4 address.
+       // The error message is kept consistent with ipToSockaddrInet4.
        addr := ap.Addr()
-       if !addr.Is4() {
+       if !addr.Is4() && !addr.Is4In6() {
                return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: addr.String()}
        }
        sa := syscall.SockaddrInet4{
index 6dacc81df6e059f85e564d642ab6f830c90759bc..7ad8a585b07e335ecbc1686ebf967a724c8d39fe 100644 (file)
@@ -705,3 +705,35 @@ func TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
                t.Fatal(err)
        }
 }
+
+// TestIPv4WriteMsgUDPAddrPortTargetAddrIPVersion verifies that
+// WriteMsgUDPAddrPort accepts IPv4 and IPv4-mapped IPv6 destination addresses,
+// and rejects IPv6 destination addresses on a "udp4" connection.
+func TestIPv4WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
+       if !testableNetwork("udp4") {
+               t.Skipf("skipping: udp4 not available")
+       }
+
+       conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer conn.Close()
+
+       daddr4 := netip.AddrPortFrom(netip.MustParseAddr("127.0.0.1"), 12345)
+       daddr4in6 := netip.AddrPortFrom(netip.MustParseAddr("::ffff:127.0.0.1"), 12345)
+       daddr6 := netip.AddrPortFrom(netip.MustParseAddr("::1"), 12345)
+       buf := make([]byte, 8)
+
+       if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4); err != nil {
+               t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr4) failed: %v", err)
+       }
+
+       if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6); err != nil {
+               t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6) failed: %v", err)
+       }
+
+       if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr6); err == nil {
+               t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr6) should have failed, but got no error")
+       }
+}