netflector available as plugin (mDNS, SSDP, DIAL, WSD, WoL reflector)

Started by UnicronHD, August 13, 2026, 02:44:16 PM

Previous topic - Next topic
@UnicronHD Good progress with this build!

With target_peers = ["10.10.10.2"] the Roon server is consistently discovered, bidirectional UDP/9003 communication works, and the previous Network is unreachable / ICMP issues for multicast and broadcast are gone.

There is still one issue: the iPhone does not reliably appear as a Roon audio endpoint.

I also captured:

10.10.10.2 > 192.168.1.60: ICMP udp port 9003 unreachable

for a peer-unicast packet from the Roon server to 10.10.10.2:9003.

In addition, I repeatedly see 350-byte UDP/9003 packets on wg0 from the iPhone to its own WG address, but these do not appear on the LAN capture. The LAN side only shows the normal 98-byte discovery packets and 491-byte replies.

This may be worth comparing with udp-proxy-2020: since v0.0.11 it opens a UDP listening socket specifically to prevent ICMP Port Unreachable messages, as these were found to make Roon on iOS close its listening port and prevent the phone from appearing as an audio output. The ICMP direction here is different, so it may not be the exact same issue, but the symptom is very similar.

So the new peer handling clearly fixes the original WireGuard multicast/broadcast problem, but there still seems to be something missing for reliable iPhone endpoint discovery. Happy to test further.
Deciso DEC850v2

@RamSense Thanks, that confirms the peers change does what it should: the copy carries the server's own source, and the multicast and broadcast errors are gone.

On the endpoint problem. The ICMP you captured goes from the phone to the server, so it tells us the Roon app had no socket open on 9003 at that moment: the phone cannot answer the server's query while its port is closed, which is exactly "not an endpoint". The open question is why the port was closed. Two candidates: the app was in the background (iOS suspends it, and Roon holds its listener only in the foreground), or something made the app drop the socket while it was up. udp-proxy-2020's finding was the second kind, but that needs an ICMP port unreachable arriving at the phone, and there is none in what you sent. netflector's host does not hold port 9003 open, so if the phone ever sends unicast 9003 traffic to one of the OPNsense addresses, OPNsense would answer with exactly that ICMP. Whether that happens depends on where the 350-byte packets go.

Could you check:

  • The exact destination address of the 350-byte packets on wg0, and whether their payload is a SOOD query or a reply.
  • Any ICMP toward the phone on wg0: tcpdump -ni wg0 icmp and dst host 10.10.10.2.
  • The wg0 address and prefix on OPNsense, and the phone's tunnel address and prefix (/24 or /32).
  • Whether the Roon app was in the foreground when you captured the port-unreachable from the phone.
  • Which OS the Roon Core runs on.

@UnicronHD thanks for the follow-up. I checked your remaining details.

The iPhone WireGuard interface is configured as 10.10.10.2/32. OPNsense has wg0 = 10.10.10.1/24, with 10.10.10.2/32 as the peer AllowedIP.

The ~350-byte packets are actually 348-byte SOOD packets. Their exact destination is the iPhone's own tunnel address:

10.10.10.2:<ephemeral> -> 10.10.10.2:9003

The payload starts with SOOD, message type Q, and includes the iPhone endpoint data (iOS 26.7, raat_version 1.1.48, tcp_port 9200).

During the dedicated capture I saw no ICMP packets toward 10.10.10.2.

Roon Server runs on Linux, Debian 12 (bookworm), x86_64.

Roon was in the foreground during the endpoint test.

One thing that may be relevant is the /32 on the iPhone together with the destination above: the phone's SOOD packet is sourced from 10.10.10.2 and is also addressed to 10.10.10.2:9003, and it does not appear on the LAN capture.

This may also be an interesting difference compared with udp-proxy-2020. Its VPN handling learns the client from UDP/9003 traffic seen on the tunnel interface and forwards that traffic onto the other configured interfaces; its debug examples show WG client traffic being reinjected toward the LAN.

