Package: miniupnpd-nftables
Version: 2.2.1-1
Severity: normal
Tags: patch

Dear Maintainer,

I have a manually-crafted set of firewall rules, currently using
iptables-nft but still heavily based on classic iptables way of doing
things.

On update from Debian 10 to 11, miniupnpd transitioned to the use of
miniupnpd-nftables, as expected. But I was surprised to find that after
the transition, my existing NAT rules unrelated to miniupnpd had started 
vanishing every time I stopped the miniupnpd service.

On examination of the nft_removeall.sh script, it turns out it runs "nft
delete table nat", which removes any NAT rules created using
iptables-nft's "iptables -t nat" command. As the comment at the
beginning of the script says "Do not disturb other existing structures
in nftables", this must not have been the intention.

I also noticed that the stub chains generated by /etc/miniupnpd/nft_init.sh
seem to be completely unused by the actual daemon, and the rules the
daemon creates won't match the stub chains. In fact, it looks like the
daemon might be able to work just fine without the nft_init script at
all.

On further investigation, I found that the daemon creates three
Netfilter tables, all named "miniupnpd":
* an ip6 table with two NAT chains
* an ip (=IPv4-only) table with two NAT chains
* an inet (=IPv4/v6) table with a single filter chain

The default names for the tables and the chains did match neither what the
scripts used, nor the commented-out values in the miniupnpd.conf file.
The defaults can be found in the source code file 
miniupnpd-2.2.1/netfilter_nft/nftnlrdr_misc.c, lines 66-69.

The name of the tables created by the daemon is clearly intended to be
configurable in the source code, but the configuration file processing
code does not yet define an option to change it away from default.

I cleaned up the scripts to match the assumed intent and the actual
behavior of miniupnpd-nftables, and now it seems to work fine: see patch below.

I created variables at the beginning of each script to match the chain
name configuration options in miniupnpd.conf. I also added a variable
for the table name, in the assumption that the actual configuration
option might eventually be added.

I made the nft commands in the scripts explicitly specify the address 
family in each case, to make it more obvious what the scripts will do.
Since existing documentation is rather sparse, this might be the
next best thing.

diff -rup miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_delete_chain.sh 
miniupnpd-2.2.1/netfilter_nft/scripts/nft_delete_chain.sh
--- miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_delete_chain.sh      
2019-06-26 00:30:54.000000000 +0300
+++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_delete_chain.sh   2021-09-20 
01:05:14.457155573 +0300
@@ -1,5 +1,14 @@
 #!/bin/sh
 
-nft delete chain nat MINIUPNPD
-nft delete chain nat MINIUPNPD-POSTROUTING
-nft delete chain filter MINIUPNPD
+# If you modify the corresponding settings in miniupnpd.conf,
+# change these variables in the scripts too.
+upnp_table=miniupnpd
+upnp_forward_chain=forward
+upnp_nat_chain=prerouting
+upnp_nat_postrouting_chain=postrouting
+
+nft delete chain ip ${upnp_table} ${upnp_nat_chain}
+nft delete chain ip ${upnp_table} ${upnp_nat_postrouting_chain}
+nft delete chain inet ${upnp_table} ${upnp_forward_chain}
+nft delete chain ip6 ${upnp_table} ${upnp_nat_chain}
+nft delete chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain}
diff -rup miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_display.sh 
miniupnpd-2.2.1/netfilter_nft/scripts/nft_display.sh
--- miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_display.sh   2019-06-26 
00:26:46.000000000 +0300
+++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_display.sh        2021-09-20 
01:05:24.707083374 +0300
@@ -1,8 +1,19 @@
 #!/bin/sh
 
-# Prerouting
-nft list chain ip nat MINIUPNPD
-# Postrouting
-nft list chain ip nat MINIUPNPD-POSTROUTING
-# Filter
-nft list chain inet filter MINIUPNPD
+# If you modify the corresponding settings in miniupnpd.conf,
+# change these variables in the scripts too.
+upnp_table=miniupnpd
+upnp_forward_chain=forward
+upnp_nat_chain=prerouting
+upnp_nat_postrouting_chain=postrouting
+
+# IPv6 prerouting
+nft list chain ip6 ${upnp_table} ${upnp_nat_chain}
+# IPv6 postrouting
+nft list chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain}
+# IPv4 prerouting
+nft list chain ip ${upnp_table} ${upnp_nat_chain}
+# IPv4 postrouting
+nft list chain ip ${upnp_table} ${upnp_nat_postrouting_chain}
+# IPv4/v6 filter
+nft list chain inet ${upnp_table} ${upnp_forward_chain}
diff -rup miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_flush.sh 
miniupnpd-2.2.1/netfilter_nft/scripts/nft_flush.sh
--- miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_flush.sh     2019-06-26 
00:30:54.000000000 +0300
+++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_flush.sh  2021-09-20 
01:05:35.473674198 +0300
@@ -1,5 +1,14 @@
 #!/bin/sh
 
