Whenever IPTables has a hostname in a rule it looks up the hostname’s IP address and uses that instead of the actual hostname – so it’s stuck with the IP until the next time IPTables is flushed/restarted. Here’s a quick little python script to stick in a crontab which checks the IP of your dynamic IP hostname (free ones provided by dyndns.org) and will restart iptables if it catches a change in your hostname. The script was made for CentOS so should work on Red Hat based distributions – if you don’t have an /etc/init.d/iptables file you’ll have to modify the reload iptables command in the source. Viewable Source After Jump
I just set this up as root and in root’s crontab.
Source:
#!/usr/bin/python import os def gettextoutput(cmd): """Return (status, output) of executing cmd in a shell.""" pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r') pipe = os.popen(cmd + ' 2>&1', 'r') text = pipe.read() if text[-1:] == '\n': text = text[:-1] return text home_dyndns = "example.dyndns.org" log_dyndns = "./new_home_ip_check.log" last_dyndns = gettextoutput("cat " + log_dyndns) cur_dyndns = gettextoutput("host " + home_dyndns) print "Log: "+ last_dyndns print "Cur: "+ cur_dyndns if last_dyndns == cur_dyndns: print "IPs match, no restart necessary" else: print "Updating last IP with current" os.system("echo '" + cur_dyndns + "' > " + log_dyndns) print "Restarting iptables to update" os.system("/etc/init.d/iptables restart") |
Output looks like:
Log: example.dyndns.org has address 114.76.37.112 Cur: example.dyndns.org has address 114.76.37.112 IPs match, no restart necessary Log: example.dyndns.org has address 114.76.37.113 Cur: example.dyndns.org has address 114.76.37.112 Updating last IP with current Restarting iptables to update Flushing firewall rules: [ OK ] Setting chains to policy ACCEPT: filter [ OK ] Unloading iptables modules: [ OK ] Applying iptables firewall rules: [ OK ] Loading additional iptables modules: ip_conntrack_netbios_n[ OK ] |
Thanks, EXACTLY what I needed!
Glad I could help.
I have this script working except when it restarts the iptables the ip address that gets listed in my iptables doesn’t change. I’m adding the host to my iptables using
iptables -I INPUT -i eth1 -s hostname -j ACCEPT
if I check my iptables with
iptables -L -n
I get the rule and it has substituted the current IP address for the host name. and everything works. but if the IP for the host name changes this script detects it and restarts the iptables but the IP address listed doing an iptables -L -n doesn’t change. I’m pretty new to the whole IP tables so maybe I’m doing it wrong? any ideas? thanks
So I couldn’t get the dns name in the IP tables to work so I took your idea and wrtoe a bash script that looks up the host name adds it to the iptables and if the IP changes removes the old rule and adds a new one for the new ip.
#!/bin/bash#allow a dyndns name
HOSTNAME=HOST_NAME_HERE
LOGFILE=LOGFILE_NAME_HERE
Current_IP=$(host $HOSTNAME | cut -f4 -d' ')
if [ $LOGFILE = "" ] ; then
iptables -I INPUT -i eth1 -s $Current_IP -j ACCEPT
echo $Current_IP > $LOGFILE
else
Old_IP=$(cat $LOGFILE)
if [ "$Current_IP" = "$Old_IP" ] ; then
echo IP address has not changed
else
iptables -D INPUT -i eth1 -s $Old_IP -j ACCEPT
iptables -I INPUT -i eth1 -s $Current_IP -j ACCEPT
echo $Current_IP > $LOGFILE
echo iptables have been updated
fi
fi
then just add this line to your crontab and it will check every 5 mins and keep your iptables up-to-date.
*/5 * * * * /root/NAME_OF_SCRIPT.sh > /dev/null 2>&1
Nice work.
What flavor of linux are you running? If you didn’t have an iptables init.d script, that might have been the problem. does /etc/init.d/iptables exist?
I see you’ve already come up with a work around though – I went ahead and edited the articles to add a note about the iptables reload command being Red Hat based and needing to probably be modified for other system types.