From: database64128 Date: Fri, 25 Jul 2025 07:14:16 +0000 (+0800) Subject: net: fix WriteMsgUDPAddrPort addr handling on IPv4 sockets X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=bdb2d50fdf40706e7d7411f33ade80edac726707;p=gostls13.git net: fix WriteMsgUDPAddrPort addr handling on IPv4 sockets 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 Reviewed-by: Mark Freeman Reviewed-by: Damien Neil --- diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go index 2aeabd4487..52712f932f 100644 --- a/src/net/ipsock_posix.go +++ b/src/net/ipsock_posix.go @@ -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{ diff --git a/src/net/udpsock_test.go b/src/net/udpsock_test.go index 6dacc81df6..7ad8a585b0 100644 --- a/src/net/udpsock_test.go +++ b/src/net/udpsock_test.go @@ -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") + } +}