I just found back an old note about using iptables in combination with dyndns to open up access from a remote location. For instance, if you have a laptop that you take everywhere and you want to connect to your home or office. The script the other site suggested was broken, so let's write a new one.
Step 1: Create a new chain in the firewall
Create a new chain in the firewall where we can plug in the dynamic rules. On my Fedora machine, the firewall is located in /etc/sysconfig/iptables. I added the bold lines to this example.
*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
<b>:DYNAMICPARENT - [0:0]
-A INPUT -j DYNAMICPARENT</b>
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
Step 2: Write a script
#!/bin/bash HOSTNAME=myname.dyndns.org CHECK_INTERVAL=60 #once a minute IP="" #initialize $IP while [ true ]; do OIP=$IP IP=$(dig +short $HOSTNAME | grep -iE "^[0-9]+.[0-9]+.[0-9]+.[0-9]+$"|head -n 1) if [ "$OIP" != "$IP" -a "$IP" != "" ]; then echo "Changing ip to $IP" /sbin/iptables -N DYNAMICNEW # create new rule /sbin/iptables -I DYNAMICNEW -s $IP -j ACCEPT # allow new ip /sbin/iptables -I DYNAMICPARENT -j DYNAMICNEW # attach new rule to its parent while [ true ]; do # unlink old rule - if multiple exist, remove all /sbin/iptables -D DYNAMICPARENT -j DYNAMICCHILD 2>/dev/null || break done /sbin/iptables -F DYNAMICCHILD #flush all old rules /sbin/iptables -X DYNAMICCHILD #flush all old rules /sbin/iptables -E DYNAMICNEW DYNAMICCHILD #rename new to "current" fi sleep $CHECK_INTERVAL done |
In this case, the firewall accepts all traffic from $IP, but of course you could restrict it to 1 port. Also, I focussed on IPv4, but you could easily rewrite this script to IPv6 using ip6tables. I saved the file to /usr/local/bin/dynfirewall.sh
Step 3: Run the script
I'd prefer running the script from inittab, but since Fedora doesn't work like this anymore, I put the following line in /etc/rc.d/rc.local:
/usr/local/bin/dynfirewall.sh >>/var/log/dynfirewall 2>>/var/log/dynfirewall & |
Please don't forget the ampersand at the end to fork the script!!
Why is this script better than previous version?
- This script can handle cnames
- The old script used to delete old rules, before creating new ones. This one does not. Therefore, it will never leave a second where you cannot connect.