-nft flush chain ip nat MINIUPNPD
-nft flush chain ip nat MINIUPNPD-POSTROUTING
-nft flush chain inet filter MINIUPNPD
+# If you modify the corresponding settings in miniupnpd.conf,
+# change these variables in the scripts too.
+upnp_table=miniupnpd
+upnp_forward_chain=forward
+upnp_nat_chain=prerouting
+upnp_nat_postrouting_chain=postrouting
+
+nft flush chain ip ${upnp_table} ${upnp_nat_chain}
+nft flush chain ip ${upnp_table} ${upnp_nat_postrouting_chain}
+nft flush chain inet ${upnp_table} ${upnp_forward_chain}
+nft flush chain ip6 ${upnp_table} ${upnp_nat_chain}
+nft flush chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain}
diff -rup miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_init.sh 
miniupnpd-2.2.1/netfilter_nft/scripts/nft_init.sh
--- miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_init.sh      2019-09-02 
02:02:26.000000000 +0300
+++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_init.sh   2021-09-20 
01:05:46.250264959 +0300
@@ -7,17 +7,38 @@
 
 #opts="--echo"
 
-echo "create nat table"
-nft ${opts} add table nat
-
-echo "create chain in nat table"
-nft ${opts} add chain nat MINIUPNPD
-
-echo "create pcp peer chain in nat table"
-nft ${opts} add chain nat MINIUPNPD-POSTROUTING
-
-echo "create filter table"
-nft ${opts} add table inet filter
-
-echo "create chain in filter table"
-nft ${opts} add chain inet filter MINIUPNPD
+# If you modify the corresponding settings in miniupnpd.conf,
+# change these variables in the scripts too.
+upnp_table=miniupnpd
+upnp_forward_chain=forward
+upnp_nat_chain=prerouting
+upnp_nat_postrouting_chain=postrouting
+
+echo "create ipv4 table"
+nft ${opts} add table ip ${upnp_table}
+
+echo "create nat chain in ipv4 table"
+nft ${opts} add chain ip ${upnp_table} ${upnp_nat_chain} \
+        "{ type nat hook prerouting priority dstnat; policy accept; }"
+
+echo "create pcp peer nat chain in ipv4 table"
+nft ${opts} add chain ip ${upnp_table} ${upnp_nat_postrouting_chain} \
+       "{ type nat hook postrouting priority srcnat; policy accept; }"
+
+echo "create ipv4/v6 table"
+nft ${opts} add table inet ${upnp_table}
+
+echo "create forward filter chain in ipv4/v6 table"
+nft ${opts} add chain inet ${upnp_table} ${upnp_forward_chain} \
+       "{ type filter hook forward priority -25; policy accept; }"
+
+echo "create ipv6 table"
+nft ${opts} add table ip6 ${upnp_table}
+
+echo "create nat chain in ipv6 table"
+nft ${opts} add chain ip6 ${upnp_table} ${upnp_nat_chain} \
+       "{ type nat hook prerouting priority dstnat; policy accept; }"
+
+echo "create ipv6 srcnat chain"
+nft ${opts} add chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain} \
+       "{ type nat hook postrouting priority srcnat; policy accept; }"
diff -rup miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_removeall.sh 
miniupnpd-2.2.1/netfilter_nft/scripts/nft_removeall.sh
--- miniupnpd-2.2.1/netfilter_nft/scripts.orig/nft_removeall.sh 2019-09-02 
02:02:26.000000000 +0300
+++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_removeall.sh      2021-09-20 
01:05:58.290180162 +0300
@@ -5,40 +5,69 @@
 # Do not disturb other existing structures in nftables, e.g. those created by 
firewalld
 #
 
