UFW: разрешить трафик только из домена с динамическим IP-адресом

32

Я запускаю VPS, который я хотел бы защитить с помощью UFW, позволяя подключаться только к порту 80. Однако, чтобы иметь возможность управлять им удаленно, мне нужно оставить порт 22 открытым и сделать его доступным из дома.

Я знаю, что UFW можно настроить, чтобы разрешить подключения к порту только с определенного IP-адреса:

ufw allow proto tcp from 123.123.123.123 to any port 22

Но мой IP-адрес динамический, так что это еще не решение.

Вопрос в том, что у меня динамическое разрешение DNS с помощью DynDNS, так возможно ли создать правило, используя домен вместо IP?

Я уже попробовал это:

ufw allow proto tcp from mydomain.dyndns.org to any port 22

но я получил ERROR: Bad source address

Карлес Сала
источник

Ответы:

47

Я не верю, что это возможно с ufw. ufwэто всего лишь интерфейс, в iptablesкотором также отсутствует эта функция, поэтому одним из подходов будет создание записи в crontab, которая будет периодически запускаться и проверять, изменился ли IP-адрес. Если это так, он будет обновлять его.

У вас может возникнуть соблазн сделать это:

$ iptables -A INPUT -p tcp --src mydomain.dyndns.org --dport 22 -j ACCEPT

Но это преобразует имя хоста в IP и использует его для правила, поэтому, если IP позже изменится, это правило станет недействительным.

Альтернативная идея

Вы можете создать сценарий, так называемый 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

Источник: Использование IPTables с динамическими IP-именами хостов, такими как dyndns.org

С помощью этого сохраненного скрипта вы можете создать запись в crontab, например, в файле /etc/crontab:

*/5 * * * * root /etc/iptables_update.bash > /dev/null 2>&1

Эта запись будет запускать сценарий каждые 5 минут, проверяя, изменился ли IP-адрес, назначенный имени хоста. Если это так, то он создаст новое правило, разрешающее его, при этом удаляя старое правило для старого IP-адреса.

SLM
источник
2
Как глупо, что я не думал о разрешении имени хоста периодически. Я изменил ваш скрипт (добавил логирование и т. Д.), И он работает как шарм. Спасибо!
Карлес Сала
@CarlesSala - рад, что это решило вашу проблему. В дополнение к принятию вы также можете поднять 8-).
SLM
1
примечание: в Debian 7 мне пришлось изменить строку Current_IP=$(host $HOSTNAME | cut -f4 -d' ')наCurrent_IP=$(host $HOSTNAME | head -n1 | cut -f4 -d ' ')
Krystian
Смогу ли я увидеть это при использовании подробного статуса ufw? Я имею в виду, правила?
Фридо
@ Фридо не уверен, попробуйте и посмотрите, что получится.
SLM
8

Я знаю, что он старый, но я наткнулся на него и в итоге получил это решение, которое кажется еще лучше, потому что файл журнала не нужен, и очень легко добавлять дополнительные хосты по мере необходимости. Работает как шарм!

Источник: 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
Дом
источник
извини, я немного новичок Где мне нужно хранить этот скрипт и где я изменяю вещи, чтобы отразить мой конкретный случай?
Фридо
5

Основываясь на предыдущих ответах, я обновил следующий сценарий как bash, который работает на 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
Маттиас Петтерссон
источник
К этому можно даже добавить, чтобы cronон периодически запускался сам по себе.
Тим Кеннеди
Вот что я сделал;)
Маттиас Петтерссон
У этого скрипта есть небольшая проблема: при первом использовании, если вы забыли запустить от имени пользователя root, он создаст файл журнала, но не добавит правила. Затем, если вы снова запустите root, он просто скажет: «IP-адрес не изменился». Он должен запускаться с правами root с первого раза! Кроме того, было бы неплохо перейти LOGFILE=$HOME/ufw.logна одновременное выполнение LOGFILE=$HOME/ufw.$HOSTNAME.logнескольких сценариев
OCs Guerlando
@ GuerlandoOCs, как вы можете сбросить, если вы столкнулись с этой проблемой?
Мэтью
0

На основе всех ответов, прежде чем я их объединил. Лог-файл не требуется. Проверено на Ubuntu 18.04

#!/bin/bash
HOSTNAME=YOUR.DNS.NAME.HERE

if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root"
   exit 1
fi

new_ip=$(host $HOSTNAME | head -n1 | cut -f4 -d ' ')
old_ip=$(/usr/sbin/ufw status | grep $HOSTNAME | head -n1 | tr -s ' ' | cut -f3 -d ' ')

if [ "$new_ip" = "$old_ip" ] ; then
    echo IP address has not changed
else
    if [ -n "$old_ip" ] ; then
        /usr/sbin/ufw delete allow from $old_ip to any
    fi
    /usr/sbin/ufw allow from $new_ip to any comment $HOSTNAME
    echo iptables have been updated
fi

Вы можете добавить порт в правила с помощью параметра "port". например:

if [ -n "$old_ip" ] ; then
    /usr/sbin/ufw delete allow from $old_ip to any port 22
fi
/usr/sbin/ufw allow from $new_ip to any port 22 comment $HOSTNAME
Себастьян
источник