Back to Silas S. Brown's home page

UPnP router command-line control scripts

These scripts allow a UPnP-based home router to be controlled programmatically from a Unix or Linux box. They were tested on a "Sky Hub" in 2016/17 but usual disclaimers apply.

(If you have an older router with the widely-reported security problem of leaving its UPnP port open to the outside, I'd rather you switch off and don't use UPnP. Thankfully such older routers usually provide a non-UPnP means of route configuration like the VMDG280. Services like GRC ShieldsUp might be able to show if your older router is incorrectly handling UPnP security. But some newer routers are configurable only via UPnP, and do handle its security correctly---the scripts on this page can be useful for those.)

Installation: Make sure you have Python and the miniupnpc library (sudo pip install miniupnpc or apt-get install python-miniupnpc). Unpack upnp.tgz into /usr/local/bin or wherever.

upnp-add-port (PortNum)
Add a simple port-forwarding rule to forward incoming port PortNum (1 through 65535) to the machine running this command. PortNum may optionally be followed by a different port number to use on the machine itself, for example if you want to reduce probing by using a non-standard external port while keeping the standard port on your network.
  • But many ISP-supplied routers will not apply UPnP forwarding rules to packets originating from inside your network even if addressed to your external IPv4 address, so to use your server from home you might still need to use its internal IP (you might want to edit the hosts files of your local machines).
  • Routers that lack non-UPnP forwarding options will often still allow you to specify a ``DMZ'' machine and have this respond to your external IPv4 address even for connections coming from inside your network (such as WiFi-connected mobile devices where it's difficult to edit the hosts file).
  • DMZ however will expose all ports (except ones directed elsewhere), so you'll have to do your own iptables work on the Linux box---my suggested starting point is:
    iptables -A INPUT ! -i lo+ -p tcp --syn ! -s 192.168.0.0/16 ! --dport 80 -j DROP
    (remember to add it to startup scripts before ifup; the package iptables-persistent might help, or if all your local-only servers are run from inetd you can try putting commands in /etc/default/openbsd-inetd)
upnp-date
Shows the current date and time from the router (via HTTP)
  • Some ISP-supplied routers are 'hardwired' to use that ISP's internal NTP servers at startup, so the router might get stuck in 1970 if you use it with a different ISP.
upnp-delete-port (PortNum)
Delete a port-forwarding rule, specified by external port. The deletion takes effect only for new connections; existing connections to the port (e.g. open SSH sessions) are not affected.
  • So for example if you run a Web server which you only occasionally SSH into, you can reduce the level of SSH probing by keeping the port closed until you need it, open it via a CGI script and close it again from your login script. If you do this via router configuration then the scripts don't need any special privileges on the server itself. If using the DMZ approach above, you'll instead need 'sudo'-enabled scripts (or 'suid' scripts in a protected directory) that do the iptables -I and -D.
upnp-ip-address
Shows the router's current external IP address
upnp-ports
Shows the port forwarding table in a simple textual format
upnp-uptime
Shows the uptime of the router
Routers might or might not persist the port-forwarding rules across a power cycle. For best results you might need to arrange for them to be re-done.
All material © Silas S. Brown unless otherwise stated.