Fedora firewall with UPnP

firewallfirewalldupnp

I'm using Fedora 15 and Transmission BT client. Transmission can't open ports unless the firewall is disabled.

I searched some posts that said add 1900 to the trusted ports, or via a iptable rule: -A INPUT -m state --state NEW -m udp -p udp --sport 1900 -j ACCEPT". However, Transmission can't open ports anyway.

I also tested with upnp-inspector, which is better than Transmission, it could detect my upnp router after add 1900 to the trusted ports, but the detection is slower than if the firewall is disabled.

Any ideas on how to let Transmission UPnP works with the Firewall?

Best Answer

First thing you need to know is how UPnP IGD protocol is working. You choose random local UDP port and from it you send discovery request to well-known multicast address 239.255.255.250 and UDP port 1900. UPnP IGD server (running on your router) listen for those multicast queries and send you back unicast UDP reply from randomly chosen port to your ip address and port from which discovery request was sent. But such reply is not paired by conntrack iptables module to your sent request so, received reply is dropped by iptables. This is why enabling all UDP ports or disabling firewall helped. In that UDP reply is location of your UPnP IGD server and client then establish classic TCP connection with UPnP IGD server. So the only problem is how to write a rule for receiving UDP reply to that multicast discovery request.

Via ipset it is possible. I described it in answer at https://serverfault.com/a/911286:

$ ipset create upnp hash:ip,port timeout 3
$ iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j SET --add-set upnp src,src --exist
$ iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT

In IPv6 are UPnP packets sent to multicast address ff02::c or ff05::c. So rules would look like:

$ ipset create upnp6 hash:ip,port timeout 3 family inet6
$ ip6tables -A OUTPUT -d ff02::c/128 -p udp -m udp --dport 1900 -j SET --add-set upnp6 src,src --exist
$ ip6tables -A OUTPUT -d ff05::c/128 -p udp -m udp --dport 1900 -j SET --add-set upnp6 src,src --exist
$ ip6tables -A INPUT -p udp -m set --match-set upnp6 dst,dst -j ACCEPT

Some UPnP servers (but not all) periodically (e.g. every 30s) announce theirself via multicast UDP packet to well-known address/port. If you have such server and also client which is listening for these multicast packets, then iptables rule very is simple:

$ iptables -A INPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j ACCEPT

And equivalent for IPv6:

$ ip6tables -A INPUT -d ff02::c/128 -p udp -m udp --dport 1900 -j ACCEPT
$ ip6tables -A INPUT -d ff05::c/128 -p udp -m udp --dport 1900 -j ACCEPT

In your question you described something similar to above iptables rule, but you have did one big mistake: You specified source port, instead of destination: --sport 1900. UPnP UDP packets are sent from random source ports to fixed destination port 1900.

You also described that upnp-inspector can detect your UPnP IGD router after you added port 1900 to trusted (probably both source and destination), but it was slower as disabling firewall. This perfectly matches above description of periodic announcement as upnp-inspector was waiting when your router send next announce packet.

Related Question