Open rittneje opened 3 weeks ago
Related Issues and Documentation
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
@neild @ianlancetaylor Are these changes that you would be amenable to? We'd be willing to contribute the fixes. In particular, we want to make two changes.
First, fix joinIPv4Group
to use SetsockoptIPMreqn
on Linux and pass the interface index.
Second, fix setIPv4MreqToInterface
to check whether mreq.Interface
is 0.0.0.0 after the loop instead of mreq.Multiaddr
, which we suspect was the intent.
https://github.com/golang/go/blob/3730814f2f2bf24550920c39a16841583de2dac1/src/net/sockopt_posix.go#L69-L71
Go version
go version 1.22.8 linux/amd64
Output of
go env
in your module/workspace:What did you do?
My VirtualBox VM has two Ethernet interfaces - enp0s3 and enp0s8. I have noticed a few issues with how
net.ListenMulticastUDP
works, all seemingly due to how it doesIP_ADD_MEMBERSHIP
.What did you see happen?
If I run the above code after telling VirtualBox to disconnect the cable from enp0s3, I get:
I have tracked the error down to this specific call. https://github.com/golang/go/blob/6d39245514c675cdea5c7fd7f778e97bf0728dd5/src/net/sockoptip_posix.go#L19
Meanwhile, if I change the sample program to bind to enp0s8 instead, and I tell VirtualBox to disconnect enp0s8 (and re-connect enp0s3), what actually happens is it ends up bound to enp0s3, as confirmed by
netstat
.I believe what is happening is that
setIPv4MreqToInterface
ends up leavingmreq.Interface
as 0.0.0.0 because the interface in question has no IP addresses when the cable is unplugged. Since enp0s3 is my default interface:It is worth noting we have also observed this issue in "the real world" (i.e., not in a VM) -
net.ListenMulticastUDP
will hard fail if the kernel has no route table entry at that moment, which can happen if the Ethernet cable happens to be unplugged.My experiments show that using
SetsockoptIPMreqn
instead ofSetsockoptIPMreq
to doIP_ADD_MEMBERSHIP
(and passing the interface index instead of its IP address) seems to make it work as expected in both cases.I also noticed that x/net uses
MCAST_JOIN_GROUP
instead ofIP_ADD_MEMBERSHIP
.https://github.com/golang/net/blob/f35fec92ec9213ee211cf45f451a5970386f7978/ipv4/sys_linux.go#L34
However, that sockopt is entirely undocumented and seems to be an internal detail of the kernel.
What did you expect to see?
I expected
net.ListenMulticastUDP
to work as advertised regardless of the state of the Ethernet cable.In particular, on Linux it should use
SetsockoptIPMreqn
so that it always does the right thing. On non-Linux, it should fail if anet.Interface
was provided and the interface in question has no IP address.