[release-branch.go1.25] net: fix WriteMsgUDPAddrPort addr handling on IPv4 sockets

Accept IPv4-mapped IPv6 destination addresses on IPv4 UDP sockets.

Fixes #74999.

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>
(cherry picked from commit bdb2d50fdf)
Reviewed-on: https://go-review.googlesource.com/c/go/+/695875
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
This commit is contained in:
database64128 2025-07-25 15:14:16 +08:00 committed by Cherry Mui
parent 8995e84ac6
commit cdd8cf4988
2 changed files with 37 additions and 1 deletions

View 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) { func addrPortToSockaddrInet4(ap netip.AddrPort) (syscall.SockaddrInet4, error) {
// ipToSockaddrInet4 has special handling here for zero length slices. // ipToSockaddrInet4 has special handling here for zero length slices.
// We do not, because netip has no concept of a generic zero IP address. // 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() addr := ap.Addr()
if !addr.Is4() { if !addr.Is4() && !addr.Is4In6() {
return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: addr.String()} return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: addr.String()}
} }
sa := syscall.SockaddrInet4{ sa := syscall.SockaddrInet4{

View file

@ -705,3 +705,35 @@ func TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
t.Fatal(err) 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")
}
}