Block Internet access for some devices

I want to block some devices (IP Cameras) from the Internet to prevent them from phoning home to the cloud. I have configured static IP lease so their IP address is fixed.

This is the rule I have in /etc/config/firewall:

config rule
        option name 'Block-Cameras'
        option src 'lan'
        option target 'REJECT'
        list proto 'tcp'
        list proto 'udp'
        option dest 'wan'
        list src_ip '192.168.0.21'

nft list ruleset shows the rule was installed into nftables:

chain forward_lan {
                meta l4proto tcp ip saddr 192.168.0.21 counter packets 3 bytes 156 jump reject_to_wan comment "!fw4: Block-Cameras"
                meta l4proto udp ip saddr 192.168.0.21 counter packets 26660 bytes 2527440 jump reject_to_wan comment "!fw4: Block-Cameras"
                jump accept_to_wan comment "!fw4: Accept lan to wan forwarding"
                jump accept_to_lan
        }

However, I am still seeing the video feed from the cloud app and tcpdump shows the packets are passing through:

root@FriendlyWrt:~# tcpdump -i br-lan host 192.168.0.21 -s0 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on br-lan, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:30:48.783827 IP 192.168.0.21.35421 > 50.19.254.134.10240: UDP, length 40
12:30:48.784202 IP 192.168.0.1 > 192.168.0.21: ICMP 50.19.254.134 udp port 10240 unreachable, length 76
12:30:48.783828 IP 192.168.0.21.35421 > 122.248.234.207.10240: UDP, length 40
12:30:48.784350 IP 192.168.0.1 > 192.168.0.21: ICMP 122.248.234.207 udp port 10240 unreachable, length 76
12:30:48.783850 IP 192.168.0.21.35421 > 122.226.84.253.10240: UDP, length 40
12:30:48.784466 IP 192.168.0.1 > 192.168.0.21: ICMP 122.226.84.253 udp port 10240 unreachable, length 76
...
12:30:48.784064 IP 192.168.0.21.35421 > 129.80.110.57.10001: UDP, length 288
12:30:48.784134 IP 192.168.0.21.35421 > 192.168.1.1.10000: UDP, length 288
12:30:48.784174 IP 192.168.0.21.35421 > 141.147.50.196.10001: UDP, length 288
12:30:48.784296 IP 192.168.0.21.35421 > 89.168.126.249.10001: UDP, length 288
...
12:30:48.947299 IP 141.147.50.196.10001 > 192.168.0.21.35421: UDP, length 288
12:30:48.947956 IP 89.168.126.249.10001 > 192.168.0.21.35421: UDP, length 288
12:30:49.007743 IP 129.80.110.57.10001 > 192.168.0.21.35421: UDP, length 288

Edit: Apparently some packets are blocked (rejected) but the ones to the cloud service aren't. I installed a tracing rule in nftables and here is the monitor trace:

trace id 4e9c0651 ip trace_table trace_chain packet: iif "br-lan" ether saddr 00:62:6e:65:3c:72 ether daddr b2:42:33:1e:
ab:bf ip saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 10529 ip length 76 udp sp
ort 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 4e9c0651 ip trace_table trace_chain rule ip saddr 192.168.0.21 meta nftrace set 1 (verdict continue)
trace id 4e9c0651 ip trace_table trace_chain verdict continue
trace id 4e9c0651 ip trace_table trace_chain policy accept
trace id 4e9c0651 inet fw4 raw_prerouting packet: iif "br-lan" ether saddr 00:62:6e:65:3c:72 ether daddr b2:42:33:1e:ab:
bf ip saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 10529 ip protocol udp ip len
gth 76 udp sport 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 4e9c0651 inet fw4 raw_prerouting verdict continue
trace id 4e9c0651 inet fw4 raw_prerouting policy accept
trace id 4e9c0651 inet fw4 mangle_prerouting packet: iif "br-lan" ether saddr 00:62:6e:65:3c:72 ether daddr b2:42:33:1e:
ab:bf ip saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 10529 ip protocol udp ip
length 76 udp sport 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 4e9c0651 inet fw4 mangle_prerouting verdict continue
trace id 4e9c0651 inet fw4 mangle_prerouting policy accept
trace id 4e9c0651 inet fw4 prerouting packet: iif "br-lan" ether saddr 00:62:6e:65:3c:72 ether daddr b2:42:33:1e:ab:bf i
p saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 10529 ip protocol udp ip length
76 udp sport 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 4e9c0651 inet fw4 prerouting rule iifname "br-lan" jump helper_lan comment "!fw4: Handle lan IPv4/IPv6 helper a
ssignment" (verdict jump helper_lan)
trace id 4e9c0651 inet fw4 helper_lan verdict continue
trace id 4e9c0651 inet fw4 prerouting verdict continue
trace id 4e9c0651 inet fw4 prerouting policy accept
trace id 4e9c0651 inet nft-qos-monitor download packet: iif "br-lan" ether saddr 00:62:6e:65:3c:72 ether daddr b2:42:33:
1e:ab:bf ip saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 10529 ip protocol udp
ip length 76 udp sport 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 4e9c0651 inet nft-qos-monitor download verdict continue
trace id 4e9c0651 inet nft-qos-monitor download policy accept
trace id 7204081a inet fw4 mangle_forward packet: iif "br-lan" oif "eth0" ether saddr 00:62:6e:65:3c:72 ether daddr b2:4
2:33:1e:ab:bf ip saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 63 ip id 10529 ip protocol
 udp ip length 76 udp sport 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 7204081a inet fw4 mangle_forward verdict continue
