Блокируем внешний Интернет при подключении к внутреннему серверу

Возникла необычная творческая задача, после решения которой я подумал, что мой опыт может пригодиться кому-то ещё.

Задача следующая: в сети имеется RDP-сервер (10.0.0.10), к которому подключаются клиенты. Так же на этих клиентах имеется доступ в Интернет. Требуется сделать так, чтобы при подключении к серверу RDP, доступа в Интернет у клиентов уже не было. А при отключении от RDP-сервера, доступ появлялся обратно. То есть работало одновременно только что-то одно.

Я, конечно, не очень люблю вмешиваться в сетевые пакеты. Работает NAT да и ладно, но в некоторых случаях приходится изворачиваться, чтобы пропустить какой-нибудь капризный сервис внутрь/наружу. Пока ещё не сталкивались с неприятными моментами в CryptoPro, а ведь некоторыем компьютерщикам приходится “разруливать” и такие: Проблема Джакарты вещи.

Моё решение не претендует на медаль, конечно, возможно я впоследствии его улучшу (надеюсь), но выполнено это было следующим образом:

  1. Настройка DNAT на шлюзе Интернета:
    /sbin/iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 13389 -j DNAT --to-destination 10.0.0.10:3389
    Это правило изменит IP назначения пакета, пришедшего на 13389-ый порт шлюза на соответствующий порт RDP-сервера;
  2. Устанавливаем ipset – модуль для линуксового файрволла netfilter. Я качал пакеты и ставил.
  3. Прописываем запрещающее правило для внешки:
    /sbin/iptables -A FORWARD -i eth0 -m set --match-set blocked dst -j DROP
    Это правило будет отбрасывать пакеты, приходящие с внешнего интерфейса на адреса, перечисленные в списке blocked;
  4. Пишем скрипт:
    #!/bin/sh
    IPFILE='/etc/ban_ip.txt'
    IPFILE_OLD='/etc/ban_ip_old.txt'
    TIMEOUT=10
    while true
    do
    if [ -e $IPFILE ];
    then
    mv $IPFILE $IPFILE_OLD
    fi
    cat /proc/net/nf_conntrack | grep 'dport=13389' | awk '{print $7}' | cut -d'=' -f2 > $IPFILE
    for i in `cat $IPFILE`
    do
    ipset -T blocked $i 0> /dev/null 2> /dev/null 1> /dev/null
    if [ $? -ne 0 ];
    then
    ipset -A blocked $i
    fi
    done
    for i in `diff --left-column --unchanged-group-format='' $IPFILE $IPFILE_OLD`
    do
    ipset -D blocked $i
    done
    sleep $TIMEOUT
    done
  5. Создаём новый список ip:
    # ipset -N blocked iphash
  6. Запускаем наш скрипт на выполнение.

Что делает скрипт? Получает установленные соединения на порт RDP-сервера (перенаправляемый), выделяет из них IP-адреса. Затем добавляет эти адреса в список блокируемых. Если на следующей итерации адресов стало меньше, то исчезнувшие адреса удаляются из списка блокируемых.

Пока отлаживал работу со сниффером – многое удалось выяснить. Если у вас вдруг какие-то проблемы возникают (у меня часто не получалось), проследите, чтобы последовательность действий была такая:

  1. Клиент 10.0.0.2 посылает SYN-сегмент на 10.0.0.1:13389 (шлюз и порт перенаправления);
  2. Шлюз 10.0.0.1 перепосылает этот же SYN-сегмент на 3389 порт сервера;
  3. Сервер 10.0.0.10 получает SYN-сегмент на порт 3389;
  4. Сервер 10.0.0.10 отвечает SYN+ACK-сегментом на порт шлюза 10.0.0.1;
  5. Шлюз пересылает SYN+ACK-сегмент на порт клиента;

У меня проблемы возникали на разных этапах, чаще всего сервер посылал ответ SYN+ACK не на адрес шлюза, а напрямую клиенту, поэтому соединение сбрасывалось (RST) из-за несоответствия SEQ и ACK-последовательностей.

Кстати, данный подход можно использовать не только в моём сценарии, но и в некоторых других. Подобных решений я пока не встречал (может плохо искал, так что забирайте, применяйте, отписывайтесь!)

Скрипт конечно не идеален, планирую его улучшить, добавить логи, убрать мелкие косяки где-то подшлифовать (иногда дублируются записи + задержку уменьшить, да и уйти от файлов, оставив таблицы в памяти), но пока что работает.

Да, создание ipset набора нужно повесить в автозагрузку.

P.S. Некоторая задержка связана с не мгновенным разрывом соединения в connection tracking, таймер можно уменьшить, но пока не знаю, как это отразится на качестве работы сети в целом.

Интересно? Поделись с другом
Litl-Admin.ru

Comments:

Leave a Reply