iptables: drop incoming UDP packets, destination port 1900

I am trying to use iptables to drop UDP packets that have destination port 1900. This shall affect both directions, so I added one rule each for the INPUT and the OUTPUT chain of the filter table.

root@hostname:~# iptables --table filter --list --numeric --verbose
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:1900

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:1900

This is what the incoming packets look like:

root@hostname:~# tcpdump -i enp2s0 -n "udp and port 1900"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp2s0, link-type EN10MB (Ethernet), capture size 262144 bytes
11:17:35.845252 IP 192.168.0.1.56189 > 239.255.255.250.1900: UDP, length 123
11:17:36.285268 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 133
11:17:36.285758 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 127
11:17:36.286157 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 127
11:17:36.286566 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 129
11:17:36.286971 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 129
11:17:36.287390 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 124
11:17:40.845707 IP 192.168.0.1.56189 > 239.255.255.250.1900: UDP, length 123
11:17:41.285393 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 133
11:17:41.285810 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 127
11:17:41.286220 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 127
11:17:41.286613 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 129
11:17:41.287029 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 129
11:17:41.287405 IP 192.168.0.1.36900 > 239.255.255.250.1900: UDP, length 124
^C
14 packets captured
14 packets received by filter
0 packets dropped by kernel

Usually iptables works very well, I had other filter rules that worked as expected. This OUTPUT rule also works as expected. The following output shows that this OUTPUT rule caught (and dropped) a few packets.