trace id 7204081a inet fw4 mangle_forward policy accept
trace id 7204081a inet fw4 forward packet: iif "br-lan" oif "eth0" ether saddr 00:62:6e:65:3c:72 ether daddr b2:42:33:1e
:ab:bf ip saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 63 ip id 10529 ip protocol udp ip
 length 76 udp sport 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 7204081a inet fw4 forward rule ct state vmap { established : accept, related : accept } comment "!fw4: Handle f
orwarded flows" (verdict accept)
trace id 7204081a inet fw4 mangle_postrouting packet: iif "br-lan" oif "eth0" ether saddr 00:62:6e:65:3c:72 ether daddr
b2:42:33:1e:ab:bf ip saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 63 ip id 10529 ip prot
ocol udp ip length 76 udp sport 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 7204081a inet fw4 mangle_postrouting verdict continue
trace id 7204081a inet fw4 mangle_postrouting policy accept
trace id 7204081a inet nft-qos-monitor upload packet: iif "br-lan" oif "eth0" ether saddr 00:62:6e:65:3c:72 ether daddr
b2:42:33:1e:ab:bf ip saddr 192.168.0.21 ip daddr 141.147.50.196 ip dscp cs0 ip ecn not-ect ip ttl 63 ip id 10529 ip prot
ocol udp ip length 76 udp sport 35421 udp dport 10001 udp length 56 udp checksum 32896
trace id 7204081a inet nft-qos-monitor upload rule ip saddr 192.168.0.21 counter packets 349076 bytes 397114265 (verdict
 continue)
trace id 7204081a inet nft-qos-monitor upload verdict continue
trace id 7204081a inet nft-qos-monitor upload policy accept

Edit: It seems that the old connections (to 141.147..., 89.168..., 129.80..) are established in the NAT so it is not filtered? I read the solution is to flush the conntrack but I can't do echo f > /proc/net/nf_conntrack because the file has only read permissions. conntrack -F also does not work as I do not have the file or package.

I thought switching to OpenWRT would make things easier. But I have no idea what such a simple task seems impossible to do.

Pls, provide complete firewall rules. To be on safe side, both

cat /etc/config/firewall

nft list ruleset

    option target 'REJECT'
    list proto 'tcp'
    list proto 'udp'

why is the proto not set to ‘any’?

Feed them bogus default GW and DNS IPs ?

IMHO, it's much easier to create an IoT independent network with no internet access.

Does it matter? I only need to block tcp and udp. Though I have also tried proto any but it also has no effect.

Remove list src_ip '192.168.0.21'see if you lock yourself out from internet completely.

How is it easier to configure an IoT network than adding simple firewall filter rules? It seems way more complicated to create two subnets and configure routing rules between them. And I don't even know if that is even possible over my WiFi mesh.

Adding a firewall filter rule is very basic. Every commercial home router I have used could do it. And I have done it using iptables on OpenWRT 20 years ago. This new nftables is baffliing.

VLANs are actually quite simple, but yes, you're right that you should be able to achieve this block without using VLANs.

Please connect to your OpenWrt device using ssh and copy the output of the following commands and post it here using the "Preformatted text </> " button (red circle; this works best in the 'Markdown' composer view in the blue oval):

Screenshot 2025-10-20 at 8.14.14 PM

Remember to redact passwords, VPN keys, MAC addresses and any public IP addresses you may have:

ubus call system board
cat /etc/config/network
cat /etc/config/firewall

I'll post my complete /etc/config/firewall and ntf list ruleset later when I get home. But it should be nothing different since this is a newly bought NanoPi R76S with factory intsalled FriendlyWRT.

It appears you are using firmware that is not from the official OpenWrt project.