So perhaps the relevant question here is whether UDP/9003 sourced from a configured WG peer should also be treated as discovery input for the opposite interface even when its destination is the peer's own tunnel address (?)

Happy to run any further captures or test another build.
Deciso DEC850v2

@RamSense, that is the smoking gun, thank you. The 348-byte packet is the phone announcing itself as an endpoint, sent to the broadcast address of its tunnel interface. Roon derives that from the address and mask, and for a /32 the broadcast address is the host's own address, which is why you see 10.10.10.2 -> 10.10.10.2. netflector relays broadcasts from wg0, but that packet is not one, so the Core never hears the announcement and only learns the phone when it happens to answer one of the Core's own queries.

Could you change the iPhone's interface address in the WireGuard app to 10.10.10.2/24 and test again? Roon should then announce to 10.10.10.255, which netflector relays to the LAN broadcast with the phone's source address kept. A capture on the LAN should show the 348-byte packets arriving at 192.168.1.255:9003.

@UnicronHD the /24 change confirms the first half of your diagnosis, but it looks like there is still something missing in the relay.

After changing the iPhone from 10.10.10.2/32 to 10.10.10.2/24, the 348-byte endpoint announcements now correctly go to:

10.10.10.2:<ephemeral> -> 10.10.10.255:9003

I see several of these on wg0.

However, in the simultaneous ax1 capture I do not see corresponding 348-byte packets arriving at:

10.10.10.2:<ephemeral> -> 192.168.1.255:9003

The LAN capture still only contains the usual 98-byte discovery packets and 491-byte replies.

Behaviour also matches that: on the first Roon start the iPhone endpoint did not appear; on the second start it did, presumably because it happened to answer one of the Core's own queries.

So changing to /24 fixes Roon's broadcast destination exactly as expected, but Netflector does not appear to relay those 348-byte 10.10.10.255:9003 broadcasts from wg0 onto the LAN yet.

Happy to capture anything else you need.
Deciso DEC850v2

@RamSense, thanks, that narrows it down. I rebuilt your setup locally: FreeBSD, a real WireGuard tunnel, the router's wg0 at 10.10.10.1/24, a client at 10.10.10.2/24 sending 348 bytes to 10.10.10.255:9003. There netflector relays the packet to 192.168.1.255:9003 with the client's source kept, so something differs on your box.

Could you set log_level = "trace", restart netflector, open Roon on the phone so it announces a couple of times, then stop it, and send me:

  • The output of netflector-0.16.0rc2-freebsd15-amd64 --version and your config file.
  • Command line you use to start it, and any NETFLECTOR_* environment variables set for it.
  • The full log of that run.
  • Whether your LAN is ax1 itself or a VLAN, bridge or lagg on top of it.

Also, please make sure the netflector service from the plugin is not running at the same time. pgrep -lf netflector should list only the netflector-0.16.0rc2-freebsd15-amd64 process you started by hand. If it also shows /usr/local/sbin/netflector or a daemon: line for it, disable the service on the plugin's page, or stop it with service netflector onestop.

@UnicronHD thanks. I repeated the tests and have some more useful data.

Setup used:

- Binary: netflector-0.16.0rc2-freebsd15-amd64
- --version: netflector 0.16.0
- SHA256: e0b0c32a9f062c36c29ddc7cf193ae984e59fc5215ee05167391f3e14cc2f3b4
- Command: /tmp/netflector-0.16.0rc2-freebsd15-amd64 /tmp/roon-peers-trace.toml
- No NETFLECTOR_* environment variables are set.
- Only the manually started rc2 process was running; the plugin service was not running.
- LAN is directly on ax1, 192.168.1.1/24. There is no bridge, lagg or VLAN on top of ax1.
- iPhone WireGuard IPv4 interface address is now 10.10.10.2/24.
- The OPNsense peer AllowedIP remains 10.10.10.2/32.

Config:

log_level = "trace"

[reflectors.roon-remote]
source_if = "ax1"
target_if = "wg0"
target_peers = ["10.10.10.2"]
udp_ports = [9003]
udp_groups = ["239.255.90.90"]
udp_broadcast = true
bidirectional = true

In the trace run I did repeated force-close/open tests with the same netflector process:

1: endpoint YES
2: endpoint YES
3: endpoint NO
4: endpoint NO

Netflector continued to log the phone traffic being reflected to:

10.10.10.2:<port> -> 192.168.1.255:9003

during the later failed attempts as well.

I then did a second controlled test with a simultaneous tcpdump on ax1.

Results of that test:

1: endpoint YES
2: endpoint NO
3: endpoint NO
4: endpoint YES

The important result is that the 348-byte iPhone endpoint announcements were actually visible on ax1 during all four attempts, including both failed ones:

10.10.10.2:<ephemeral> -> 192.168.1.255:9003
UDP length 348

The normal 98-byte discovery traffic and 491-byte Core replies were also present during the failed attempts.

So the intermittent endpoint failure no longer seems to correlate with netflector failing to relay the broadcast. The announcements are not only reported as reflected by netflector; they are actually present on the LAN interface even when Roon does not show the iPhone endpoint.

Full trace from the trace run:

2026-09-19T10:20:54Z DEBUG netflector: log level Trace
2026-09-19T10:20:54Z  INFO netflector: netflector 0.16.0 starting
2026-09-19T10:20:54Z DEBUG netflector: loading configuration from /tmp/roon-peers-trace.toml with NETFLECTOR_* overrides
2026-09-19T10:20:54Z DEBUG netflector::sys: open-file limit already 466659
2026-09-19T10:20:54Z DEBUG netflector::config: reflector roon-remote: ax1 <-> wg0 [udp(9003 on 239.255.90.90,broadcast)] family=Default
2026-09-19T10:20:54Z DEBUG netflector::config::conflict: no reflector conflicts
2026-09-19T10:20:54Z  INFO netflector: loaded 1 reflector
2026-09-19T10:20:54Z DEBUG netflector::dispatch::lifecycle: interface monitor installed
2026-09-19T10:20:54Z DEBUG netflector::capture::bpf: opened BPF capture on ax1 (fd 4, Ethernet, 4096-byte buffer)
2026-09-19T10:20:54Z DEBUG netflector::interface: ax1: ifindex 6
2026-09-19T10:20:54Z DEBUG netflector::interface: ax1: resolved mac 02:00:00:00:00:01, v4 192.168.1.1/24, v6 fe80::1, v6-routable 2001:db8:1::1, mtu 1500
2026-09-19T10:20:54Z  INFO netflector::interface: interface ax1: gained IPv6 fe80::1
2026-09-19T10:20:54Z  INFO netflector::interface: interface ax1: gained IPv6 routable 2001:db8:1::1
2026-09-19T10:20:54Z  INFO netflector::interface: interface ax1: gained MAC 02:00:00:00:00:01
2026-09-19T10:20:54Z  INFO netflector::interface: interface ax1: gained IPv4 192.168.1.1
2026-09-19T10:20:54Z DEBUG netflector::dispatch: watching ax1 as capture CaptureKey(0)
2026-09-19T10:20:54Z DEBUG netflector::capture::bpf: opened BPF capture on wg0 (fd 5, DltNull, 4096-byte buffer)
2026-09-19T10:20:54Z DEBUG netflector::interface: wg0: ifindex 11
2026-09-19T10:20:54Z DEBUG netflector::interface: wg0: resolved mac none, v4 10.10.10.1/24, v6 2001:db8:2::1, v6-routable 2001:db8:2::1, mtu 1420
2026-09-19T10:20:54Z  INFO netflector::interface: interface wg0: gained IPv6 2001:db8:2::1
2026-09-19T10:20:54Z  INFO netflector::interface: interface wg0: gained IPv6 routable 2001:db8:2::1
2026-09-19T10:20:54Z  INFO netflector::interface: interface wg0: gained IPv4 10.10.10.1
2026-09-19T10:20:54Z DEBUG netflector::dispatch: watching wg0 as capture CaptureKey(1)
2026-09-19T10:20:54Z  INFO netflector: roon-remote: MTU mismatch: ax1 has 1500, wg0 has 1420; packets larger than 1420 bytes cannot cross toward the smaller side and are dropped
2026-09-19T10:20:54Z DEBUG netflector::reflector: UDP relay: joined 239.255.90.90 on ax1
2026-09-19T10:20:54Z  INFO netflector::reflector::udp: UDP relay "roon-remote": ax1 -> wg0 on 1 port(s) to 1 group(s) and broadcasts
2026-09-19T10:20:54Z DEBUG netflector::reflector: UDP relay: joined 239.255.90.90 on wg0
2026-09-19T10:20:54Z  INFO netflector::reflector::udp: UDP relay "roon-remote": wg0 -> ax1 on 1 port(s) to 1 group(s) and broadcasts
2026-09-19T10:20:54Z DEBUG netflector::reactor: watch fd 4 for HandlerKey(Key { index: 0, generation: 0 }) as RegKey(Key { index: 0, generation: 0 })
2026-09-19T10:20:54Z DEBUG netflector::reactor: watch fd 5 for HandlerKey(Key { index: 0, generation: 0 }) as RegKey(Key { index: 1, generation: 0 })
2026-09-19T10:20:54Z DEBUG netflector::reactor: watch fd 3 for HandlerKey(Key { index: 0, generation: 0 }) as RegKey(Key { index: 2, generation: 0 })
2026-09-19T10:20:54Z  INFO netflector: running; press Ctrl-C or send SIGTERM to stop
2026-09-19T10:20:54Z DEBUG netflector::reactor: watch fd 9 for HandlerKey(Key { index: 2, generation: 0 }) as RegKey(Key { index: 3, generation: 0 })
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:64505 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:64505 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51405 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:49551 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51405 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:57834 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:49551 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:57834 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55097 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55097 to 192.168.1.255:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:00Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:01Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:01Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:02Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55097 to 192.168.1.255:9003
2026-09-19T10:21:02Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55097 to 192.168.1.255:9003
2026-09-19T10:21:02Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55097 to 192.168.1.255:9003
2026-09-19T10:21:02Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55097 to 192.168.1.255:9003
2026-09-19T10:21:03Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55241 to 192.168.1.255:9003
2026-09-19T10:21:03Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:60392 to 192.168.1.255:9003
2026-09-19T10:21:03Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55241 to 192.168.1.255:9003
2026-09-19T10:21:03Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:60392 to 192.168.1.255:9003
2026-09-19T10:21:03Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:64552 to 192.168.1.255:9003
2026-09-19T10:21:03Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:63541 to 192.168.1.255:9003
2026-09-19T10:21:03Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:64552 to 192.168.1.255:9003
2026-09-19T10:21:03Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:63541 to 192.168.1.255:9003
2026-09-19T10:21:07Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:57712 to 192.168.1.255:9003
2026-09-19T10:21:07Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:63704 to 192.168.1.255:9003
2026-09-19T10:21:07Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51022 to 192.168.1.255:9003
2026-09-19T10:21:07Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:57712 to 192.168.1.255:9003
2026-09-19T10:21:07Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:63704 to 192.168.1.255:9003
2026-09-19T10:21:07Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51022 to 192.168.1.255:9003
2026-09-19T10:21:07Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65002 to 192.168.1.255:9003
2026-09-19T10:21:07Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65002 to 192.168.1.255:9003
2026-09-19T10:21:08Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62406 to 192.168.1.255:9003
2026-09-19T10:21:08Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62406 to 192.168.1.255:9003
2026-09-19T10:21:08Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:08Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:08Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:08Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:08Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:08Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:09Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62406 to 192.168.1.255:9003
2026-09-19T10:21:09Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62406 to 192.168.1.255:9003
2026-09-19T10:21:09Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62406 to 192.168.1.255:9003
2026-09-19T10:21:09Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62406 to 192.168.1.255:9003
2026-09-19T10:21:10Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:53458 to 192.168.1.255:9003
2026-09-19T10:21:10Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:53458 to 192.168.1.255:9003
2026-09-19T10:21:10Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:58420 to 192.168.1.255:9003
2026-09-19T10:21:10Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:63726 to 192.168.1.255:9003
2026-09-19T10:21:10Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56444 to 192.168.1.255:9003
2026-09-19T10:21:10Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:58420 to 192.168.1.255:9003
2026-09-19T10:21:10Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:63726 to 192.168.1.255:9003
2026-09-19T10:21:10Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56444 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:50271 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:53396 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:58427 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51933 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:50271 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:53396 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:58427 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51933 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56067 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56067 to 192.168.1.255:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:12Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:13Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:13Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56067 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56067 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56067 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56067 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55869 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62698 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:60621 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55869 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62698 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:60621 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:53664 to 192.168.1.255:9003
2026-09-19T10:21:14Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:53664 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:52623 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:61699 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:52623 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:61699 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55696 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:58224 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:55696 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:58224 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:50268 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:50268 to 192.168.1.255:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:24Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:25Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:25Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:50268 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:50268 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:50268 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:50268 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51265 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51265 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:57440 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:57440 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51906 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51906 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56434 to 192.168.1.255:9003
2026-09-19T10:21:26Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56434 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62645 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:62645 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:52706 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:52466 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:60102 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:52706 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:52466 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:60102 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65044 to 192.168.1.255:9003
2026-09-19T10:21:33Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65044 to 192.168.1.255:9003
2026-09-19T10:21:34Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:34Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:34Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:53241 to 239.255.90.90:9003
2026-09-19T10:21:34Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 239.255.90.90:9003
2026-09-19T10:21:34Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:34Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 192.168.1.60:58287 to 10.10.10.255:9003
2026-09-19T10:21:35Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65044 to 192.168.1.255:9003
2026-09-19T10:21:35Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65044 to 192.168.1.255:9003
2026-09-19T10:21:35Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65044 to 192.168.1.255:9003
2026-09-19T10:21:35Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65044 to 192.168.1.255:9003
2026-09-19T10:21:37Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51255 to 192.168.1.255:9003
2026-09-19T10:21:37Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65460 to 192.168.1.255:9003
2026-09-19T10:21:37Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:53125 to 192.168.1.255:9003
2026-09-19T10:21:37Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:51255 to 192.168.1.255:9003
2026-09-19T10:21:37Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:65460 to 192.168.1.255:9003
2026-09-19T10:21:37Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:53125 to 192.168.1.255:9003
2026-09-19T10:21:37Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56721 to 192.168.1.255:9003
2026-09-19T10:21:37Z DEBUG netflector::reflector::simple: reflected UDP relay datagram from 10.10.10.2:56721 to 192.168.1.255:9003

