Sonos - Asus Router Merlin Yazfi Guest Network with One Way to Guest

Sonos - Asus Router Merlin Yazfi Guest Network with One Way to Guest

· json · rss
Subscribe:

Update 16/05/2024 notice: version 80.xx.xx.xx

After the mobile app update to version 80.xx.xx.xx, the method that the app use to discover speakers has completely changed. It is now required to allow destination UDP port 1900 (UPNP) traffic and source TCP port 1443 to flow to br0 instead:

iptables -I YazFiFORWARD -i wl0.1 -o br0 -s 172.27.15.3 -p udp --dport 1900 -j ACCEPT
iptables -I YazFiFORWARD -i wl0.1 -o br0 -s 172.27.15.3 -p tcp --sport 1443 -j ACCEPT

Where 172.27.15.3 is the IP address of the Sonos system.

For Airplay to work it is also required to allow destination TCP ephemeral ports, source TCP 7000 (BBS), along with destination UDP 319:320 (PTP) ports to flow to br0:

iptables -I YazFiFORWARD -i wl0.1 -o br0 -s 172.27.15.3 -p tcp --dport 32768:65535 -j ACCEPT
iptables -I YazFiFORWARD -i wl0.1 -o br0 -s 172.27.15.3 -p tcp --sport 7000 -j ACCEPT
iptables -I YazFiFORWARD -i wl0.1 -o br0 -s 172.27.15.3 -p udp --dport 319:320 -j ACCEPT

Where 172.27.15.3 is the IP address of the Sonos system.

I've also noticed that Sonos also need source TCP 4444 (krb524) to br0 while running updates:

iptables -I YazFiFORWARD -i wl0.1 -o br0 -s 172.27.15.3 -p tcp --sport 4444 -j ACCEPT

Where 172.27.15.3 is the IP address of the Sonos system.

Relevant new tcpdumps:

# SONOS APP TESTING
jarylc@RT-AX88U:/jffs/addons/YazFi.d/userscripts.d# tcpdump -i any src 172.27.15.3 and dst 172.27.14.98
08:23:59.721602 wl0.1 In  IP 172.27.15.3.34242 > 172.27.14.98.upnp: UDP, length 741
08:23:59.721669 br0   Out IP 172.27.15.3.34242 > 172.27.14.98.upnp: UDP, length 741
08:23:59.721678 eth7  Out IP 172.27.15.3.34242 > 172.27.14.98.upnp: UDP, length 741
08:23:59.870068 wl0.1 In  IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [S.], seq 165454314, ack 134039494, win 28960, options [mss 1460,sackOK,TS val 355714560 ecr 4169303348,nop,wscale 7], length 0
08:23:59.870090 br0   Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [S.], seq 165454314, ack 134039494, win 28960, options [mss 1460,sackOK,TS val 355714560 ecr 4169303348,nop,wscale 7], length 0
08:23:59.870093 eth7  Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [S.], seq 165454314, ack 134039494, win 28960, options [mss 1460,sackOK,TS val 355714560 ecr 4169303348,nop,wscale 7], length 0
08:23:59.926271 wl0.1 In  IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [.], ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 0
08:23:59.926303 br0   Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [.], ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 0
08:23:59.926307 eth7  Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [.], ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 0
08:23:59.926275 wl0.1 In  IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [P.], seq 1:63, ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 62
08:23:59.926330 br0   Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [P.], seq 1:63, ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 62
08:23:59.926333 eth7  Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [P.], seq 1:63, ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 62
08:23:59.926280 wl0.1 In  IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [.], seq 63:1511, ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 1448
08:23:59.926357 br0   Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [.], seq 63:1511, ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 1448
08:23:59.926361 eth7  Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [.], seq 63:1511, ack 157, win 235, options [nop,nop,TS val 355714574 ecr 4169303497], length 1448
08:24:01.100909 wl0.1 In  IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [P.], seq 2093:2124, ack 476, win 243, options [nop,nop,TS val 355714868 ecr 4169304590], length 31
08:24:01.100937 br0   Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [P.], seq 2093:2124, ack 476, win 243, options [nop,nop,TS val 355714868 ecr 4169304590], length 31
08:24:01.100942 eth7  Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [P.], seq 2093:2124, ack 476, win 243, options [nop,nop,TS val 355714868 ecr 4169304590], length 31
08:24:01.100913 wl0.1 In  IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [F.], seq 2124, ack 476, win 243, options [nop,nop,TS val 355714868 ecr 4169304590], length 0
08:24:01.100960 br0   Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [F.], seq 2124, ack 476, win 243, options [nop,nop,TS val 355714868 ecr 4169304590], length 0
08:24:01.100963 eth7  Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [F.], seq 2124, ack 476, win 243, options [nop,nop,TS val 355714868 ecr 4169304590], length 0
08:24:01.190110 wl0.1 In  IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [F.], seq 2124, ack 476, win 243, options [nop,nop,TS val 355714891 ecr 4169304590], length 0
08:24:01.190127 br0   Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [F.], seq 2124, ack 476, win 243, options [nop,nop,TS val 355714891 ecr 4169304590], length 0
08:24:01.190130 eth7  Out IP 172.27.15.3.1443 > 172.27.14.98.50146: Flags [F.], seq 2124, ack 476, win 243, options [nop,nop,TS val 355714891 ecr 4169304590], length 0
08:25:01.196936 wl0.1 In  IP 172.27.15.3.33005 > 172.27.14.98.57454: UDP, length 741
08:25:03.196969 br0   Out IP 172.27.15.3.33005 > 172.27.14.98.57454: UDP, length 741
08:25:05.196976 eth7  Out IP 172.27.15.3.33005 > 172.27.14.98.57454: UDP, length 741

