Control Your Router’s Port Forwards Programatically

If you have a DD-WRT router (or perhaps another router with custom firmware [1]), this is for you.

I don’t like having any more ports open to the internet than absolutely needed, because … well, for the same reason you don’t leave all your doors wide open all the time. However, sometimes programs actually do require being able to reach a computer inside your LAN from the wider internet – things like remote media access, a temporary web server, or a game server you’re hosting when playing the game with some friends.

With good routers, you can selectively open those ports and direct them to a specific computer on the inside. Which is better than opening up everything, yes. But you still don’t want to leave them open any longer than you need to.

Port Forwarding: Certain applications may require to open specific ports in order for it to function correctly. Examples of these applications include servers and certain online games. When a request for a certain port comes in from the Internet, the router will route the data to the computer you specify. Due to security concerns, you may want to limit port forwarding to only those ports you are using, and uncheck the Enable checkbox after you are finished.
Screenshot (with blacked out areas) of the port forward screen on a router I administer.

Using your router’s GUI works – in the screenshot above, you can check or uncheck the “enabled” box to turn that port forwarding rule on and off.

I often forget to uncheck that box after I’m done. ?

So when my ankle pain woke me up super early this morning, I decided to tackle the problem. The result is portforwards.sh, which is in my ddwrt-who-is-connected repository.

It uses iptables on the router to modify the port forwarding rules. Not only does it make it easier to have a more secure home network, but it also saves you from having to research how to do this. Every resource I found out there quickly went super technical and I couldn’t find anyplace where they put all these bits together at all, let alone in an easy-to-use way. I tried to ensure it was also well-commented so that if you need/want to tweak the script itself (or learn how it works) you can do so.

If you want to REMOVE a port forward, you invoke it like this:

ssh -q [ROUTER IP] 'sh -s' < ./portforwards.sh DEL [PORT]

That will remove all port forwards for that port, closing that port to the internet.

And if you want to ADD a port forward, you invoke it like this:

ssh -q [ROUTER IP] 'sh -s' < ./portforwards.sh [ADD|DEL] [PORT NUMBER] [PROTOCOL] [DEST IP]

Which is still a lot, I know, but it’s already a lot simpler than it used to be. It’s really designed to be called in a script that launches the server that needs the port, or to be triggered by (say) ddwrt-who-is-connected to open or close a port on demand.

As an example, here is a start.sh used to open the ports for a Minecraft server that is located on a machine with the LAN IP address of 192.168.1.324, with the router existing at 192.168.1.1, and then close the ports when the server goes down.

#!/usr/bin/env bash

ssh -q 192.168.1.1 'sh -s' < ./portforwards.sh ADD 25565 BOTH 192.168.1.324 

java -jar -Xms2048m -Xmx2048m -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M fabric-server-launch.jar nogui

ssh -q 192.168.1.1 'sh -s' < ./portforwards.sh DEL 25565

PLEASE NOTE that this example assumes that portforwards.sh is in the same directory; replace ./portforwards.sh with the full path to the file otherwise. 25565 is the default port for Minecraft servers.

Also, the rules portforwards.sh do not show up in the GUI, and do not persist across rebooting the router. The first is due to the way DD-WRT reads/updates the GUI, and the latter is intentional. This program is explicitly intended to be used for a temporary port forward.

You can find portforwards.sh in the ddwrt-who-is-connected repository on GitHub, GitLab, or my personal Git repository.

Featured Photo by FLY:D on Unsplash

[1] Requires busybox, passwordless SSH, awk, grep, and uses iptables for network routing. Tested on recent builds of DD-WRT; if you get it to work on another variety of custom firmware, I’m interested in hearing about it!