Finally got casting to LG TV in other VLAN to work, but can my nftables rules be improved?

After literally weeks of trying to figure out how to cast to my LG TV on another VLAN I finally got it figured out. I am planning on doing a write-up (somewhere here, if that is ok?), but before I do that it'd be great if somebody could check my firewall rules.

Network:

VLAN 1: br-lan (192.168.178.0/24)
VLAN 100: br-lan100 (10.1.100.0/24)

These two VLANs are in a firewall zone called SafeZone with forwarding between the zones enabled.

VLAN 103: br-iot(10.1.103.0/24)
VLAN 104: br-nonet (10.1.104.0/24)

These two VLANs are in a firewall zone called LessSafe and can't talk to each other or to devices in SafeZone. Devices in SafeZone can talk to devices in LessSafe.

100 and 104 don't play a role for casting, I am just mentioning them because their names appear in the rules.

The rules:

1. nft add rule inet fw4 mangle_prerouting iifname {"br-lan", "br-iot", "br-lan100", "br-nonet"} ip daddr 239.255.255.250 ip ttl 1 ip ttl set 2 # ssdp TTL mangling
2. nft add rule inet fw4 mangle_prerouting iifname {"br-lan", "br-iot", "br-lan100", "br-nonet"} ip daddr 224.0.0.251	        ip ttl set 2 # mdns TTL mangling

3. nft add set inet fw4 ssdp_out {type inet_service \; timeout 5s \;}
4. nft insert rule inet fw4 forward iifname {"br-iot", "br-nonet"} oifname {"br-lan", "br-lan100"} udp dport @ssdp_out counter accept
5. nft insert rule inet fw4 forward iifname {"br-iot", "br-nonet"} oifname {"br-lan", "br-lan100"} tcp dport @ssdp_out counter accept
6. nft insert rule inet fw4 forward ip daddr 239.255.255.250 udp dport 1900 set add udp sport @ssdp_out

Rules 1 and 2 take care of TTL so that packages can traverse VLAN boundaries.

Rule 6 opens ssdp port 1900 on IP 239.255.255.250 for the initial request.

Rule 3 creates an ip set.

Rule 4 and 5:
Here is what I think they do: if a device in br-lan connects to a device in br-iot these rules add the port the device connected on to the ip set which then opens the firewall for 5 seconds so the device in br-iot can talk back to the device in br-lan.

I am not sure that's true though. Don't these rules open the firewall whether a request was made from br-lan first or not?

Can rule 5 and 6 be written as one rule since they do the same except for the protocol?

Try this and see if it works:

...   meta l4proto {tcp, udp} th dport @ssdp_out   ...

I got bored after all that turkey, so added some whipped cream to your script. This loads (but otherwise untested):

nft -f - << "RULES"
    add set inet fw4 ssdp_out {
        type inet_service;
        timeout 5s;
    }

    define pre_inputs  = { "br-lan", "br-iot", "br-lan100", "br-nonet" }
    define fwd_inputs  = { "br-iot", "br-nonet"  }
    define fwd_outputs = { "br-lan", "br-lan100" }

    add rule inet fw4 mangle_prerouting  iifname $pre_inputs  ip daddr 239.255.255.250  ip ttl 1  ip ttl set 2  comment "ssdp TTL mangling"
    add rule inet fw4 mangle_prerouting  iifname $pre_inputs  ip daddr 224.0.0.251                ip ttl set 2  comment "mdns TTL mangling"

    insert rule inet fw4 forward  iifname $fwd_inputs  oifname $fwd_outputs  meta l4proto {tcp, udp} th dport @ssdp_out  counter accept
    insert rule inet fw4 forward  ip daddr 239.255.255.250  udp dport 1900  set add udp sport @ssdp_out
RULES

One tricky shell quirk in above: the quotes around the heredoc name at the start suppresses evaluation of $names in the script (otherwise you'd get errors with them shell-expanding to nothing). In otherwords, "RULES" behaves quite differently than RULES.

2 Likes

This works, first try, thank you very much! :slight_smile:

To follow up,

  1. Have you included your script in the backups by appending it to /etc/sysupgrade.conf? (Run sysupgrade --list-backup | grep script.name to make sure.) This gets picked up by any sysupgrade with "save config", auc and LuCI Attended Sysupgrade.

  2. How are you running the script? As part of normal fw4 startup via /etc/config/firewall?

    For that, I usually stick stuff it in /etc/firewall.user then stick this in /etc/config/firewall (and do echo /etc/firewall.user >> /etc/sysupgrade.conf to accomplish #1):

config include
        option enabled '1'
        option type 'script'
        option path '/etc/firewall.user'
        option fw4_compatible '1'

I just put it in /etc/firewall.user. Am I understanding you correctly, firewall.user isn't part of the backup when I create one in LuCI?

That is correct, try sysupgrade -l | grep firewall.user and if it's there, then you are good to go. When I tried it on a fresh install with that file in existence, but not listed in sysupgrade.conf, it was not shown as part of the backup list.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.