1

How can I setup UFW (Uncomplicated Firewall) to add rules for specific hosts? Eg. I want to allow SSH only from yourpc.no-ip.org?

4

I found a very useful script that creates rules dynamically for specific hosts in this blog. The script needs to be run with cron, so it can lookup a hostname and add/delete rules in case the IP changed.

#!/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 content of /etc/ufw-dynamic-hosts.allow could look like this:

tcp:22:yourpc.no-ip.org

and a crontab entry for executing the script every five minutes could look like this:

*/5 * * * * /usr/local/sbin/ufw-dynamic-host-update > /dev/null
|improve this answer|||||
  • +1 -- In my case, i use 'ufw status' instead 'ufw status numbered' in line 12 because of some "bad variable name" error in some cases. Also on root crontab i forced to use 'sudo sh /usr/local/sbin/ufw-dynamic-host-update > /dev/null'. For debugging you should make it to point in a file like 'sudo sh /usr/local/sbin/ufw-dynamic-host-update >> /etc/ufw-custom-log'. – giannis.epp Oct 8 '15 at 12:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.