# AIRPLAY TESTING
jarylc@RT-AX88U-0BC0:/tmp/home/root# tcpdump -i any src 172.27.15.3 and dst 172.27.14.110
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
08:59:34.272732 wl0.1 In  IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [S.], seq 361871852, ack 1905326041, win 28960, options [mss 1460,sackOK,TS val 356248160 ecr 2914930491,nop,wscale 7], length 0
08:59:34.272761 br0   Out IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [S.], seq 361871852, ack 1905326041, win 28960, options [mss 1460,sackOK,TS val 356248160 ecr 2914930491,nop,wscale 7], length 0
08:59:34.272769 eth7  Out IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [S.], seq 361871852, ack 1905326041, win 28960, options [mss 1460,sackOK,TS val 356248160 ecr 2914930491,nop,wscale 7], length 0
08:59:34.284023 wl0.1 In  IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [.], ack 281, win 235, options [nop,nop,TS val 356248164 ecr 2914930539], length 0
08:59:34.284038 br0   Out IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [.], ack 281, win 235, options [nop,nop,TS val 356248164 ecr 2914930539], length 0
08:59:34.284041 eth7  Out IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [.], ack 281, win 235, options [nop,nop,TS val 356248164 ecr 2914930539], length 0
08:59:34.288263 wl0.1 In  IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [P.], seq 1:977, ack 281, win 235, options [nop,nop,TS val 356248164 ecr 2914930539], length 976
08:59:34.288281 br0   Out IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [P.], seq 1:977, ack 281, win 235, options [nop,nop,TS val 356248164 ecr 2914930539], length 976
08:59:34.288285 eth7  Out IP 172.27.15.3.bbs > 172.27.14.110.53646: Flags [P.], seq 1:977, ack 281, win 235, options [nop,nop,TS val 356248164 ecr 2914930539], length 976
08:59:35.333401 wl0.1 In  IP 172.27.15.3 > 172.27.14.110: ICMP 172.27.15.3 udp port 320 unreachable, length 112
08:59:35.333430 br0   Out IP 172.27.15.3 > 172.27.14.110: ICMP 172.27.15.3 udp port 320 unreachable, length 112
08:59:35.333435 eth7  Out IP 172.27.15.3 > 172.27.14.110: ICMP 172.27.15.3 udp port 320 unreachable, length 112
08:59:35.333405 wl0.1 In  IP 172.27.15.3 > 172.27.14.110: ICMP 172.27.15.3 udp port 320 unreachable, length 142
08:59:35.333452 br0   Out IP 172.27.15.3 > 172.27.14.110: ICMP 172.27.15.3 udp port 320 unreachable, length 142
08:59:35.333455 eth7  Out IP 172.27.15.3 > 172.27.14.110: ICMP 172.27.15.3 udp port 320 unreachable, length 142
08:59:35.333408 wl0.1 In  IP 172.27.15.3.46785 > 172.27.14.110.53647: Flags [S.], seq 4199358917, ack 972859376, win 28960, options [mss 1460,sackOK,TS val 356248426 ecr 2879974157,nop,wscale 7], length 0
08:59:35.333474 br0   Out IP 172.27.15.3.46785 > 172.27.14.110.53647: Flags [S.], seq 4199358917, ack 972859376, win 28960, options [mss 1460,sackOK,TS val 356248426 ecr 2879974157,nop,wscale 7], length 0
08:59:35.333477 eth7  Out IP 172.27.15.3.46785 > 172.27.14.110.53647: Flags [S.], seq 4199358917, ack 972859376, win 28960, options [mss 1460,sackOK,TS val 356248426 ecr 2879974157,nop,wscale 7], length 0

