Using UPnP IGD for simpler port forwarding

If your router or ADSL modem supports the UPnP Internet Gateway Device protocol (and most of them do), you can forward ports to services on your network much more easily and more flexibly than through the admin interface.

I had to buy a new ADSL modem/wireless router this week, as my old one was no longer working properly: instead of the normal slightly disappointing 6Mbps I usually get here in ‘Digital Britain’, it was down to a few hundred kbps, with highly variable performance. I thought it might be the slightly swollen capacitor on the board, so I replaced that, but to no avail. Fortunately, you can now buy decent ADSL modem/wireless routers from the supermarket for not much money, so, whilst it did cost me £44, it was a fairly easy problem to solve. As a fringe benefit, I now have a much faster wireless network in my flat, so it’s not all bad.

My new router has all kinds of complex options on its management interface, but it’s much more limited than its predecessor in one respect: port forwarding. On the old one, I could forward arbitrarily many ports, and I could choose to map an external port to a different internal one—useful for slightly obfuscating SSH access without having to change the configuration of the internal network. On my new router, however, I can only forward ten distinct port ranges, and the external and internal ports must match. At least, that’s all I can do through the clunky and slow management interface. But it supports UPnP, and UPnP does allow mapping an external port to a different internal port.

Enter MiniUPnP, a project that provides a client and a daemon that implement the UPnP Internet Gateway Device specifications. We only need the client, which is available on Ubuntu in the miniupnpc package.

You can then forward a port as simply as:

upnpc -a 22 3333 TCP

This will forward TCP connections from the internet on port 3333 to port 22 on To remove it, use:

upnpc -d 3333 TCP

That’s a bit slow, though, as it has to discover the router every time. You can speed that up by supplying the root description URL. First, find it:

upnpc -l | grep desc:

Then supply it as the -u parameter every time you use upmpc, e.g.:

upnpc -u -l

The remaining step is to set up the connection automatically. As my server is configured via DHCP, I can make this happen every time it’s connected to the local network by putting an executable script in /etc/dhcp/dhclient-exit-hooks.d/ (I called mine upnp, but the name doesn’t really matter). I’ve chosen to use upnpc to tell me the local IP address of the server:

export LC_ALL=C

upnpc="upnpc -u"
ip=$($upnpc -l | grep "Local LAN ip address" | cut -d: -f2)

$upnpc -d $external TCP >/dev/null 2>&1
$upnpc -a $ip $port $external TCP >/dev/null 2>&1

Now, as soon as the server gets a DHCP lease, it will delete any existing port forwarding and forward port 3333 to its SSH server. The really nice thing is that the router doesn’t need to know about the server at all.


  1. Strawp

    Wrote at 2013-02-19 17:06 UTC using Chrome 24.0.1312.57 on Windows 7:

    Is no one else going to point out that UPnP is inherently insecure and should be disabled at the first opportunity?

    I like there being an admin password between the internet and ports being forwarded on my router.

    I like letting my guests having access to my wifi without worrying that they’ve shared all the files on my server to the internet accidentally.
  2. Paul Battley

    Wrote at 2013-02-20 14:27 UTC using Chrome 21.0.1180.89 on Linux:

    Strawp: I rather take the view that if you’re relying on NAT for security, you’re already at risk by allowing any unknown device onto your network. I’m also not quite sure how one would forward a port accidentally, as opposed to deliberately (in which case port forwarding is not the only vulnerability).

    I’m also confident that simply forwarding a port to my server would not share all my files to the wider internet. At worst, you might be able to watch some videos from XBMC, but I’m not really concerned about that.

    Are there other vulnerabilities of which I should be aware?
  3. Leonardo Taborda

    Wrote at 2013-12-26 18:52 UTC using Chrome 25.0.1364.160 on Linux:

    Thank you so much, quite useful. This is the only way I can open ports on my router. I called my telco many times and regardless they said the ports were open, I couldn’t access to my server. But now it works fine.