Note: I only redacted the public IPv6 addresses and the LAN MAC address in the trace. Internal IPv4 addresses, interface names, ports, timestamps and netflector log contents are otherwise unchanged.
Deciso DEC850v2

@RamSense, thanks, this run settles the relay question: wg0 resolves with its /24, both directions are registered with broadcasts, and the announcements reach ax1 on every attempt. Sorry about trace, by the way: release builds compile it out, so debug was all that binary could log.

Your log shows something else though: every datagram from the phone is relayed twice. I reproduced that locally once I enabled IP forwarding on my test router. WireGuard interfaces have no broadcast flag, so the router treats 10.10.10.255 as an ordinary host and forwards the packet back out wg0. netflector picks up that forwarded copy too, and the WireGuard driver, finding no peer for 10.10.10.255, answers the sender with an ICMP "host 10.10.10.255 unreachable". So since the /24 change OPNsense has most likely been answering every Roon announcement with an ICMP error to the phone, which is exactly what udp-proxy-2020 found breaks Roon on iOS. Your earlier capture without ICMP was taken with the /32, where this does not happen.

Could you try this:

  • First confirm the ICMP: run tcpdump -ni wg0 icmp while opening Roon on the phone. I expect "host 10.10.10.255 unreachable" from 10.10.10.1 to 10.10.10.2.
  • Add a firewall rule on the WireGuard interface: action Block (not Reject), direction in, quick, destination single host 10.10.10.255, placed above your pass rules.
  • Repeat the ICMP capture, it should now stay empty, and repeat the four open/close attempts.

netflector captures ahead of the firewall, so it still relays the announcement. In my test setup the rule leaves exactly one relayed copy per announcement and no ICMP toward the phone.

@UnicronHD, confirmed.

The inbound rule did not match on my OPNsense setup, but an outbound quick block on wg0 does:

block drop out quick on wg0 inet from 10.10.10.2 to 10.10.10.255

After the test it had:

Packets: 66
Bytes: 20316

With that rule active:

- ICMP capture from 10.10.10.1 to 10.10.10.2 stays completely empty.
- The previous "host 10.10.10.255 unreachable" messages are gone.
- The duplicate relay is also gone.
- On ax1 I now see only TTL 64 copies of the phone traffic.
- The 348-byte SOOD endpoint announcements still reach 192.168.1.255:9003.
- The 98-byte discovery packets also still reach the LAN.

So the forwarding/ICMP issue is confirmed and fixed by blocking the routed egress copy.

However, the iPhone endpoint is still intermittent in Roon. During the latest tests there were attempts where the endpoint did not appear even though the 348-byte announcements were present on ax1 and there were no ICMP errors toward the phone.

So at this point the remaining intermittent endpoint issue no longer appears to correlate with:
- missing netflector relay
- duplicate relay
- or ICMP unreachable responses.

I have not changed anything else in the setup.
Deciso DEC850v2

Great, thanks for nailing down the rule direction. That closes the netflector side: discovery now crosses correctly both ways. The Core's queries reach the phone, the phone's announcements reach the LAN broadcast once each with the phone's source kept, nothing answers the phone with ICMP anymore, and the Core replies to them.

What is left happens after discovery. From the announcement the Core learns the endpoint's RAAT port (tcp_port 9200 in your capture) and connects to the phone over plain routed TCP, which netflector is not part of. Three things would tell us where it fails:

  • A baseline: the same four force-close/open attempts with the phone on your LAN Wi-Fi, WireGuard off. If the endpoint is intermittent there too, it is Roon's own behaviour after a force-close, for example the Core still holding the previous session for that device.
  • During a run over WireGuard with both good and failed attempts, capture on both interfaces at once:
    tcpdump -ni wg0 -w /tmp/wg0.pcap host 10.10.10.2
    tcpdump -ni ax1 -w /tmp/ax1.pcap host 10.10.10.2
    Note the time of each attempt and whether the endpoint appeared, then send me both files. I want to see whether the Core opens a TCP connection to 10.10.10.2:9200 on the failed attempts, whether that connection shows up on both interfaces, and what the phone answers.
  • In a failed attempt, how long did you wait? The phone re-announces every few seconds, so if the endpoint never shows up while announcements keep arriving, the Core is ignoring them or its TCP connect keeps failing.

@UnicronHD, the LAN-only baseline reproduces it too.

WireGuard was completely OFF and the iPhone was on normal LAN Wi-Fi only.

The endpoint behaviour was still intermittent. When it failed, I waited 20-30 seconds and the endpoint still did not appear. It only came back after one or more force-close/reopen cycles of Roon.

So this is not just a 2-3 second discovery delay. The same remaining behaviour exists without WireGuard and without netflector. I did not know that.

That seems to confirm your conclusion that the netflector/discovery side is now closed and the remaining issue is in Roon/iOS endpoint/session behaviour after discovery.
Deciso DEC850v2

Thanks for running the baseline. If it's just as flaky on plain Wi-Fi with no tunnel and no netflector, then it's Roon itself after a force-close, and there's nothing left to fix on the network side.

Good to know where things stand though. Peers fix discovery over WireGuard, but the phone needs a /24 on its tunnel address, otherwise it sends its endpoint announcement to itself. And the router has to drop 10.10.10.255 on the WireGuard interface, or it forwards the packet back into the tunnel and replies to the phone with ICMP. I'll put both into the docs, we'd never have found them without your captures.

Thanks again for all the testing. I'll prepare a new official release soon.