From 0da7fafac4eabec799df40278f68ba86b574afea Mon Sep 17 00:00:00 2001 From: Jesse Rittner Date: Sat, 25 Jan 2025 16:21:53 -0500 Subject: net: fix ListenMulitcastUDP to work properly when interface has no IPv4 The existing implementation would either fail or bind to the wrong interface when the requested interface had no IPv4 address, such as when the Ethernet cable was unplugged. Now on Linux, it will always bind to the requested interface. On other operating systems, it will consistently fail if the requested interface has no IPv4 address. Fixes #70132 Change-Id: I22ec7f9d4adaa4b5afb21fc448050fb4219cacee Reviewed-on: https://go-review.googlesource.com/c/go/+/644375 Reviewed-by: Damien Neil Reviewed-by: Ian Lance Taylor Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor --- src/net/sockopt_posix.go | 30 --------------------- src/net/sockoptip4_bsdvar.go | 30 +++++++++++++++++++++ src/net/sockoptip4_linux.go | 37 +++++++++++++++++++++++++ src/net/sockoptip4_posix_nonlinux.go | 52 ++++++++++++++++++++++++++++++++++++ src/net/sockoptip4_windows.go | 29 ++++++++++++++++++++ src/net/sockoptip6_posix.go | 39 +++++++++++++++++++++++++++ src/net/sockoptip_bsdvar.go | 30 --------------------- src/net/sockoptip_linux.go | 27 ------------------- src/net/sockoptip_posix.go | 49 --------------------------------- src/net/sockoptip_windows.go | 29 -------------------- 10 files changed, 187 insertions(+), 165 deletions(-) create mode 100644 src/net/sockoptip4_bsdvar.go create mode 100644 src/net/sockoptip4_linux.go create mode 100644 src/net/sockoptip4_posix_nonlinux.go create mode 100644 src/net/sockoptip4_windows.go create mode 100644 src/net/sockoptip6_posix.go delete mode 100644 src/net/sockoptip_bsdvar.go delete mode 100644 src/net/sockoptip_linux.go delete mode 100644 src/net/sockoptip_posix.go delete mode 100644 src/net/sockoptip_windows.go (limited to 'src/net') diff --git a/src/net/sockopt_posix.go b/src/net/sockopt_posix.go index a380c7719b..2452f06b0a 100644 --- a/src/net/sockopt_posix.go +++ b/src/net/sockopt_posix.go @@ -7,7 +7,6 @@ package net import ( - "internal/bytealg" "runtime" "syscall" ) @@ -43,35 +42,6 @@ func interfaceToIPv4Addr(ifi *Interface) (IP, error) { return nil, errNoSuchInterface } -func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error { - if ifi == nil { - return nil - } - ifat, err := ifi.Addrs() - if err != nil { - return err - } - for _, ifa := range ifat { - switch v := ifa.(type) { - case *IPAddr: - if a := v.IP.To4(); a != nil { - copy(mreq.Interface[:], a) - goto done - } - case *IPNet: - if a := v.IP.To4(); a != nil { - copy(mreq.Interface[:], a) - goto done - } - } - } -done: - if bytealg.Equal(mreq.Multiaddr[:], IPv4zero.To4()) { - return errNoSuchMulticastInterface - } - return nil -} - func setReadBuffer(fd *netFD, bytes int) error { err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes) runtime.KeepAlive(fd) diff --git a/src/net/sockoptip4_bsdvar.go b/src/net/sockoptip4_bsdvar.go new file mode 100644 index 0000000000..3e9ba1ee78 --- /dev/null +++ b/src/net/sockoptip4_bsdvar.go @@ -0,0 +1,30 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris + +package net + +import ( + "runtime" + "syscall" +) + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + ip, err := interfaceToIPv4Addr(ifi) + if err != nil { + return wrapSyscallError("setsockopt", err) + } + var a [4]byte + copy(a[:], ip.To4()) + err = fd.pfd.SetsockoptInet4Addr(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + err := fd.pfd.SetsockoptByte(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v))) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} diff --git a/src/net/sockoptip4_linux.go b/src/net/sockoptip4_linux.go new file mode 100644 index 0000000000..8b953ebdc6 --- /dev/null +++ b/src/net/sockoptip4_linux.go @@ -0,0 +1,37 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "runtime" + "syscall" +) + +func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPMreqn{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} + if ifi != nil { + mreq.Ifindex = int32(ifi.Index) + } + err := fd.pfd.SetsockoptIPMreqn(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + var v int32 + if ifi != nil { + v = int32(ifi.Index) + } + mreq := &syscall.IPMreqn{Ifindex: v} + err := fd.pfd.SetsockoptIPMreqn(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} diff --git a/src/net/sockoptip4_posix_nonlinux.go b/src/net/sockoptip4_posix_nonlinux.go new file mode 100644 index 0000000000..85e8c6dcfe --- /dev/null +++ b/src/net/sockoptip4_posix_nonlinux.go @@ -0,0 +1,52 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (unix && !linux) || windows + +package net + +import ( + "internal/bytealg" + "runtime" + "syscall" +) + +func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} + if err := setIPv4MreqToInterface(mreq, ifi); err != nil { + return err + } + err := fd.pfd.SetsockoptIPMreq(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error { + if ifi == nil { + return nil + } + ifat, err := ifi.Addrs() + if err != nil { + return err + } + for _, ifa := range ifat { + switch v := ifa.(type) { + case *IPAddr: + if a := v.IP.To4(); a != nil { + copy(mreq.Interface[:], a) + goto done + } + case *IPNet: + if a := v.IP.To4(); a != nil { + copy(mreq.Interface[:], a) + goto done + } + } + } +done: + if bytealg.Equal(mreq.Interface[:], IPv4zero.To4()) { + return errNoSuchMulticastInterface + } + return nil +} diff --git a/src/net/sockoptip4_windows.go b/src/net/sockoptip4_windows.go new file mode 100644 index 0000000000..9dfa37c51e --- /dev/null +++ b/src/net/sockoptip4_windows.go @@ -0,0 +1,29 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "os" + "runtime" + "syscall" +) + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + ip, err := interfaceToIPv4Addr(ifi) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + var a [4]byte + copy(a[:], ip.To4()) + err = fd.pfd.SetsockoptInet4Addr(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} diff --git a/src/net/sockoptip6_posix.go b/src/net/sockoptip6_posix.go new file mode 100644 index 0000000000..5bbc609f7b --- /dev/null +++ b/src/net/sockoptip6_posix.go @@ -0,0 +1,39 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || windows + +package net + +import ( + "runtime" + "syscall" +) + +func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error { + var v int + if ifi != nil { + v = ifi.Index + } + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setIPv6MulticastLoopback(fd *netFD, v bool) error { + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v)) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPv6Mreq{} + copy(mreq.Multiaddr[:], ip) + if ifi != nil { + mreq.Interface = uint32(ifi.Index) + } + err := fd.pfd.SetsockoptIPv6Mreq(syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} diff --git a/src/net/sockoptip_bsdvar.go b/src/net/sockoptip_bsdvar.go deleted file mode 100644 index 3e9ba1ee78..0000000000 --- a/src/net/sockoptip_bsdvar.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris - -package net - -import ( - "runtime" - "syscall" -) - -func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { - ip, err := interfaceToIPv4Addr(ifi) - if err != nil { - return wrapSyscallError("setsockopt", err) - } - var a [4]byte - copy(a[:], ip.To4()) - err = fd.pfd.SetsockoptInet4Addr(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} - -func setIPv4MulticastLoopback(fd *netFD, v bool) error { - err := fd.pfd.SetsockoptByte(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v))) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/src/net/sockoptip_linux.go b/src/net/sockoptip_linux.go deleted file mode 100644 index bd7d834425..0000000000 --- a/src/net/sockoptip_linux.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "runtime" - "syscall" -) - -func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { - var v int32 - if ifi != nil { - v = int32(ifi.Index) - } - mreq := &syscall.IPMreqn{Ifindex: v} - err := fd.pfd.SetsockoptIPMreqn(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} - -func setIPv4MulticastLoopback(fd *netFD, v bool) error { - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/src/net/sockoptip_posix.go b/src/net/sockoptip_posix.go deleted file mode 100644 index 572ea455c0..0000000000 --- a/src/net/sockoptip_posix.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || windows - -package net - -import ( - "runtime" - "syscall" -) - -func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { - mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} - if err := setIPv4MreqToInterface(mreq, ifi); err != nil { - return err - } - err := fd.pfd.SetsockoptIPMreq(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} - -func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error { - var v int - if ifi != nil { - v = ifi.Index - } - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} - -func setIPv6MulticastLoopback(fd *netFD, v bool) error { - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v)) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} - -func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error { - mreq := &syscall.IPv6Mreq{} - copy(mreq.Multiaddr[:], ip) - if ifi != nil { - mreq.Interface = uint32(ifi.Index) - } - err := fd.pfd.SetsockoptIPv6Mreq(syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/src/net/sockoptip_windows.go b/src/net/sockoptip_windows.go deleted file mode 100644 index 9dfa37c51e..0000000000 --- a/src/net/sockoptip_windows.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "os" - "runtime" - "syscall" -) - -func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { - ip, err := interfaceToIPv4Addr(ifi) - if err != nil { - return os.NewSyscallError("setsockopt", err) - } - var a [4]byte - copy(a[:], ip.To4()) - err = fd.pfd.SetsockoptInet4Addr(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} - -func setIPv4MulticastLoopback(fd *netFD, v bool) error { - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} -- cgit v1.3-5-g9baa