DynDNS with iptables

I wanted to use a DynDNS address with iptables. Obviously, you need a way to update the iptables rules when the IP of the dyndns address changes. Easiest solution is to cron a script that updates iptables when the IP changes. Here is one such script:

#!/bin/bash
#
# Auth: Ryan Bowlby
# Desc: Verify DynDNS address is listed in iptables. Logs to
#       /var/log/secure on most Linux systems. Check syslog.conf
#       to see where authpriv.notice is logged.
#
# FYI:  Before first use add dummy rule to iptables ruleset (save it).
#       ( i.e. /sbin/iptables -I INPUT 2 -s 127.0.0.1 -j ACCEPT )

dynDomain="YOUR.DYNDNS.ADDR"
dynIP=$(/usr/bin/dig +short $dynDomain) 

# verify dynIP resembles an IP
if ! echo -n $dynIP | grep -Eq "[0-9.]+"; then
    /bin/logger -p authpriv.notice -t $(/bin/basename $0)\
    "Error: $dynDomain is not a valid IP (\"${dynIP}\")"
    exit 1
fi

# if dynIP has changed
if ! /sbin/iptables -nL | /bin/grep -q "$dynIP"; then
    /sbin/iptables -I INPUT 2 -s $dynIP -m tcp -p tcp --dport 22 -j ACCEPT &&\
    /sbin/iptables -D INPUT 3  # Old dynIP deletion, use file if you hate simple.
    /bin/logger -p authpriv.notice -t $(/bin/basename $0) "$dynDomain updated to $dynIP"
fi

This assumes you are using a pretty basic set of rules. The script adds the dyndns rule as the second rule in the INPUT chain. What was previously the second rule is now the third, which the script will remove. So you can think of it as a replace or edit of the second rule. Make sure that the iptables file that’s loaded on startup has a dummy line as the second rule. That way when this script runs it will replace the dummy rule with a real dyndns rule.

I have a pretty basic set of rules that I’m not afraid to paste here. It’s just the moat, and security through obscurity only works against bots. Unlike most people who place a reject or drop line at the end of their ruleset, I use a default DROP policy on the INPUT chain. The only thing to watch out for when using a default policy of DROP is that you can’t be careless in the use of iptables -F. After a flush of the ruleset the policy will still be DROP and ALL! traffic would then be dropped. Just stop iptables where you would normally flush.

# cat /etc/sysconfig/iptables
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

-A INPUT -d IP.ADDR -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -s 127.0.0.1 -j ACCEPT #Dummy Rule
-A INPUT -d IP.ADDR -m tcp -p tcp --dport 21 -m state --state NEW \
-m limit --limit 2/min --limit-burst 2 -j ACCEPT
-A INPUT -d IP.ADDR  -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -i lo -j ACCEPT 

COMMIT


One Response to “DynDNS with iptables”

  1. Mark Ruys says:

    Thanks for your script. I made a few modifications which perhaps others might find handy.

    #!/bin/bash
    #
    # Auth: Ryan Bowlby
    # Modifications: Mark Ruys (2010-02-05)
    #
    # Desc: Verify DynDNS address is listed in iptables. Logs to
    # /var/log/secure on most Linux systems. Check syslog.conf
    # to see where authpriv.notice is logged.
    #
    # FYI: Before first use add dummy rule to iptables ruleset (save it).
    # This must be the but last line of the chain (typically just before the REJECT).

    dynDomain="YOUR.DYNDNS.ADDR"
    chain="INPUT"

    rulenr=$(/sbin/iptables -nL $chain |
    /bin/awk '/^[A-Z]+[[:space:]]/ { nlines++ } END { print nlines - 1 }')
    dynIP=$(/usr/bin/dig +short $dynDomain)
    name=$(/bin/basename $0)

    # verify dynIP resembles an IP
    if ! echo -n $dynIP | /bin/grep -Eq "^[0-9]+(\.[0-9]+){3}$"; then
    /bin/logger -p authpriv.notice -t $name "Error: $dynDomain is not a valid IP (\"$dynIP\")"
    exit 1
    fi

    # verify we found a valid rule number
    if [ -z "$rulenr" ]; then
    /bin/logger -p authpriv.notice -t $name "Error: could not determine rule number to replace"
    exit 1
    fi
    if [ $rulenr -le 0 ]; then
    /bin/logger -p authpriv.notice -t $name "Error: bad rule number $rulenr"
    exit 1
    fi

    # if dynIP has changed
    if ! /sbin/iptables -nL $chain | /bin/grep -q "$dynIP"; then
    /sbin/iptables -R $chain $rulenr -s $dynIP -m tcp -p tcp --dport 22 -j ACCEPT
    /bin/logger -p authpriv.notice -t $name "$dynDomain updated to $dynIP"
    fi

Leave a Reply