Skip to content

fix: pass interface to multicast receive socket on Windows multi-NIC …#149

Open
koenvelle wants to merge 1 commit intohashicorp:mainfrom
koenvelle:fix/multicast-interface-windows
Open

fix: pass interface to multicast receive socket on Windows multi-NIC …#149
koenvelle wants to merge 1 commit intohashicorp:mainfrom
koenvelle:fix/multicast-interface-windows

Conversation

@koenvelle
Copy link
Copy Markdown

On Windows with multiple network interfaces, newClient creates the multicast
receive socket with net.ListenMulticastUDP("udp4", nil, ipv4Addr). The nil
interface argument causes IP_ADD_MEMBERSHIP to be issued with INADDR_ANY,
which lets Windows choose the multicast group membership interface based on the
lowest route metric. On a multi-NIC machine this is often not the interface
passed via params.Interface, so the receive socket never sees incoming packets
even though queries are sent on the correct interface via setInterface/IP_MULTICAST_IF.

The fix passes iface (from params.Interface) through newClient to both
ListenMulticastUDP calls so that IP_ADD_MEMBERSHIP is issued for the correct
interface from the start. When params.Interface is nil, iface is nil and
behaviour is identical to before.

Verified on Windows 11 with Ethernet + vEthernet (WSL Hyper-V) adapters: before
the fix ReadFromUDP was never called during a 15-second query; after the fix
the target board is discovered within 15 ms.

Fixes #80

Description

hashicorp/mdns is used by arduino/mdns-discovery (Arduino IDE's pluggable
network port discovery tool). On Windows machines with more than one network
adapter — common with WSL, VirtualBox, VPN clients, etc. — mDNS discovery
silently returns no results even when the target device is actively responding
on the wire.

The root cause is that newClient passes nil as the interface to
net.ListenMulticastUDP. On Windows, nil resolves to IP_ADD_MEMBERSHIP with
INADDR_ANY, and the OS picks whichever interface has the lowest routing metric.
This is often a virtual adapter (WSL, VPN), not the physical NIC where the mDNS
device lives. The send path was already correct (setInterface calls
IP_MULTICAST_IF), but receive group membership was never updated to match.

This PR fixes the receive path by forwarding params.Interface into newClient
and passing it to both ListenMulticastUDP calls.

Related Issue

Fixes #80 ("No results (Windows)")

Also resolves the underlying cause of:

How Has This Been Tested?

Tested manually on Windows 11 with two active network interfaces:

  • Ethernet 2 at 10.0.0.17 (route metric 281) — physical NIC, Arduino device present
  • vEthernet (WSL Hyper-V firewall) at 172.17.112.1 (route metric 5256) — virtual adapter

Before the fix: ReadFromUDP was never invoked during the full 15-second
query window. The Arduino device at 10.0.0.38 was confirmed responding on the
wire (Wireshark showed its mDNS reply within 15 ms), but the socket never
received it because multicast membership was joined on the WSL adapter.

After the fix: The device is discovered and an add event is emitted within
15 ms of the query starting. All other mDNS devices on the same network are also
discovered correctly.

Backward compatibility: when params.Interface is nil (the default),
iface is nil and net.ListenMulticastUDP behaves identically to before —
no regression on single-NIC or Linux/macOS hosts.

…hosts

On Windows with multiple network interfaces, newClient creates the multicast
receive socket with net.ListenMulticastUDP(udp4, nil, ipv4Addr). The nil
interface argument causes IP_ADD_MEMBERSHIP to be issued with INADDR_ANY, which
lets Windows choose the multicast group membership interface based on the lowest
route metric. On a multi-NIC machine this is often not the interface passed via
params.Interface, so the receive socket never sees incoming packets even though
queries are sent on the correct interface via setInterface/IP_MULTICAST_IF.

The fix passes iface (from params.Interface) through newClient to both
ListenMulticastUDP calls so that IP_ADD_MEMBERSHIP is issued for the correct
interface from the start. When params.Interface is nil, iface is nil and
behaviour is identical to before.

Verified on Windows 11 with Ethernet + vEthernet (WSL Hyper-V) adapters: before
the fix ReadFromUDP was never called during a 15-second query; after the fix the
target board is discovered within 15 ms.

Fixes hashicorp#80
@koenvelle koenvelle requested review from a team as code owners March 18, 2026 11:06
@hashicorp-cla-app
Copy link
Copy Markdown

hashicorp-cla-app bot commented Mar 18, 2026

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No results (Windows)

1 participant