Port forward UDP to internal multicast ? Is it possible?

Hello,

I would like to forward any packets coming in to port 22223 UDP

to 239.0.0.1:9990

Is this possible ?

And in the same vein

Can I forward internal UDP multicast to a single outside host ?

Example

internal UDP packets received on LAN side 239.0.0.1:9991 to internet host example:22224 on WAN side

(Preferably in a way that uses the router hardware properly and not blows up the CPU on my weak router ? (in other words, 1 megabit of UDP multicast packets shouldn't use more cpu power than a 1 megabit http download))

Please post output of

ubus call system board
1 Like

root@router:~# ubus call system board
{
"kernel": "5.10.161",
"hostname": "router",
"system": "Qualcomm Atheros QCA9558 ver 1 rev 0",
"model": "TP-Link Archer C7 v2",
"board_name": "tplink,archer-c7-v2",
"rootfs_type": "squashfs",
"release": {
"distribution": "OpenWrt",
"version": "22.03.3",
"revision": "r20028-43d71ad93e",
"target": "ath79/generic",
"description": "OpenWrt 22.03.3 r20028-43d71ad93e"
}
}

I could update the latest openwrt, but I have so many settings and stuff configured that I would have to re-do.

But imagine I had a fresh, latest version of openwrt

It is DNAT type rule with multicast as destination, quite simple, or you can install some multicast forwarder .

Hi,

So I'm trying to get the "easy" case to work first

So on the router I've try the following

uci add firewall redirect # =cfg343837
uci set firewall.@redirect[-1].dest='lan'
uci set firewall.@redirect[-1].target='DNAT'
uci set firewall.@redirect[-1].name='Forward UDP 22223 to multicast'
uci set firewall.@redirect[-1].src='wan'
uci set firewall.@redirect[-1].src_dport='22223'
uci set firewall.@redirect[-1].dest_ip='239.0.0.1'
uci set firewall.@redirect[-1].dest_port='9990'

I have this setup on various hosts listening to traffic

First test , streaming mp4 file from internet host, using ffmpeg to my UDP port 22223

sender
on internet host : ffmpeg -re -i testfile1.mp4 -c copy -f mpegts udp://MYHOMEINTERNETADDRESS.net:22223

listeners

on router.lan : tcpdump port 22223
on router.lan : tcpdump -i any port 9990
on wapn.lan : tcpdump port 9990
computer wireshark filter : ip.dst == 239.0.0.1
computer ffplay : ffplay -hide_banner -fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 -max_delay 0 "udp://239.0.0.1:9990"

Result

on router.lan : tcpdump port 22223 :  UDP packets observed
on router.lan : tcpdump -i any port 9990 :   nothing observed
on wapn.lan : tcpdump port 9990 :  nothing observed
computer wireshark filter : ip.dst == 239.0.0.1 : nothing observed
computer ffplay : nothing happens

Next test


streaming mp4 file from LAN host to multicast 239.0.0.1:9990

sender
on comprouter.lan : ffmpeg -re -i testfile1.mp4 -c copy -f mpegts udp://239.0.0.1:9990

listeners

on router.lan : tcpdump port 22223
on router.lan : tcpdump -i any port 9990
on wapn.lan : tcpdump port 9990
computer wireshark filter : ip.dst == 239.0.0.1
computer ffplay : ffplay -hide_banner -fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 -max_delay 0 "udp://239.0.0.1:9990"

results

on router.lan : tcpdump port 22223 :  nothing observed
on router.lan : tcpdump -i any port 9990 :   UDP packets observed
on wapn.lan : tcpdump port 9990 :  UDP packets observed
computer wireshark filter : ip.dst == 239.0.0.1 : UDP packets observed
computer ffplay : video appears

next test


streaming desktop capture from my computer

sender

on my computer : ffmpeg -hide_banner -filter_complex "ddagrab=framerate=30:output_idx=1:video_size=3840x2160,hwdownload,format=bgra,scale=1280:720" -colorspace bt709 -chroma_sample_location left -c:v h264_nvenc -preset p1 -tune ull -bufsize 600k -g 15 -pix_fmt nv12 -flags low_delay -f mpegts udp://239.0.0.1:9990

results

on router.lan : tcpdump port 22223 :   nothing appears
on router.lan : tcpdump -i any port 9990 :    UDP packets observed
on wapn.lan : tcpdump port 9990 :   UDP packets observed
computer wireshark filter : ip.dst == 239.0.0.1 :  UDP packets observed
computer ffplay : Desktop video stream visible

So LAN multicast works great, but my router.lan is not port forwarding incoming UDP packets to the address 239.0.0.1:9990 ?

Did I configure it wrong ?

Here is the config again, in port forwards

and here is the rule

firewall.@redirect[26]=redirect
firewall.@redirect[26].dest='lan'
firewall.@redirect[26].target='DNAT'
firewall.@redirect[26].name='Forward UDP 22223 to multicast'
firewall.@redirect[26].src='wan'
firewall.@redirect[26].src_dport='22223'
firewall.@redirect[26].dest_ip='239.0.0.1'
firewall.@redirect[26].dest_port='9990'

I have many other redirects they all seem to work fine ?

Please refrain from posting pictures

So it should work but it doesn't ....

And it seems this is simply because mc_forwarding is off

root@router:~# cat /proc/sys/net/ipv4/conf/all/mc_forwarding
0
root@router:~# sysctl -w net.ipv4.conf.all.mc_forwarding=1
sysctl: error setting key 'net.ipv4.conf.all.mc_forwarding': Permission denied

According to

This is because multicast forwarding is disabled in kernel by default in linux

That would be the kernel config parameter CONFIG_MROUTE

Advice points to using smcroute and/or igmproxy and more complex config, but I rather avoid this if possible as that would mean passing all multicast packets through the cpu again, probably doubling or more the cpu load.

Looking at the nftables using

nft list ruleset

in chain dstnat_lan { I found
ip saddr 192.168.1.0/24 ip daddr 192.168.2.102 udp dport 22223 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast (reflection)"

In this case 192.168.2.102 is my upstream DMZ router

There is also a rule in chain srcnat_lan {
ip saddr 192.168.1.0/24 ip daddr 239.0.0.1 udp dport 9990 snat ip to 192.168.1.1 comment "!fw4: Forward UDP 22223 to multicast (reflection)"

I also found this third rule in chain dstnat_wan {
meta nfproto ipv4 udp dport 22223 counter packets 0 bytes 0 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"

This rule has a counter and if I watch it while sending a video stream from outside into my port 22223 I can see the counter go up !

root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 0 bytes 0 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 0 bytes 0 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 0 bytes 0 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 73 bytes 94352 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 157 bytes 202548 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 209 bytes 269804 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 241 bytes 306796 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 318 bytes 400696 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 352 bytes 441504 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 381 bytes 476156 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 413 bytes 511268 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 492 bytes 620828 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 521 bytes 653224 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"
root@router:~# nft list ruleset | grep 22223 | grep meta
                meta nfproto ipv4 udp dport 22223 counter packets 543 bytes 677152 dnat ip to 239.0.0.1:9990 comment "!fw4: Forward UDP 22223 to multicast"

So it does look like the packets are being received, but they're not being sent anywhere ?

I thought, maybe it is sending the packet out of the wrong interface but

tcpdump -i any port 9990

While it is receiving those packets from outside, and there is just nothing showing up ...

Not sure where to go from there, I sure hope it's not that CONFIG_MROUTE kernel parameter !

So, as far as I can tell, dnat doesn't work because CONFIG_MROUTE is not set and someone somewhere decided to just drop all packets for that address range instead of doing what I asked.

Anyway, I think the next solution is the mangle target, just overwrite the destination address directly. That's probably going to be more computationally expensive than dnat, which might have worked with NAT hardware acceleration but it won't be as expensive as routing all those packets through a userspace application like smcroute and do a second or maybe even third round trip through the CPU.

Now the question becomes, how can I use LuCI to create a mangle rule ?

I -think- the rule is as follows

table inet fw4 {
    chain mangle_prerouting {
        type filter hook prerouting priority mangle; policy accept;
        iifname "eth0.2" udp dport 22223 ip daddr set 239.0.0.1 comment "Rewrite destination to 239.0.0.1"
    }
}

But I've had a look aroung in

luci/admin/network/firewall/zones
luci/admin/network/firewall/forwards
luci/admin/network/firewall/rules
luci/admin/network/firewall/snats

Didn't find anything about a mangle rule action

There was a possible configution in firewall/snats, that was almost the right thing, as follows

but the action MANGLE is not there, I'm not sure if it would have been valid at this place

image

This is what the config looks like

uci add firewall nat # =cfg2c93c8
uci set firewall.@nat[-1].name='Forward UDP to Multicast'
uci add_list firewall.@nat[-1].proto='udp'
uci set firewall.@nat[-1].src='lan'
uci set firewall.@nat[-1].dest_port='9990'
uci set firewall.@nat[-1].target='SNAT'
uci set firewall.@nat[-1].snat_ip='239.0.0.1'
uci set firewall.@nat[-1].snat_port='9990'

I tried anyway, doesn't work, the description explains why

So it re-writes the SOURCE address but I need to rewrite the destination, so SNAT is not the right thing.

I was hoping maybe in traffic rules, but the only actions listed are

drop
accept
reject
don't track
assign conntrack helper
apply firewall mark
XOR firewall mark
DSCP classification

I tried creating something that looks right using uci

root@router:~# uci add firewall rule # Creates a new rule and returns a unique ID (e.g., `cfgXXXXXX`)
cfg2c92bd
root@router:~# uci set firewall.@rule[-1].name='Rewrite UDP to Multicast'
root@router:~# uci set firewall.@rule[-1].proto='udp' # Match UDP traffic
root@router:~# uci set firewall.@rule[-1].src='wan' # Match packets from the WAN zone
root@router:~# uci set firewall.@rule[-1].dest='lan' # Specify the LAN zone as the output
root@router:~# uci set firewall.@rule[-1].dest_port='22223' # Match destination port 22223
root@router:~# uci set firewall.@rule[-1].target='DNAT' # Set the rule's action to rewrite the packet
root@router:~# uci set firewall.@rule[-1].dest_ip='239.0.0.1' # Rewrite the destination address to the multicast group
root@router:~# uci set firewall.@rule[-1].family='ipv4' # Ensure the rule is applied to IPv4 traffic
root@router:~# uci set firewall.@rule[-1].table='mangle' # Place the rule in the mangle table
root@router:~# uci set firewall.@rule[-1].chain='prerouting' # Apply the rule in the prerouting chain
root@router:~#
root@router:~# # Commit and reload the firewall configuration
root@router:~# uci commit firewall
root@router:~# /etc/init.d/firewall reload
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @rule[11] (Rewrite UDP to Multicast) specifies unknown option 'table'
Section @rule[11] (Rewrite UDP to Multicast) specifies unknown option 'chain'
Section @redirect[8] (testrule1) is disabled, ignoring section
Section @redirect[24] (Forward UDP 22223 to multicast) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible
/dev/stdin:120:51-61: Error: Could not process rule: No such file or directory
                ip daddr 239.0.0.1 udp dport 22223 counter jump dnat_to_lan comment "!fw4: Rewrite UDP to Multicast"
                                                                ^^^^^^^^^^^
root@router:~#

Next I tried adding the rule to /etc/nftables.d/custom-rules.nft

nano /etc/nftables.d/custom-rules.nft

table inet fw4 {
    chain prerouting {
        type filter hook prerouting priority mangle; policy accept;
        iif "eth0.2" udp dport 22223 ip daddr set 239.0.0.1 comment "Rewrite UDP to Multicast"
    }
}

That does not work, with the following error

root@router:~# /etc/init.d/firewall reload
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @redirect[8] (testrule1) is disabled, ignoring section
Section @redirect[24] (Forward UDP 22223 to multicast) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible
In file included from /dev/stdin:20:2-33:
/etc/nftables.d/custom-rules.nft:1:1-5: Error: syntax error, unexpected table
table inet fw4 {
^^^^^
/dev/stdin:27:14-14: Error: syntax error, unexpected '{', expecting string
        chain input {
                    ^
/dev/stdin:28:3-6: Error: syntax error, unexpected type
                type filter hook input priority filter; policy accept;
                ^^^^
/dev/stdin:28:43-48: Error: syntax error, unexpected policy
                type filter hook input priority filter; policy accept;
                                                        ^^^^^^
/dev/stdin:30:3-9: Error: syntax error, unexpected iifname
                iifname "lo" accept comment "!fw4: Accept traffic from loopback"
                ^^^^^^^
/dev/stdin:32:6-10: Error: syntax error, unexpected state, expecting timeout or expectation or helper
                ct state established,related accept comment "!fw4: Allow inbound established and related flows"
                   ^^^^^
/dev/stdin:33:3-5: Error: syntax error, unexpected tcp
                tcp flags & (fin | syn | rst | ack) == syn jump syn_flood comment "!fw4: Rate limit TCP syn packets"
                ^^^
/dev/stdin:34:3-6: Error: syntax error, unexpected meta
                meta l4proto udp counter accept comment "!fw4: Allow UDP"
                ^^^^
/dev/stdin:35:3-9: Error: syntax error, unexpected iifname
                iifname "br-lan" jump input_lan comment "!fw4: Handle lan IPv4/IPv6 input traffic"
                ^^^^^^^
/dev/stdin:36:3-9: Error: syntax error, unexpected iifname
                iifname "eth0.2" jump input_wan comment "!fw4: Handle wan IPv4/IPv6 input traffic"
                ^^^^^^^

Chatgpt claims this is because

The issue here stems from directly pasting an entire nftables configuration block (table inet fw4) into /etc/nftables.d/custom-rules.nft. This approach does not work in OpenWrt because the custom-rules.nft file is not a full ruleset file, but a fragment of rules that is inserted into the main fw4 ruleset. You cannot redefine tables or chains in this file.

It then suggests the following syntax

iif "eth0.2" udp dport 22223 ip daddr set 239.0.0.1 comment "Rewrite UDP to Multicast"

And that's not valid either

root@router:~# nano /etc/nftables.d/custom-rules.nft
root@router:~# /etc/init.d/firewall reload
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @redirect[8] (testrule1) is disabled, ignoring section
Section @redirect[24] (Forward UDP 22223 to multicast) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible
In file included from /dev/stdin:20:2-33:
/etc/nftables.d/custom-rules.nft:1:1-3: Error: syntax error, unexpected iif
iif "eth0.2" udp dport 22223 ip daddr set 239.0.0.1 comment "Rewrite UDP to Multicast"
^^^
root@router:~#

Then I got this next formulation, also doesn't work

root@router:~# nano /etc/nftables.d/custom-rules.nft
root@router:~# cat /etc/nftables.d/custom-rules.nft
ip protocol udp iif "eth0.2" udp dport 22223 ip daddr set 239.0.0.1 comment "Rewrite UDP to Multicast"
root@router:~# nft -c -f /etc/nftables.d/custom-rules.nft
/etc/nftables.d/custom-rules.nft:1:4-11: Error: syntax error, unexpected protocol, expecting string
ip protocol udp iif "eth0.2" udp dport 22223 ip daddr set 239.0.0.1 comment "Rewrite UDP to Multicast"
   ^^^^^^^^
root@router:~# /etc/init.d/firewall reload
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @redirect[8] (testrule1) is disabled, ignoring section
Section @redirect[24] (Forward UDP 22223 to multicast) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible
In file included from /dev/stdin:20:2-33:
/etc/nftables.d/custom-rules.nft:1:1-2: Error: syntax error, unexpected ip
ip protocol udp iif "eth0.2" udp dport 22223 ip daddr set 239.0.0.1 comment "Rewrite UDP to Multicast"
^^

It also suggested

ip daddr 239.0.0.1 udp dport 22223 iif "eth0.2" counter ip daddr set 239.0.0.1 comment "Rewrite UDP to Multicast"

That doesn't work

It also suggested

table inet fw4 {
    chain mangle_prerouting {
        type filter hook prerouting priority mangle; policy accept;
        udp dport 22223 iif "eth0.2" ip daddr set 239.0.0.1 comment "Rewrite UDP to Multicast"
    }
}

That doesn't work

I am running out of options and permutations .....

Are the TTL of these packets >=2 ?

If not, it's your router likely dropping them.

(In some cases you still have to handle the issue that the packets Die In Transit - "Time To Live Exceeded In Transit".)

You may wish to verify.

2 Likes

Thanks good idea to check

In my current setup, I see the incoming packets have a TTL of 60

05:58:09.874867 IP (tos 0x0, ttl 60, id 32305, offset 0, flags [DF], proto UDP (17), length 968)
    123.123.123.123.60635 > 192.168.2.102.22223: UDP, length 940

The closest I have come to something that might work was the port forward

firewall.@redirect[24]=redirect
firewall.@redirect[24].dest='lan'
firewall.@redirect[24].target='DNAT'
firewall.@redirect[24].name='Forward UDP 22223 to multicast'
firewall.@redirect[24].src='wan'
firewall.@redirect[24].src_dport='22223'
firewall.@redirect[24].dest_ip='239.0.0.1'
firewall.@redirect[24].dest_port='9990'
firewall.@redirect[24].proto='udp'
firewall.@redirect[24].enabled='1'

But this does not provide a method for changing the TTL. It is possible something somewhere is setting the TTL to 1 and maybe there is more than one hop between eth0.2/br-lan/eth1.1 ?

when I run tcpdump -i any port 22223 -v

I can see the packets coming from outside to port 22223

when I run tcpdump -i any port 9990 -v , there is nothing showing up