-nft --check list table nat > /dev/null 2>&1
+# If you modify the corresponding settings in miniupnpd.conf,
+# change these variables in the scripts too.
+upnp_table=miniupnpd
+upnp_forward_chain=forward
+upnp_nat_chain=prerouting
+upnp_nat_postrouting_chain=postrouting
+
+nft --check list table ip ${upnp_table} > /dev/null 2>&1
 if [ $? -eq "0" ]; then
 {
-       # nat table exists, so first remove the chains we added
-       nft --check list chain nat MINIUPNPD > /dev/null 2>&1
+       # ipv4 table exists, so first remove the nat chains we added
+       nft --check list chain ip ${upnp_table} ${upnp_nat_chain} > /dev/null 
2>&1
        if [ $? -eq "0" ]; then
-               echo "Remove chain from nat table"
-               nft delete chain nat MINIUPNPD
+               echo "Remove prerouting nat chain from ipv4 table"
+               nft delete chain ip ${upnp_table} ${upnp_nat_chain}
        fi
 
-       nft --check list chain nat MINIUPNPD-POSTROUTING > /dev/null 2>&1
+       nft --check list chain ip ${upnp_table} ${upnp_nat_postrouting_chain} > 
/dev/null 2>&1
        if [ $? -eq "0" ]; then
-               echo "Remove pcp peer chain from nat table"
-               nft delete chain nat MINIUPNPD-POSTROUTING
+               echo "Remove pcp peer nat chain from ipv4 table"
+               nft delete chain ip ${upnp_table} ${upnp_nat_postrouting_chain}
        fi
 
        # then remove the table itself
-       echo "Remove nat table"
-       nft delete table nat
+       echo "Remove ipv4 table"
+       nft delete table ip ${upnp_table}
 }
 fi
 
-nft --check list table inet filter > /dev/null 2>&1
+nft --check list table inet ${upnp_table} > /dev/null 2>&1
 if [ $? -eq "0" ]; then
 {
-       # filter table exists, so first remove the chain we added
-       nft --check list chain inet filter MINIUPNPD > /dev/null 2>&1
+       # ipv4/v6 table exists, so first remove the filter chain we added
+       nft --check list chain inet ${upnp_table} ${upnp_forward_chain} > 
/dev/null 2>&1
        if [ $? -eq "0" ]; then
-               echo "Remove chain from filter table"
-               nft delete chain inet filter MINIUPNPD
+               echo "Remove filter chain from ipv4/v6 table"
+               nft delete chain inet ${upnp_table} ${upnp_forward_chain}
        fi
 
        # then remove the table itself
-       echo "Remove filter table"
-       nft delete table inet filter
+       echo "Remove ipv4/v6 table"
+       nft delete table inet ${upnp_table}
+}
+fi
+
+nft --check list table ip6 ${upnp_table} > /dev/null 2>&1
+if [ $? -eq "0" ]; then
+{
+        # ipv6 table exists, so first remove the nat chains we added
+        nft --check list chain ip6 ${upnp_table} ${upnp_nat_chain} > /dev/null 
2>&1
+        if [ $? -eq "0" ]; then
+                echo "Remove prerouting nat chain from ipv6 table"
+                nft delete chain ip6 ${upnp_table} ${upnp_nat_chain}
+        fi
+
+        nft --check list chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain} 
> /dev/null 2>&1
+        if [ $? -eq "0" ]; then
+                echo "Remove pcp peer nat chain from ipv6 table"
+                nft delete chain ip6 ${upnp_table} 
${upnp_nat_postrouting_chain}
+        fi
+
+        # then remove the table itself
+        echo "Remove ipv6 table"
+        nft delete table ip6 ${upnp_table}
 }
 fi

*** Reporter, please consider answering these questions, where appropriate ***

   * What led up to the situation?
   * What exactly did you do (or not do) that was effective (or
     ineffective)?
   * What was the outcome of this action?
   * What outcome did you expect instead?

*** End of the template - remove these template lines ***


-- System Information:
Debian Release: 11.0
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable-security'), (500, 'stable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 5.10.63-i3 (SMP w/2 CPU threads)
Kernel taint flags: TAINT_OOT_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=fi_FI.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages miniupnpd-nftables depends on:
ii  libc6       2.31-13
ii  libmnl0     1.0.4-3
ii  libnftnl11  1.1.9-1

miniupnpd-nftables recommends no packages.

miniupnpd-nftables suggests no packages.

-- Configuration Files:
/etc/miniupnpd/nft_delete_chain.sh changed:
upnp_table=miniupnpd
upnp_forward_chain=MINIUPNPD
upnp_nat_chain=MINIUPNPD
upnp_nat_postrouting_chain=MINIUPNPD-POSTROUTING
nft delete chain ip ${upnp_table} ${upnp_nat_chain}
nft delete chain ip ${upnp_table} ${upnp_nat_postrouting_chain}
nft delete chain inet ${upnp_table} ${upnp_forward_chain}
nft delete chain ip6 ${upnp_table} ${upnp_nat_chain}
nft delete chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain}

