UFW: Allow traffic only from a domain with dynamic IP address
I don't believe this is possible with ufw
. ufw
is just a frontend to iptables
which also lacks this feature, so one approach would be to create a crontab entry which would periodically run and check if the IP address has changed. If it has then it will update it.
You might be tempted to do this:
$ iptables -A INPUT -p tcp --src mydomain.dyndns.org --dport 22 -j ACCEPT
But this will resolve the hostname to an IP and use that for the rule, so if the IP later changes this rule will become invalid.
Alternative idea
You could create a script like so, called, iptables_update.bash
.
#!/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
/etc/init.d/iptables save
echo $Current_IP > $LOGFILE
echo iptables have been updated
fi
fi
source: Using IPTables with Dynamic IP hostnames like dyndns.org
With this script saved you could create a crontab entry like so in the file /etc/crontab
:
*/5 * * * * root /etc/iptables_update.bash > /dev/null 2>&1
This entry would then run the script every 5 minutes, checking to see if the IP address assigned to the hostname has changed. If so then it will create a new rule allowing it, while deleting the old rule for the old IP address.
I know this is old but I ran across it and ended up with this solution in the end which seems even better because no log file is needed and it very easy to add additional hosts as needed. Works like a charm!
Source: http://rdstash.blogspot.ch/2013/09/allow-host-with-dynamic-ip-through.html
#!/bin/bash
DYNHOST=$1
DYNHOST=${DYNHOST:0:28}
DYNIP=$(host $DYNHOST | grep -iE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" |cut -f4 -d' '|head -n 1)
# Exit if invalid IP address is returned
case $DYNIP in
0.0.0.0 )
exit 1 ;;
255.255.255.255 )
exit 1 ;;
esac
# Exit if IP address not in proper format
if ! [[ $DYNIP =~ (([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) ]]; then
exit 1
fi
# If chain for remote doesn't exist, create it
if ! /sbin/iptables -L $DYNHOST -n >/dev/null 2>&1 ; then
/sbin/iptables -N $DYNHOST >/dev/null 2>&1
fi
# Check IP address to see if the chain matches first; skip rest of script if update is not needed
if ! /sbin/iptables -n -L $DYNHOST | grep -iE " $DYNIP " >/dev/null 2>&1 ; then
# Flush old rules, and add new
/sbin/iptables -F $DYNHOST >/dev/null 2>&1
/sbin/iptables -I $DYNHOST -s $DYNIP -j ACCEPT
# Add chain to INPUT filter if it doesn't exist
if ! /sbin/iptables -C INPUT -t filter -j $DYNHOST >/dev/null 2>&1 ; then
/sbin/iptables -t filter -I INPUT -j $DYNHOST
fi
fi
Based on previous answers I updated the following as bash script that works on Debian Jessie
#!/bin/bash
HOSTNAME=dynamichost.domain.com
LOGFILE=$HOME/ufw.log
Current_IP=$(host $HOSTNAME | head -n1 | cut -f4 -d ' ')
if [ ! -f $LOGFILE ]; then
/usr/sbin/ufw allow from $Current_IP to any port 22 proto tcp
echo $Current_IP > $LOGFILE
else
Old_IP=$(cat $LOGFILE)
if [ "$Current_IP" = "$Old_IP" ] ; then
echo IP address has not changed
else
/usr/sbin/ufw delete allow from $Old_IP to any port 22 proto tcp
/usr/sbin/ufw allow from $Current_IP to any port 22 proto tcp
echo $Current_IP > $LOGFILE
echo iptables have been updated
fi
fi