mirror of
https://github.com/golang/go.git
synced 2025-10-19 11:03:18 +00:00
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 <dneil@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Commit-Queue: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
65004c7bf4
commit
0da7fafac4
6 changed files with 62 additions and 40 deletions
|
@ -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)
|
||||
|
|
|
@ -9,6 +9,16 @@ import (
|
|||
"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 {
|
52
src/net/sockoptip4_posix_nonlinux.go
Normal file
52
src/net/sockoptip4_posix_nonlinux.go
Normal file
|
@ -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
|
||||
}
|
|
@ -11,16 +11,6 @@ import (
|
|||
"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 {
|
Loading…
Add table
Add a link
Reference in a new issue