Маскируем определённый сервис средствами FirewallD

Иногда требуется замаскировать какой-то сервис так, чтобы он был доступен только для определённых IP-адресов, а все остальные на этом же месте видели что-то другое. Это можно реализовать средствами FirewallD без каких-либо TCP-балансировщиков.

Скрипт для Fedora/CentOS 7

Наш код написан на чистом bash с использованием утилиты firewall-cmd:

#!/bin/bash
set -e
 
HPORT=443
PSERVICE=444
HSERVICE=445
OURIP=1.1.1.0/24
ZONE=public

function fw_add {
    sysctl -w net.ipv4.ip_forward=1
    firewall-cmd --zone=$ZONE --permanent --add-masquerade
    firewall-cmd --zone=$ZONE --permanent --add-rich-rule="rule family=\"ipv4\" source address=\"$OURIP\" forward-port port=\"$HPORT\" protocol=\"tcp\" to-port=\"$HSERVICE\""
    firewall-cmd --zone=$ZONE --permanent --add-rich-rule="rule family=\"ipv4\" source not address=\"$OURIP\" forward-port port=\"$HPORT\" protocol=\"tcp\" to-port=\"$PSERVICE\""
    firewall-cmd --reload
}

function fw_rem {
    sysctl -w net.ipv4.ip_forward=0
    firewall-cmd --zone=$ZONE --permanent --remove-masquerade
    firewall-cmd --zone=$ZONE --permanent --remove-rich-rule="rule family=\"ipv4\" source address=\"$OURIP\" forward-port port=\"$HPORT\" protocol=\"tcp\" to-port=\"$HSERVICE\""
    firewall-cmd --zone=$ZONE --permanent --remove-rich-rule="rule family=\"ipv4\" source not address=\"$OURIP\" forward-port port=\"$HPORT\" protocol=\"tcp\" to-port=\"$PSERVICE\""
    firewall-cmd --reload
}
 
function fw_msg {
    echo "Use additional command-line parameters:"
    echo "  * start - start script and add firewalld rules;"
    echo "  * stop - stop script and remove firewalld rules."
}
 
case "$1" in
    "start")
        fw_add
        ;;
    "stop")
        fw_rem
        ;;
    *)
        fw_msg
        ;;
esac

Конфигурация

Скрипт имеет несколько настраиваемых пользователем параметров:

  • HPORT — переменная, хранящая публичный номер порта, к которому мы будем подключаться, например 443 (HTTPS);
  • PSERVICE — номер порта публичного сервиса для чужих пользователей;
  • HSERVICE — номер порта скрытого сервиса для наших IP-адресов;
  • OURIP — наш внешний IP-адрес, с которого мы будем подключаться сервису (HPORT);
  • ZONE — название зоны FirewallD для соединения.

Работа со скриптом

Скрипт добавляет постоянные правила, которые работают до их явной отмены пользователем.

Предположим, что мы сохранили указанный выше код в виде файла под именем rt.sh и выдали ему флаг +x. В таком случае запуск осуществляется так:

./rt.sh start

Отмена всех созданных правил:

./rt.sh stop

Принцип работы

Сценарий запуска:

  • включаем маскарадинг для указанной зоны брандмауэра;
  • проверяем IP-адрес, с которого пришёл пакет и если он соответствует указанному (наш), перенаправляем на порт скрытого сервиса, иначе (чужой) — на порт публичного.

Сценарий остановки:

  • отключаем маскарадинг для указанной зоны брандмауэра;
  • удаляем созданные нами правила перенаправления портов.

Лицензия

Код распространяется под лицензией GNU GPL версии 3 без каких-либо гарантий (явных или подразумеваемых). Используйте его исключительно на свой страх и риск.

Литература

При написании статьи использовалась литература из следующих источников:

4 commentary to post

    1. Например поднимаешь на сервере nginx с HTTPS (слушает порт 444) и openvpn (445), затем подключаешься к openvpn через порт 443. Твой провайдер или кто-то ещё видят в логах соединение на порт 443, решают проверить и видят там вместо VPN сервера обычный веб-сайт.

        1. Разумеется, но:

          1. настоящие DPI стоят очень дорого, поэтому они мало у кого есть;
          2. на DPI обычно гонят далеко не весь трафик, а только для определённых адресов;
          3. можно установить плагин для OpenVPN, который будет эмулировать рукопожатие TLS;
          4. вместо OpenVPN можно поднять SoftEther VPN, который давно умеет маскироваться под HTTPS.

Обсуждение закрыто.