net: fix WriteMsgUDPAddrPort addr handling

WriteMsgUDPAddrPort should accept IPv4 target addresses on IPv6 UDP sockets.
An IPv4 target address will be converted to an IPv4-mapped IPv6 address.

Fixes #52264.

Change-Id: Ib9ed4c61fa1289ae7bbc8c4c9de1a9951b647ec0
GitHub-Last-Rev: 6776fdb0a7
GitHub-Pull-Request: golang/go#52265
Reviewed-on: https://go-review.googlesource.com/c/go/+/399454
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
database64128 2022-04-29 17:29:58 +00:00 committed by Ian Lance Taylor
parent caa225dd29
commit faf4e97200
2 changed files with 48 additions and 1 deletions

View file

@ -215,8 +215,12 @@ func addrPortToSockaddrInet4(ap netip.AddrPort) (syscall.SockaddrInet4, error) {
func addrPortToSockaddrInet6(ap netip.AddrPort) (syscall.SockaddrInet6, error) {
// ipToSockaddrInet6 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 address, because As16 will convert it
// to an IPv4-mapped IPv6 address.
// The error message is kept consistent with ipToSockaddrInet6.
addr := ap.Addr()
if !addr.Is6() {
if !addr.IsValid() {
return syscall.SockaddrInet6{}, &AddrError{Err: "non-IPv6 address", Addr: addr.String()}
}
sa := syscall.SockaddrInet6{

View file

@ -9,6 +9,7 @@ package net
import (
"errors"
"internal/testenv"
"net/netip"
"os"
"reflect"
"runtime"
@ -622,3 +623,45 @@ func TestUDPIPVersionReadMsg(t *testing.T) {
t.Error("returned UDPAddr is not IPv4")
}
}
// TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion verifies that
// WriteMsgUDPAddrPort accepts IPv4, IPv4-mapped IPv6, and IPv6 target addresses
// on a UDPConn listening on "::".
func TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
if !supportsIPv6() {
t.Skip("IPv6 is not supported")
}
switch runtime.GOOS {
case "openbsd":
// OpenBSD's IPv6 sockets are always IPv6-only, according to the man page:
// https://man.openbsd.org/ip6#IPV6_V6ONLY
t.Skipf("skipping on %v", runtime.GOOS)
}
conn, err := ListenUDP("udp", nil)
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)
_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4)
if err != nil {
t.Fatal(err)
}
_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6)
if err != nil {
t.Fatal(err)
}
_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr6)
if err != nil {
t.Fatal(err)
}
}