/etc/miniupnpd/nft_flush.sh changed:
upnp_table=miniupnpd
upnp_forward_chain=MINIUPNPD
upnp_nat_chain=MINIUPNPD
upnp_nat_postrouting_chain=MINIUPNPD-POSTROUTING
nft flush chain ip ${upnp_table} ${upnp_nat_chain}
nft flush chain ip ${upnp_table} ${upnp_nat_postrouting_chain}
nft flush chain inet ${upnp_table} ${upnp_forward_chain}
nft flush chain ip6 ${upnp_table} ${upnp_nat_chain}
nft flush chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain}

/etc/miniupnpd/nft_init.sh changed:
upnp_table=miniupnpd
upnp_forward_chain=MINIUPNPD
upnp_nat_chain=MINIUPNPD
upnp_nat_postrouting_chain=MINIUPNPD-POSTROUTING
echo "create IPv4 nat table"
nft ${opts} add table ip ${upnp_table}
echo "create chain in nat table"
nft ${opts} add chain ip ${upnp_table} ${upnp_nat_chain} \
    "{ type nat hook prerouting priority dstnat; policy accept; }"
echo "create pcp peer chain in nat table"
nft ${opts} add chain ip ${upnp_table} ${upnp_nat_postrouting_chain} \
    "{ type nat hook postrouting priority srcnat; policy accept; }"
echo "create IPv4/IPv6 filter table"
nft ${opts} add table inet ${upnp_table}
echo "create chain in filter table"
nft ${opts} add chain inet ${upnp_table} ${upnp_forward_chain} \
    "{ type filter hook forward priority -25; policy accept; }"
echo "create ip6 table"
nft ${opts} add table ip6 ${upnp_table}
echo "create IPv6 dstnat chain"
nft ${opts} add chain ip6 ${upnp_table} ${upnp_nat_chain} \
    "{ type nat hook prerouting priority dstnat; policy accept; }"
echo "create IPv6 srcnat chain"
nft ${opts} add chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain} \
    "{ type nat hook postrouting priority srcnat; policy accept; }"

/etc/miniupnpd/nft_removeall.sh changed:
upnp_table=miniupnpd
upnp_forward_chain=MINIUPNPD
upnp_nat_chain=MINIUPNPD
upnp_nat_postrouting_chain=MINIUPNPD-POSTROUTING
nft --check list table ip ${upnp_table} > /dev/null 2>&1
if [ $? -eq "0" ]; then
{
        # nat table exists, so first remove the chains we added
        nft --check list chain ip ${upnp_table} ${upnp_nat_chain} > /dev/null 
2>&1
        if [ $? -eq "0" ]; then
                echo "Remove chain from nat table"
                nft delete chain ip ${upnp_table} ${upnp_nat_chain}
        fi
        nft --check list chain ip ${upnp_table} ${upnp_nat_postrouting_chain} > 
/dev/null 2>&1
        if [ $? -eq "0" ]; then
                echo "Remove pcp peer chain from nat table"
                nft delete chain ip ${upnp_table} ${upnp_nat_postrouting_chain}
        fi
        # then remove the table itself
        echo "Remove nat table"
        nft delete table ip ${upnp_table}
}
fi
nft --check list table inet ${upnp_table} > /dev/null 2>&1
if [ $? -eq "0" ]; then
{
        # filter table exists, so first remove the chain we added
        nft --check list chain inet ${upnp_table} ${upnp_forward_chain} > 
/dev/null 2>&1
        if [ $? -eq "0" ]; then
                echo "Remove chain from filter table"
                nft delete chain inet ${upnp_table} ${upnp_forward_chain}
        fi
        # then remove the table itself
        echo "Remove filter table"
        nft delete table inet ${upnp_table}
}
fi
nft --check list table ip6 ${upnp_table} > /dev/null 2>&1
if [ $? -eq "0" ]; then
{
        # IPv6 NAT table exists, so first remove the chains we added
        nft --check list chain ip6 ${upnp_table} ${upnp_nat_chain} > /dev/null 
2>&1
        if [ $? -eq "0" ]; then
                echo "Remove chain from IPv6 nat table"
                nft delete chain ip6 ${upnp_table} ${upnp_nat_chain}
        fi
        nft --check list chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain} 
> /dev/null 2>&1
        if [ $? -eq "0" ]; then
                echo "Remove IPv6 pcp peer chain from nat table"
                nft delete chain ip6 ${upnp_table} ${upnp_nat_postrouting_chain}
        fi
        # then remove the table itself
        echo "Remove IPv6 nat table"
        nft delete table ip6 ${upnp_table}
}
fi


-- no debconf information

  • Bug#994726: miniupnpd-nftables scripts eat iptables-nft NAT ... Matti Kurkela

Reply via email to