Allow Dynamic IP Through Firewall

In my server set up, I want to be able to access it remotely, for backups and also random maintenance without physically having to be there. I already have layers of security with authentication keys and regular firewalls, but that can be a problem when the user is behind a dynamic IP address.

So in that case, I found the solution at this site to periodically run an update to the firewall that would allow port 22 (SSH) to come in, from only the specified remote IP addresses.

Here’s the info from that site, just in case it ever disappears:

    • The shell script to check the ip address for the host and update the ufw rules:
#!/bin/bash
 
HOSTS_ALLOW=/etc/ufw-dynamic-hosts.allow
IPS_ALLOW=/var/tmp/ufw-dynamic-ips.allow
 
add_rule() {
  local proto=$1
  local port=$2
  local ip=$3
  local regex='${port}\/${proto}.*ALLOW.*IN.*${ip}'
  local rule=$(ufw status numbered | grep $regex)
  if [ -z '$rule' ]; then
      ufw allow proto ${proto} from ${ip} to any port ${port}
  else
      echo 'rule already exists. nothing to do.'
  fi
}
 
delete_rule() {
  local proto=$1
  local port=$2
  local ip=$3
  local regex='${port}\/${proto}.*ALLOW.*IN.*${ip}'
  local rule=$(ufw status numbered | grep $regex)
  if [ -n '$rule' ]; then
      ufw delete allow proto ${proto} from ${ip} to any port ${port}
  else
      echo 'rule does not exist. nothing to do.'
  fi
}
 
 
sed '/^[[:space:]]*$/d' ${HOSTS_ALLOW} | sed '/^[[:space:]]*#/d' | while read line
do
    proto=$(echo ${line} | cut -d: -f1)
    port=$(echo ${line} | cut -d: -f2)
    host=$(echo ${line} | cut -d: -f3)
 
    if [ -f ${IPS_ALLOW} ]; then
      old_ip=$(cat ${IPS_ALLOW} | grep ${host} | cut -d: -f2)
    fi
 
    ip=$(dig +short $host | tail -n 1)
 
    if [ -z ${ip} ]; then
        if [ -n '${old_ip}' ]; then
            delete_rule $proto $port $old_ip
        fi
        echo 'Failed to resolve the ip address of ${host}.' 1>&2
        exit 1
    fi
 
    if [ -n '${old_ip}' ]; then
        if [ ${ip} != ${old_ip} ]; then
            delete_rule $proto $port $old_ip
        fi
    fi
    add_rule $proto $port $ip
    if [ -f ${IPS_ALLOW} ]; then
      sed -i.bak /^${host}*/d ${IPS_ALLOW}
    fi
    echo '${host}:${ip}' >> ${IPS_ALLOW}
done

(The script above needs to be saved to /usr/local/sbin/ufw-dynamic-host-update in order to match the calling code from the crontab entry listed below. Both could be changed to something else if necessary.)

    • The sample hosts file: /etc/ufw-dynamic-hosts.allow:
tcp:22:yourpc.no-ip.org
    • The crontab which executes the script every 5 minutes to update the rules:
# m h  dom mon dow   command
*/5 * * * * /usr/local/sbin/ufw-dynamic-host-update  2>&1 > /dev/null

Then at the end of all of that, you need to enable UFW, if you don’t already have it running. (On my systems at least, it was not running by default.)

sudo ufw enable

Then once it’s running, you can check the status of the firewall and what it’s set to with this:

sudo ufw status

But don’t worry that you see an IP address. The code is meant to figure out the numbers behind a dynamic IP address, so it just shows that it worked as it was supposed to. (Hopefully. Without double-checking there’s no way to tell that it’s actually set to the proper IP address.)

Leave a Reply