When using forks/offshoots/vendor-specific builds that are "based on OpenWrt", there may be many differences compared to the official versions (hosted by OpenWrt.org). Some of these customizations may fundamentally change the way that OpenWrt works. You might need help from people with specific/specialized knowledge about the firmware you are using, so it is possible that advice you get here may not be useful.

You may find that the best options are:

  1. Install an official version of OpenWrt, if your device is supported (see https://firmware-selector.openwrt.org).
  2. Ask for help from the maintainer(s) or user community of the specific firmware that you are using.
  3. Provide the source code for the firmware so that users on this forum can understand how your firmware works (OpenWrt forum users are volunteers, so somebody might look at the code if they have time and are interested in your issue).

If you believe that this specific issue is common to generic/official OpenWrt and/or the maintainers of your build have indicated as such, please feel free to clarify.

See your nft monitor trace output, there's: { established : accept, related : accept }

trace id 7204081a inet fw4 forward rule ct state vmap { established : accept, related : accept } comment "!fw4: Handle forwarded flows" (verdict accept)

openwrt’s firewall is stateful, so once a connection is marked as established, it is accepted and go through later rules in the forward chain.

Your rule is only applied to new connections. Any sessions that were active before you added the rule will continue to pass.

To fully apply the new rule you created, I'd recommend either restarting the firewall (/etc/init.d/firewall restart) or flushing conntrack (conntrack -F).

After that, new connection attempts from the device should be blocked.

I just installed conntrack using opkg and ran conntrack -F

root@FriendlyWrt:~# conntrack -F
conntrack v1.4.8 (conntrack-tools): connection tracking table has been emptied.

But the traffic is still getting through.

root@FriendlyWrt:~# tcpdump -i br-lan host 192.168.0.21 -s0 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on br-lan, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:49:32.091066 IP 192.168.0.21.35421 > 50.19.254.134.10240: UDP, length 40
22:49:32.091408 IP 192.168.0.1 > 192.168.0.21: ICMP 50.19.254.134 udp port 10240 unreachable, length 76
22:49:32.091067 IP 192.168.0.21.35421 > 122.226.84.253.10240: UDP, length 40
22:49:32.091067 IP 192.168.0.21.35421 > 122.248.234.207.10240: UDP, length 40
22:49:32.091088 IP 192.168.0.21.35421 > 120.24.59.150.10240: UDP, length 40
22:49:32.091102 IP 192.168.0.21.35421 > 61.188.37.216.10240: UDP, length 40
22:49:32.091193 IP 192.168.0.21.35421 > 114.215.137.159.10240: UDP, length 40
22:49:32.091194 IP 192.168.0.21.35421 > 46.137.188.54.10240: UDP, length 40
22:49:32.091194 IP 192.168.0.21.35421 > 129.80.110.57.10001: UDP, length 288

I can't see any incoming response though so that's halfway there

Try installing official openwrt. Create the rule and see if it works. If not, we can help you debug the issue when you’re using genuine openwrt.

Check if the camera stream still works, it shouldn’t. Your tcpdump is on br-lan, which sees packets before the firewall drops them. Capture on the WAN interface instead, you should see that they never leave.

You're right.

root@FriendlyWrt:~# tcpdump -i eth1 host 46.137.188.54 -s0 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
00:17:42.048372 IP 192.168.0.23.35421 > 46.137.188.54.10240: UDP, length 40
00:17:42.371505 IP 192.168.0.21.35421 > 46.137.188.54.10240: UDP, length 40
00:17:42.547994 IP 192.168.0.23.35421 > 46.137.188.54.10240: UDP, length 40
00:17:43.049439 IP 192.168.0.23.35421 > 46.137.188.54.10240: UDP, length 40

Packets are hitting eth1

root@FriendlyWrt:~# tcpdump -i eth0 host 46.137.188.54 -s0 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

But nothing on eth0

Seems like conntrack -F did the trick. Now to stop my cameras from spamming those UDP packets. I might have to set their DCHP lease gateway to 127.0.0.1

Thanks for the advice. Yes, I know I'm not on an official version. But without any sdcard or USB-A cable, I have no means to install or flash my NanoPi now.

Since FriendlyWRT came pre-installed, I rather just leave it in place and see if the problem can be solved by configuration, which it did. I had to install conntrack and run conntrack -F

In that case, please direct your questions to the FriendlyWRT support resources. It is not the same thing as OpenWrt and it works differently, so you need to ask for support there.

That said, it sounds like your problem is now solved...

If your problem is solved, please consider marking this topic as [Solved]. See How to mark a topic as [Solved] for a short how-to.
Thanks! :slight_smile: