miniupnp: Miniupnpd + nftables does not seem to work properly
Ever since I switched to nftables, I have been unable to get miniupnpnd to work. I have been running it for years before without issues using iptables / netfilter.
- Distro: Gentoo Linux
- Kernel: Linux 4.19.66-gentoo
- miniupnpd version: 2.1.20190902
- two nics:
- enp2s0 is LAN
- eno0 is WAN
The base ruleset I have configured is as follows:
table ip filter {
chain input {
type filter hook input priority 0; policy accept;
ct state established,related accept
ip protocol icmp counter packets 146 bytes 17104 drop
tcp dport { ssh, http, https } ct state new counter packets 74 bytes 3944 accept
iifname "lo" accept
iifname "enp2s0" counter packets 3792 bytes 1012502 accept
iifname "eno0" counter packets 996 bytes 93929 drop
drop
}
chain output {
type filter hook output priority 100; policy accept;
}
chain forward {
type filter hook forward priority 0; policy drop;
iifname "enp2s0" oifname "eno0" accept
iifname "eno0" oifname "enp2s0" ct state established,related accept
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname "eno0" masquerade random,persistent
}
}
When I start miniupnpd, the ruleset becomes as follows as the miniupnpd tables and chains are being added:
table ip filter {
chain input {
type filter hook input priority 0; policy accept;
ct state established,related accept
ip protocol icmp counter packets 147 bytes 17188 drop
tcp dport { ssh, http, https } ct state new counter packets 82 bytes 4364 accept
iifname "lo" accept
iifname "enp2s0" counter packets 3980 bytes 1058250 accept
iifname "eno0" counter packets 1017 bytes 95803 drop
drop
}
chain output {
type filter hook output priority 100; policy accept;
}
chain forward {
type filter hook forward priority 0; policy drop;
iifname "enp2s0" oifname "eno0" accept
iifname "eno0" oifname "enp2s0" ct state established,related accept
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname "eno0" masquerade random,persistent
}
chain MINIUPNPD {
}
chain MINIUPNPD-POSTROUTING {
}
}
table inet filter {
chain MINIUPNPD {
}
}
So far so good. However, when I run a service on the LAN that tries to open a port, it either does not get added to the chains, or it does get added but the app always says the port it not open to the outside world.
For example, when I start Transmission while debugging (miniupnpd -d -f miniupnpd.conf), I regularly see the following line:
miniupnpd[24596]: rule with label 'Transmission at 53732' is not a IGD pinhole
The two TCP and UDP rules have now indeed been added:
add rule ip nat MINIUPNPD iif "eno0" tcp dport 53732 dnat to 192.168.2.10: 53732
# new generation 557 by process 24914 (miniupnpd)
add rule inet filter MINIUPNPD iif "eno0" @th,16,16 53732 @nh,128,32 3232236052 @nh,72,8 6 accept
# new generation 558 by process 24914 (miniupnpd)
table ip nat {
...
chain MINIUPNPD {
iif "eno0" tcp dport 53732 dnat to 192.168.2.10:53732
iif "eno0" udp dport 53732 dnat to 192.168.2.10:53732
}
chain MINIUPNPD-POSTROUTING {
}
}
table inet filter {
chain MINIUPNPD {
iif "eno0" @th,16,16 53732 @nh,128,32 3232236052 @nh,72,8 6 accept
iif "eno0" @th,16,16 53732 @nh,128,32 3232236052 @nh,72,8 17 accept
}
}
However, Transmission will will keep saying the port is closed:

I have similar issues with Plex Media Server:
add rule ip nat MINIUPNPD iif "eno0" tcp dport 23945 dnat to 192.168.2.10:32400
# new generation 604 by process 26870 (miniupnpd)
add rule inet filter MINIUPNPD iif "eno0" @th,16,16 32400 @nh,128,32 3232236042 @nh,72,8 6 accept
# new generation 605 by process 26870 (miniupnpd)
However, miniupnpd -d -f miniupnpd.conf shows several occurrences:
rule with label 'Plex Media Server' is not a IGD pinhole

An observation is that the MINIUPNPD-POSTROUTING chain is always empty?
Do you have any clue why the services are not accessible? I’m not sure what an IGD pinhole exactly is? Might my initial configuration have something invalid in there, dropping the packets?
Any help is appreciated 😃
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 32 (21 by maintainers)
Commits related to this issue
- Rework nft_removeall.sh to preserve nftables structures miniupnpd didn't add. Important for firewalld and sshguard co-existance. — committed to miniupnp/miniupnp by paul-chambers 5 years ago
should be fixed by @paul-chambers work
Thanks, @4np. Glad those changes fixed the issue, since I didn’t know how I was going to diagnose a problem I couldn’t reproduce. Sounds like I can submit a pull request with a clear conscience 😃
I’ve been testing with NoMachine, Plex Media Server and Zerotier One, on a firewall machine also running firewalld and sshguard with their respective nftables backends.
Yes, that’s the order I’d expect. Strange…
What happens if you do:
I’ll play around with transmission later, after my day job 😃
hmm… I suspect changing your default policy is letting packets through from the filter/forward chain to allow miniupnpd/forward chain to process them too. If they are both the same priority, I doubt there’s a guarantee what order the two chains will be processed in, and if one is default drop, well, the other never gets to see it.
The convention appears to be for all filter chains to be priority 0. I would suggest you leave your forward/filter chain at priority 0 and change the policy to accept, and define another forward chain with a default drop policy, with a decreased priority (e.g. +25) so that all forward/filter chains at priority 0 will see the packets, and and the default drop policy will only apply if no chains at the default filter priority (NF_IP_PRI_FILTER, i.e. zero) handle the packet. Could you give that a try?
I’ve increased the priority of miniupnpd’s forward chain (i.e. making it more negative) to guarantee that it runs before your filter/forward chain. If you would be so kind as to pull and build again, and let me know? thank you
@4np Jeroen, I have something that seems to work, would you like to give it a try?
https://github.com/paul-chambers/miniupnp branch ‘nftables’
I’d like to make sure someone else can replicate my results before submitting the pull request to @miniupnp/Thomas. It’s not a small patch.
You’re right, of course. But where’s the fun in that? 😉
I’m only beginning to get into the code, but already suspect I’ll be making a structural change or two. For one thing, I would like to implement some privilege separation between the front end (UPnP server) and back end (iptables, nftables, etc. support).
The back end has to run with root privileges (or at least CAP_NET_ADMIN) to be able to update the rules, but running userspace code that receives and processes network packets with root privileges makes me a little nervous. Not that the UPnP protocol is exactly a paragon of security, but still…
I’m currently thinking that the classic pipe()/fork() approach and dropping privileges on one of the two processes may be both simple and secure enough. It would also help impose a cleaner boundary between the two, rarely a bad thing.
p.s. I’m also looking to enable remote access to my Plex Media Server 😃
It doesn’t work for me, either. I’m hoping to work on it as my time allows, if no-one else has the bandwidth. It may take me a while, though, spare time is scarce.
I think it would be better to create a separate
tableforminiupnpd, to keep everything related tominiupnpdseparate. Something like this:Something like this:
Unfortunately I have been unable to get this to work. It looks like
nftablesdoes not accept the traffic to32400, even though it is processing theminiupnpdtable. Tracing showscontinuebut notaccept(tcp dport 32400 nftrace set 1).