root@hostname:~# iptables --table filter --list OUTPUT --numeric --verbose
Chain OUTPUT (policy ACCEPT 412 packets, 87079 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    6  1128 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:1900

But the INPUT rule does not work. I have now tried several rule variants to catch the incoming packets, no success.

root@hostname:~# iptables --table filter --list INPUT --numeric --verbose
Chain INPUT (policy ACCEPT 385 packets, 138K bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:1900
    0     0 DROP       udp  --  enp0s2 *       0.0.0.0/0            0.0.0.0/0            udp dpt:1900
    0     0 DROP       all  --  *      *       0.0.0.0/0            239.255.255.250     
    0     0 DROP       all  --  enp0s2 *       0.0.0.0/0            239.255.255.250     
    0     0 DROP       udp  --  *      *       0.0.0.0/0            239.255.255.250     
    0     0 DROP       udp  --  enp0s2 *       0.0.0.0/0            239.255.255.250     
    0     0 DROP       all  --  enp0s2 *       0.0.0.0/0            224.0.0.0/4         

For me it looks like the rules are correct but the incoming packets aren't even visible to the INPUT chain. The counter displayed per chain policy doesn't match the count of packets I see in tcpdump. In one case I saw like 20 UDP packets in tcpdump, but the counter showed only 1 packet: Chain INPUT (policy ACCEPT 1 packets, 52 bytes).

The incoming packets are also not visible in the log file, when I add a rule that logs every packet in the INPUT chain:

Chain INPUT (policy ACCEPT 655 packets, 573K bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:1900
   46  5527 LOG        udp  --  *      *       0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 4 prefix "[INPUT UDP] "
  657  573K LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 4 prefix "[INPUT all] "

The only packets in the log are HTTPS and DNS.

My questions are:

  1. Why is the INPUT rule not effective? Maybe iptables doesn't handle the incoming packets because they are addressed to some sort of broadcast address?
  2. How can I drop the packets (UDP, destination port 1900) with iptables?

This is all about IPv4, I am not worried about IPv6.

Linux kernel version: 5.8.0-44-generic #50~20.04.1-Ubuntu SMP

Update (2021-05-26): I tried a few older kernels, read some changelogs and known bugs. No success. I ended up with buying a dedicated firewall.


This is less of an answer and more of supporting your conclusions.

For me it looks like the rules are correct but the incoming packets aren't even visible to the INPUT chain. The counter displayed per chain policy doesn't match the count of packets I see in tcpdump. In one case I saw like 20 UDP packets in tcpdump, but the counter showed only 1 packet: Chain INPUT (policy ACCEPT 1 packets, 52 bytes).

I get the same. Here is my rules set script:

doug@rpi2:~ $ cat test-iptables
#!/bin/sh
FWVER=0.01
#
# test_firewall 2021.03.05 Ver:0.01
#       Just some simple rules for a test.
#       Currently for this question:
#       https://askubuntu.com/questions/1321344/iptables-drop-incoming-udp-packets-destination-port-1900
#

echo "Loading test_firewall version $FWVER..\n"

# The location of the iptables program
#
IPTABLES=/usr/sbin/iptables

#Set some stuff
#
EXTIF="eth0"
UNIVERSE="0.0.0.0/0"

#Clearing any previous configuration
#
#echo "  Clearing any existing rules and setting default policies.."
$IPTABLES -P INPUT ACCEPT
$IPTABLES -F INPUT
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -F OUTPUT

# Otherwise, I can not seem to delete it later on
$IPTABLES -F
# Delete user defined chains
$IPTABLES -X

# Reset all IPTABLES counters
$IPTABLES -Z
$IPTABLES -t nat -Z

# try to prevent accidental loss of my SSH connection.
# added after I did exactly that.
#
$IPTABLES -A INPUT -i $EXTIF -p tcp --dport 22 -j ACCEPT

# loopback interfaces are valid.
#
$IPTABLES -A INPUT -i lo -s $UNIVERSE -d $UNIVERSE -j ACCEPT

$IPTABLES -A INPUT -i $EXTIF -p udp --dport 1900 -j LOG --log-prefix "U1900:" --log-level info
$IPTABLES -A INPUT -i $EXTIF -p udp --dport 1900 -j DROP

$IPTABLES -A INPUT -d 224.0.0.7 -j LOG --log-prefix "IP224:" --log-level info
$IPTABLES -A INPUT -d 224.0.0.7 -j DROP

$IPTABLES -A INPUT -p udp --dport 8001 -j LOG --log-prefix "U8001:" --log-level info
$IPTABLES -A INPUT -p udp --dport 8001 -j DROP

$IPTABLES -A INPUT -m pkttype --pkt-type broadcast -j LOG --log-prefix "BROAD:" --log-level info
$IPTABLES -A INPUT -m pkttype --pkt-type broadcast -j DROP
$IPTABLES -A INPUT -m pkttype --pkt-type multicast -j LOG --log-prefix "MULTI:" --log-level info
$IPTABLES -A INPUT -m pkttype --pkt-type multicast -j DROP
$IPTABLES -A INPUT -m pkttype --pkt-type UNICAST -j LOG --log-prefix "UNI:" --log-level info
$IPTABLES -A INPUT -m pkttype --pkt-type UNICAST -j DROP
#$IPTABLES -A INPUT -m pkttype --pkt-type ANYCAST -j LOG --log-prefix "ANY:" --log-level info
#$IPTABLES -A INPUT -m pkttype --pkt-type ANYCAST -j DROP

$IPTABLES -A INPUT -s 192.168.111.123  -p udp --sport 8001 -j DROP

$IPTABLES -A INPUT -s 192.168.111.122 -j DROP
$IPTABLES -A INPUT -d 224.0.0.0/4 -j LOG --log-prefix "IP224B:" --log-level info
$IPTABLES -A INPUT -d 224.0.0.0/4 -j DROP

# $IPTABLES -A FORWARD -p udp -i $EXTIF --dport 8001 -j DROP

$IPTABLES -A INPUT -j LOG --log-prefix "CATCH:" --log-level info

echo test_iptables $FWVER done.
echo "test_iptables $FWVER done..." >> /dev/kmsg

In my case, I have a Samsung T.V. at 192.168.111.123 constantly spewing packets to port 8001:

doug@rpi2:~ $ sudo tcpdump -n -tttt -vvv host 192.168.111.123
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
2021-03-06 13:26:24.073438 IP (tos 0x0, ttl 64, id 57376, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.111.123.36088 > 192.168.111.255.15600: [udp sum ok] UDP, length 35
2021-03-06 13:26:24.840570 IP (tos 0x0, ttl 1, id 35446, offset 0, flags [DF], proto UDP (17), length 232)
    192.168.111.123.8001 > 224.0.0.7.8001: [udp sum ok] UDP, length 204
2021-03-06 13:26:26.849469 IP (tos 0x0, ttl 1, id 35532, offset 0, flags [DF], proto UDP (17), length 232)
    192.168.111.123.8001 > 224.0.0.7.8001: [udp sum ok] UDP, length 204
^C

And I agree they simply do not get to the INPUT chain:

doug@rpi2:~ $ sudo iptables -xvnL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination
     194    15856 ACCEPT     tcp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
       0        0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
       0        0 LOG        udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp dpt:1900 LOG flags 0 level 6 prefix "U1900:"
       0        0 DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp dpt:1900
       0        0 LOG        all  --  *      *       0.0.0.0/0            224.0.0.7            LOG flags 0 level 6 prefix "IP224:"
       0        0 DROP       all  --  *      *       0.0.0.0/0            224.0.0.7
       0        0 LOG        udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:8001 LOG flags 0 level 6 prefix "U8001:"
       0        0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:8001
    1612   173750 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = broadcast LOG flags 0 level 6 prefix "BROAD:"
    1612   173750 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = broadcast
     460    69304 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = multicast LOG flags 0 level 6 prefix "MULTI:"
     460    69304 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = multicast
      96    13068 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = unicast LOG flags 0 level 6 prefix "UNI:"
      96    13068 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = unicast
       0        0 DROP       udp  --  *      *       192.168.111.123      0.0.0.0/0            udp spt:8001
       0        0 DROP       all  --  *      *       192.168.111.122      0.0.0.0/0
       0        0 LOG        all  --  *      *       0.0.0.0/0            224.0.0.0/4          LOG flags 0 level 6 prefix "IP224B:"
       0        0 DROP       all  --  *      *       0.0.0.0/0            224.0.0.0/4
       0        0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 6 prefix "CATCH:"

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 264 packets, 39247 bytes)
    pkts      bytes target     prot opt in     out     source               destination

And we see nothing related in the syslog file:

doug@rpi2:~ $ grep -a "DPT=8001" /var/log/syslog
doug@rpi2:~ $