# UPDATE TESTING
jarylc@RT-AX88U-0BC0:/tmp/home/root# tcpdump -i any src 172.27.15.3 or src 172.27.15.1 or src 172.27.15.3
08:22:01.901621 wl0.1 In  IP 172.27.15.3.krb524 > 172.27.14.98.35390: Flags [R.], seq 0, ack 3400968069, win 0, length 0
08:22:01.901646 br0   Out IP 172.27.15.3.krb524 > 172.27.14.98.35390: Flags [R.], seq 0, ack 1, win 0, length 0
08:22:01.901653 eth7  Out IP 172.27.15.3.krb524 > 172.27.14.98.35390: Flags [R.], seq 0, ack 1, win 0, length 0

Overall, my latest script looks like this now:

HOME_ASSISTANT='172.27.14.254'
MEDIA_RANGE='172.27.15.2-172.27.15.20'
iptables -I YazFiFORWARD -i wl0.1 -o br0 -d ${HOME_ASSISTANT} -p tcp -m multiport --dports 1400,8123 -j ACCEPT
iptables -I YazFiFORWARD -i wl0.1 -o br0 -m iprange --src-range "${MEDIA_RANGE}" -p tcp --dport 32768:65535 -j ACCEPT
iptables -I YazFiFORWARD -i wl0.1 -o br0 -m iprange --src-range "${MEDIA_RANGE}" -p udp -m multiport --dports 319,320,1900 -j ACCEPT
iptables -I YazFiFORWARD -i wl0.1 -o br0 -m iprange --src-range "${MEDIA_RANGE}" -p tcp -m multiport --sports 1400,1443,4444,7000 -j ACCEPT
End of update here, original post follows

Most recently I've discovered that Asuswrt-Merlin (community firmware for Asus routers) has a terminal UI interface `amtm`.

Within it there is a project called Yazfi by @jackyaz which provides a "feature expansion of guest Wi-Fi networks on AsusWRT-Merlin".

I've always wanted to move all my smart devices to another VLAN with only pinhole access to my main LAN. Thanks to Yazfi, the effort is reduced tremendously trying to configure these while leveraging on the Guest Network functionality of Asus Routers. With that, I started my project to reformat my Asus Router, rotating my Wi-Fi passwords and start moving everything over.

I did however encounter some issues with discovering Sonos devices on the mobile app even with `One way to guest` enabled, it was either totally not discovering or very slow, and decided to start digging into it.

Investigation

This section explains how I investigated how the Sonos works in my network under the hood and you can skip to the Solution section below if you only care about that!

Temporarily allowing two-way traffic between LAN and Guest Network

Since we are investigating how Sonos operates, I temporarily allowed two-way communication between the 2 networks in Yazfi configuration.

Enabling multicast routing

Since various online sources says that Sonos uses Simple Service Discovery Protocol (SSDP) and multicast DNS (mDNS) to support discoverability, for good measure, I enabled multicast routing under LAN > IPTV > Enable multicast routing

However I'm not 100% sure there is a need for this.

Installing entware and tcpdump on my router

You can follow these instructions to install entware on your router.

After installationof entware is complete, it's as simple as

jarylc@RT-AX88U:/tmp/home/root# opkg install tcpdump

Running tcpdump

After snooping around the UI and the Sonos App, the private IP addresses of the relevant devices are the following:

  • My Android phone: 172.27.14.98 (172.27.14.x is my main LAN)
  • One of my Sonos devices: 172.27.15.3 (172.27.15.x is my smart devices Guest network)

I limited the snooping to UDP packets only as that is what SSDP and mDNS primarily uses

jarylc@RT-AX88U:/jffs/addons/YazFi.d/userscripts.d# tcpdump -i any 'udp and (src 172.27.15.3 or src 172.27.14.98)'
09:26:30.044460 wl0.4 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 200
09:26:30.044469 wl0.1 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 200
09:26:30.044433 br0   M   IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 200
09:26:30.044582 wl0.4 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 200
09:26:30.044589 wl0.1 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 200
09:26:30.044443 br0   B   IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 200
09:26:30.045267 wl0.4 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:30.045274 wl0.1 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:30.045259 br0   M   IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:30.045539 wl0.4 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:30.045544 wl0.1 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:30.045530 br0   B   IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:30.048134 wl0.4 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 1 PTR (QU)? _sonos._tcp.local. (35)
09:26:30.048139 wl0.1 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 1 PTR (QU)? _sonos._tcp.local. (35)
09:26:30.048125 br0   M   IP 172.27.14.98.5353 > mdns.mcast.net.5353: 1 PTR (QU)? _sonos._tcp.local. (35)
09:26:30.227307 wl0.1 M   IP 172.27.15.3.5353 > mdns.mcast.net.5353: 0*- [0q] 1/0/6 PTR Sonos-XXXXXXXXXXXX@Media Room._sonos._tcp.local. (676)
09:26:30.266863 wl0.4 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:30.266871 wl0.1 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:30.266828 br0   M   IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:30.266945 wl0.4 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:30.266950 wl0.1 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:30.266840 br0   B   IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:30.580416 wl0.1 In  IP 172.27.15.3.37360 > 172.27.14.98.37972: UDP, length 741
09:26:30.580456 br0   Out IP 172.27.15.3.37360 > 172.27.14.98.37972: UDP, length 741
09:26:31.072123 wl0.4 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 2 PTR (QM)? _sonos._tcp.local. (35)
09:26:31.072128 wl0.1 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 2 PTR (QM)? _sonos._tcp.local. (35)
09:26:31.071869 br0   M   IP 172.27.14.98.5353 > mdns.mcast.net.5353: 2 PTR (QM)? _sonos._tcp.local. (35)
09:26:31.072203 wl0.4 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 200
09:26:31.072208 wl0.1 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 200
09:26:31.071885 br0   M   IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 200
09:26:31.072269 wl0.4 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 200
09:26:31.072274 wl0.1 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 200
09:26:31.071892 br0   B   IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 200
09:26:31.309102 wl0.1 In  IP 172.27.15.3.38139 > 172.27.14.98.37972: UDP, length 741
09:26:31.309125 br0   Out IP 172.27.15.3.38139 > 172.27.14.98.37972: UDP, length 741
09:26:31.343765 wl0.4 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:31.343773 wl0.1 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:31.343737 br0   M   IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:31.343853 wl0.4 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:31.343858 wl0.1 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:31.343748 br0   B   IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:31.692594 wl0.1 In  IP 172.27.15.3.38570 > 172.27.14.98.37972: UDP, length 741
09:26:31.692617 br0   Out IP 172.27.15.3.38570 > 172.27.14.98.37972: UDP, length 741
09:26:32.271746 wl0.4 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 1 PTR (QU)? _sonos._tcp.local. (35)
09:26:32.271753 wl0.1 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 1 PTR (QU)? _sonos._tcp.local. (35)
09:26:32.271598 br0   M   IP 172.27.14.98.5353 > mdns.mcast.net.5353: 1 PTR (QU)? _sonos._tcp.local. (35)
09:26:32.278203 eth7  M   IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:32.278226 wl0.4 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:32.278232 wl0.1 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:32.278203 br0   M   IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:32.278296 wl0.4 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:32.278301 wl0.1 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:32.278214 br0   B   IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:32.465141 wl0.1 M   IP 172.27.15.3.5353 > mdns.mcast.net.5353: 0*- [0q] 1/0/6 PTR Sonos-XXXXXXXXXXXX@Media Room._sonos._tcp.local. (676)
09:26:32.701778 wl0.1 In  IP 172.27.15.3.41457 > 172.27.14.98.37972: UDP, length 741
09:26:32.701801 br0   Out IP 172.27.15.3.41457 > 172.27.14.98.37972: UDP, length 741
09:26:33.215347 wl0.4 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 2 PTR (QM)? _sonos._tcp.local. (35)
09:26:33.215355 wl0.1 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 2 PTR (QM)? _sonos._tcp.local. (35)
09:26:33.215331 br0   M   IP 172.27.14.98.5353 > mdns.mcast.net.5353: 2 PTR (QM)? _sonos._tcp.local. (35)
09:26:33.905757 wl0.4 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:33.905763 wl0.1 Out IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:33.905736 br0   M   IP 172.27.14.98.37972 > 239.255.255.250.upnp: UDP, length 254
09:26:33.905846 wl0.4 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:33.905851 wl0.1 Out IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:33.905744 br0   B   IP 172.27.14.98.37972 > 255.255.255.255.upnp: UDP, length 254
09:26:34.034082 wl0.1 In  IP 172.27.15.3.59807 > 172.27.14.98.37972: UDP, length 741
09:26:34.034122 br0   Out IP 172.27.15.3.59807 > 172.27.14.98.37972: UDP, length 741
09:26:34.220437 wl0.4 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 3 PTR (QM)? _sonos._tcp.local. (35)
09:26:34.220444 wl0.1 Out IP 172.27.14.98.5353 > mdns.mcast.net.5353: 3 PTR (QM)? _sonos._tcp.local. (35)
09:26:34.220422 br0   M   IP 172.27.14.98.5353 > mdns.mcast.net.5353: 3 PTR (QM)? _sonos._tcp.local. (35)
09:26:34.387343 wl0.1 M   IP 172.27.15.3.5353 > mdns.mcast.net.5353: 0*- [0q] 1/0/6 PTR Sonos-XXXXXXXXXXXX@Media Room._sonos._tcp.local. (676)

The problem

09:26:30.580416 wl0.1 In  IP 172.27.15.3.37360 > 172.27.14.98.37972: UDP, length 741
09:26:30.580456 br0   Out IP 172.27.15.3.37360 > 172.27.14.98.37972: UDP, length 741
09:26:31.309102 wl0.1 In  IP 172.27.15.3.38139 > 172.27.14.98.37972: UDP, length 741
09:26:31.309125 br0   Out IP 172.27.15.3.38139 > 172.27.14.98.37972: UDP, length 741
09:26:32.701778 wl0.1 In  IP 172.27.15.3.41457 > 172.27.14.98.37972: UDP, length 741
09:26:32.701801 br0   Out IP 172.27.15.3.41457 > 172.27.14.98.37972: UDP, length 741
09:26:34.034082 wl0.1 In  IP 172.27.15.3.59807 > 172.27.14.98.37972: UDP, length 741
09:26:34.034122 br0   Out IP 172.27.15.3.59807 > 172.27.14.98.37972: UDP, length 741

Filtering out all the noise, I noticed that the Sonos device was trying to send a UDP packet from the ephemeral UDP ports (range 32768-65535) to my mobile device.

This is actually not surprising as that is how SSDP works as the device would switch to unicast after being discovered. Prior to this, I was not very familiar with SSDP and did not know that.

I noticed in a previous tcpdump before enabling two-way communication that this was being blocked:

00:13:65.371058 wl0.1 In  IP 172.27.15.3.46814 > 172.27.14.98.49972: UDP, length 737
00:13:54.373059 wl0.1 Out IP 172.27.15.1 > 172.27.15.3: ICMP 172.27.14.98 udp port 49972 unreachable, length 556

Solution

Adding custom firewall allow rules to Yazfi to allow this UDP traffic from Sonos devices

Yazfi allows additional iptables rules by adding a shell script with iptables commands to any file in `/jffs/addons/YazFi.d/userscripts.d/`

With that I created a file called `myscript.sh` within the folder and placed this in the file to allow UDP traffic on the ephemeral ports (range 32768-65535) originating from the Sonos device to flow back to the main LAN

#!/bin/sh
iptables -I YazFiFORWARD -i wl0.1 -o br0 -s 172.27.15.3 -p udp --dport 32768:65535 -j ACCEPT
  • `-I YazFiForward` - adds the rule to the FORWARD chain in the YazFi table
  • `-i wl0.1` - make sure to change this to your actual Guest Wi-Fi interface
  • `-o br0` - packets moving to the bridge interface
  • `-s 172.27.15.3` - make sure to change this to your actual Sonos device's IP address
  • `-p udp` - UDP packets only
  • `--dport 32768:65536` - ephemeral UDP port ranges only
  • `-j ACCEPT` - allow packets filtered by this rule
You can duplicate that iptables line for as many Sonos device you have and their respective IPs, or you can also use `-srcrange` (i.e. `-m iprange --src-range 172.27.15.2-172.27.15.9`) if you have configured continuous static DHCP IPs for them.

Be reminded to `chmod +x` the file afterwards

jarylc@RT-AX88U:/jffs/addons/YazFi.d/userscripts.d# chmod +x myscript.sh

Reverting to only allowing one-way (LAN to Guest) communication

During investigation, I allowed two-way communication, so I am reverting it to one-way only in the Yazfi configuration.

Testing the Sonos app again

Sure enough, after allowing the UDP packet to flow back allows the Sonos app to be snappy again.

Bonus

HomeAssistant

I integrated my Sonos systems with HomeAssistant as well, it is also recommended by them to enable communication back via port 1400

iptables -I YazFiFORWARD -i wl0.1 -o br0 -d 172.27.14.100 -p tcp --dport 1400 -j ACCEPT
  • `-I YazFiForward` - adds the rule to the FORWARD chain in the YazFi table
  • `-i wl0.1` - make sure to change this to your actual Guest Wi-Fi interface
  • `-o br0` - packets moving to the bridge interface
  • `-s 172.27.14.100` - make sure to change this to your actual HomeAssistant's IP address
  • `-p tcp` - TCP packets only
  • `-dport 1400` - port 1400 only
  • `-j ACCEPT` - allow packets filtered by this rule

It is also highly recommended to allow the Sonos systems to communicate with HomeAssistant directly (especially to use local media storage if you have any)

iptables -I YazFiFORWARD -i wl0.1 -o br0 -d 172.27.14.100 -p tcp --dport 8123 -j ACCEPT
  • `-I YazFiForward` - adds the rule to the FORWARD chain in the YazFi table
  • `-i wl0.1` - make sure to change this to your actual Guest Wi-Fi interface
  • `-o br0` - packets moving to the bridge interface
  • `-s 172.27.14.100` - make sure to change this to your actual HomeAssistant's IP address
  • `-p tcp` - TCP packets only
  • `-dport 8123` - make sure to change this to your actual HomeAssistant's port
  • `-j ACCEPT` - allow packets filtered by this rule