Программирование, радиоэлектроника,
саморазвитие и частичка из моей жизни здесь...

Скрипт фаервола IPTables для ipv4 и ipv6 с автозагрузкой в Linux (systemd)

Простой и надежный скрипт для загрузки правил фаервола IPTables в GNU Linux используя сценарий авто-запуска для демона инициализации systemd (новая замена для /sbin/init). Правила загружаются и работают как для протокола IPv4, так и для IPv6.

Содержание:

Немного о systemd и IPv6

Раньше, в одной из статей по Linux, я уже описывал создание простого фаервола для защиты сервера и мониторинга количества "вредных" сетевых пакетов. Для авто-запуска скрипта мы размещали его в папке "/etc/init.d", а также добавляли в автостарт системных процессов используя команду "update-rc.d".

Время идет, технологии меняются и в некоторых дистрибутивах GNU Linux на смену старому демону инициализации /sbin/init пришел новый, более мощный - systemd. Кто-то встретил такое нововведение с недовольством, а кто-то поковырявшись оценил преимущества и новые мощные инструменты.

Также время наложило свой отпечаток и на адресное пространство протокола IPv4, которое уже считается исчерпанным, а внешние IPv4-адреса для арендованных VPS/VDS уже не раздают так просто по несколько штук в одни руки, как это было раньше.

Поскольку я работаю с системами на основе Debian/Ubuntu то мне пришлось познакомиться с новым systemd, а также учесть наличие внешних IPv6-адресов на интерфейсах моих серверов и рабочих станций. Сейчас многие провайдеры при аренде у них VPS/VDS серверов предоставляют один или два IPv4-адреса и целую подсеть адресов IPv6.

К примеру при аренде даже самого бюджетного VPS у Ramnode (15$ в год = 1,25$ в месяц) в придачу к адресу IPv4 вам выделят целую подсеть /64, в которой доступно всего-навсего 18,446,744,073,709,551,616 IPv6-адресов!

Любой из таких адресов можно прописать к внешнему сетевому интерфейсу (который смотрит в интернет) и смело получить по нему доступ к вашему серверу из любой точки мира по протоколу IPv6.

IPTables и IPv6

Многие кто арендовал себе VPS и настраивают базовую защиту на основе IPTables даже не подозревают что те правила, которые загружаются при помощи команды "iptables" действуют только для входящих-исходящих пакетов с протоколом IPv4, а трафик что приходит и уходит по протоколу IPv6 в таком случае вообще никак не фильтруется.

Давайте для примера рассмотрим небольшую историю: человек арендовал VPS в Германии, настроил на нем связку Apache+PHP+MySQL, ну и прикрутил еще MongoDB для хранения 100000+ однотипных документов, которые плодят его проекты.

Сервис баз данных MongoDB по умолчанию принимает соединения на портах 27017 и 28017 для всех интерфейсов на сервере. Админ это знал, лезть в настройки MongoDB он не хотел, поэтому добавил несколько правил для брандмауэра используя команду "iptables", которые заблокируют все входящие соединения что поступают с внешнего интерфейса (интернет), как исключения разрешил только порты 80 и 433 для подключения к веб-серверу Apache.

И казалось бы все сделано верно, беспокоиться нет причины...но не тут то было! После установки Linux из образа который предоставил провайдер, сервер получил два внешних адреса в интернете: один для протокола IPv4, а другой - для IPv6.

Невнимательный админ забыл о наличии второго адреса и о вообще "забил" на протокол IPv6 (казалось-бы кто им пользуется, он не популярный еще и т.п.). Как результат - сервер взломали, затерли документы и натворили других чудес.

Кто и как взломал сервер? - судя по последствиям после взлома сервер взломали скорее всего для забавы, получив доступ к MongoDB по портам 27017 и 28017, используя для этого внешний адрес сервера с протоколом IPv6.

Сервер с открытым портом был найден при помощи поискового сервиса Shodan, который сканирует целые подсети IPv4 и IPv6 адресов и собирает признаки интернет-железок, выявляет на них открытые порты, сигнатуры демонов и т.п. Все что нужно было сделать, так это подключиться к базе данных на сервере используя адрес IPv6, сетевые пакеты на котором не фильтровались вообще.

Что можно сделать чтобы подобное не повторилось:

  • Отключить на сервере поддержку протокола IPv6, если в нем нет надобности;
  • Настроить брандмауэр для блокировки нежелательных подключений как для IPv4, так и для IPv6.

При работе с брандмауэром IPTables правила для протокола IPv6 нужно загружать используя бинарник "ip6tables", а для протокола IPv4 - используем бинарный файл "iptables". Таким образом для защиты сервера по двум протоколам нужно загрузить два набора правил, которые для каждого из протоколов имеют свои цепочки и таблички.

Отключение IPv6

Если вы все же решили отключить поддержку протокола IPv6 на сервере под управлением Debian/Ubuntu-подобного GNU Linux, то сделать это можно в несколько простых шагов.

Откроем для редактирования файл с настройками sysctl - sysctl.conf:

nano /etc/sysctl.conf

Добавим в самый низ этого файла следующие строчки:

# IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

Заставим sysctl перечитать настройки из файла sysctl.conf:

sysctl -p

Желательно перезагрузить сервер и все перепроверить. Убедиться в отключенном IPv6 можно посмотрев нет ли адресов c данным протоколом в выводе команды:

ifconfig | grep inet6

Также можно проверить не загружены ли модули поддержки IPv6 в ядре:

lsmod | grep ipv6

В выводах приведенных двух команд не должны встречаться упоминания "inet6" и "ipv6", то есть вывод должен быть пуст.

Скрипт брандмауэра с общим набором правил для IPv4 и IPv6

Раньше для автоматической загрузки ранее сохраненных правил в IPTables я использовал пакет "iptables-persistent". В новой версии GNU Debian Linux (9.0 - Stretch) этот пакет уже исключен из репозитория. Теперь всю необходимую работу по организации авто-запуска какого-либо сервиса можно удобно реализовать с помощью systemd.

Для базовой защиты Linux-сервера или рабочей станции в сети интернет по двум протоколам (IPv4 и IPv6) я написал простой скрипт, который будет автоматически стартовать при загрузке системы используя собственный файл-описание для демона инициализации systemd. Набор правил для каждого из протоколов одинаковый и он определяет вот такую фильтрацию пакетов:

  • Весь ЛОКАЛЬНЫЙ трафик (через виртуальный интерфейс lo0) - разрешен;
  • Все ИСХОДЯЩИЕ пакеты - разрешены;
  • ВХОДЯЩИЕ пакеты, которые относятся к уже установленным соединениям (established) - разрешены;
  • Все остальные ВХОДЯЩИЕ пакеты - логируются и отбрасываются (drop);
  • Все пакеты с перенаправлением (политика forward, для включенной маршрутизации) - логируются и отбрасываются (drop);
  • Блокировка пакетов, которые используются для "тихого" сканирования портов.

Таким образом, мы сможем отправлять с машины любые пакеты (http, ftp, ssh, ping и другие) и получать ответные на них пакеты (что относятся к тому же соединению). Все пакеты что будут приходить снаружи на сервер без предварительно установленного соединения будут писаться в лог системы (смотрим используя journalctl) и отбрасываться.

Такой набор правил отлично подойдет для рабочей станции, удаленный доступ к которой не планируется.

Создадим файл под именем "systemd-iptables.sh" в папке для пользовательских скриптов "/usr/local/sbin/", для этого выполним команду:

nano /usr/local/sbin/systemd-iptables.sh

Скопируем приведенный ниже исходный код скрипта в окно редактора:

#!/bin/sh
# IPTables (ipv4+ipv6) init script for systemd
# 2016 by Ph0en1x (https://ph0en1x.net)

IP4TABLES_BIN=/sbin/iptables
IP6TABLES_BIN=/sbin/ip6tables

# Flush active rules, flush custom tables, and set default policy
Flush_Rules () {
	if [ $1 = "ipv6" ]; then
		IPTABLES=$IP6TABLES_BIN
	else
		IPTABLES=$IP4TABLES_BIN
	fi
	$IPTABLES --flush
	$IPTABLES -t nat --flush
	$IPTABLES -t mangle --flush
	$IPTABLES --delete-chain
	$IPTABLES -t nat --delete-chain
	$IPTABLES -t mangle --delete-chain
	# Set default policies to ACCEPT
	$IPTABLES -P INPUT ACCEPT
	$IPTABLES -P FORWARD ACCEPT
	$IPTABLES -P OUTPUT ACCEPT
}

# Loading rules
Load_Rules () {
	if [ $1 = "ipv6" ]; then
		IPTABLES=$IP6TABLES_BIN
		IPV='IPv6'
	else
		IPTABLES=$IP4TABLES_BIN
		IPV='IPv4'
	fi
	# Flush
	Flush_Rules $1
	# Localhost
	$IPTABLES -A INPUT  -i lo -j ACCEPT
	$IPTABLES -A OUTPUT -o lo -j ACCEPT
	# Default policies
	$IPTABLES -P INPUT DROP
	$IPTABLES -P FORWARD DROP
	$IPTABLES -P OUTPUT ACCEPT
	# Input filter chain
	$IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
	$IPTABLES -A INPUT -j LOG --log-prefix "${IPV}Tables INPUT Dropped:"
	# Forward chain
	$IPTABLES -A FORWARD -j LOG --log-prefix "${IPV}Tables FORWARD Dropped:"
	# disable furtive port scanning
	$IPTABLES -N PORT-SCAN
	$IPTABLES -A PORT-SCAN -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j RETURN
	$IPTABLES -A PORT-SCAN -j DROP
	
}

case $1 in
	start)
		Load_Rules ipv4
		Load_Rules ipv6
		echo "IPTables rules loaded."
		;;
	stop)
		Flush_Rules ipv4
		Flush_Rules ipv6
		echo "IPTables rules flushed."
		;;
	restart)
		Flush_Rules ipv4
		Flush_Rules ipv6
		Load_Rules ipv4
		Load_Rules ipv6
		echo "IPTables rules reloaded."
		;;
	*)
		echo "Usage: systemctl {start|stop|restart} iptables.service"
		exit 1
esac

exit 0

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

Например, если планируется использовать только IPv6 то загрузку правил для IPv4 можно отключить выполнив следующие изменения в скрипте:

	start)
		#Load_Rules ipv4
		Load_Rules ipv6
		echo "IPTables rules loaded."
		;;
	stop)
		#Flush_Rules ipv4
		Flush_Rules ipv6
		echo "IPTables rules flushed."
		;;
	restart)
		#Flush_Rules ipv4
		Flush_Rules ipv6
		#Load_Rules ipv4
		Load_Rules ipv6

Для использования данного скрипта на удаленном сервере (VPS/VDS) нужно открыть возможность принимать входящие соединения, как минимум на порте 22 (SSH, администрирование, туннелирование).

Например, для пропускания входящих пакетов на порты 80, 443 и 22 нужно добавить после правила  "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT") в скрипт следующие строчки:

$IPTABLES -A INPUT -p tcp --dport 22 -j ACCEPT
$IPTABLES -A INPUT -p tcp --dport 80 -j ACCEPT
$IPTABLES -A INPUT -p tcp --dport 443 -j ACCEPT

Также, для открытия данных портов можно добавить всего одно правило с указанием названий протоколов:

$IPTABLES -A INPUT -p tcp -m state --state NEW -m multiport --dports ssh,http,https -j ACCEPT

Если у вас на сервере несколько сетевых интерфейсов и входящие пакеты на порты 80, 443 и 22 должны проходить только на один из них, то можно указать в правиле название интерфейса.

Например, для сетевого интерфейса "venet0" разрешающее правило для того же набора протоколов будет выглядеть следующим образом:

$IPTABLES -A INPUT -p tcp -i venet0 -m state --state NEW -m multiport --dports ssh,http,https -j ACCEPT

После правки и сохранения содержимого скрипта systemd-iptables.sh ему нужно дать права на выполнение, для этого выполним команду:

chmod +x /usr/local/sbin/systemd-iptables.sh

Теперь перейдем к созданию юнита (файл с правилами контроля и управления запуском) для systemd. В данном файле мы опишем назначение, команды управления и условия запуска нашего скрипта.

nano /etc/systemd/system/iptables.service

Разместим в нем вот такой текст:

[Unit]
Description=IPTables rules
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/systemd-iptables.sh start
ExecStop=/usr/local/sbin/systemd-iptables.sh stop
ExecReload=/usr/local/sbin/systemd-iptables.sh restart
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Содержимое данного файла очень напоминает содержимое INI-файлов в Windows. В разделе Unit объявлено описание нового демона (Description), а также название группы демонов (сетевая подсистема - network.target) после инициализации которой должен стартовать наш ново-созданный SH-скрипт.

В разделе "Service" описаны опции для запуска и управления демоном. Как видим, здесь мы вызываем наш скрипт с правилами файрвола, передавая ему в качестве аргументов: start, stop, restart.

После сохранения содержимого файла iptables.service мы можем проверить все ли в порядке с его синтаксисом, для этого выполним команду:

systemctl status iptables.service

Если все ОК то укажем systemd что нужно разрешить запуск демона iptables.service при старте системы:

systemctl enable iptables.service

Теперь мы можем перезагрузить ОС для авто-запуска скриптов или же запустить наш сервис вручную с помощью команды:

systemctl start iptables.service

Скрипт брандмауэра с раздельными наборами правил для IPv4 и IPv6

Выше был приведен простой скрипт для управления iptables+ip6tables, в котором используется один и тот же набор правил как для протокола IPv4, так и для IPv6.

Он прост и удобен, но при использовании более сложных наборов правил может оказаться неработоспособным, и вот почему:

  • При указании IP-адреса для какого-либо узла в сети, iptables откажется его обрабатывать если это IPv6-адрес, а ip6tables выдаст ошибку при попытке скормить ему правило с указанием IPv4-адреса;
  • Синтаксис некоторых ключей в правилах для iptables и ip6tables может отличаться, хотя в подавляющем большинстве своем он одинаков для двух протоколов.

Как пример различия в синтаксисе для iptables и ip6tables можно рассмотреть правило которое блокирует icmp-трафик отсылая сообщение что пакет был отклонен (refused):

iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
ip6tables -A INPUT -j REJECT --reject-with icmp6-adm-prohibited

 Если попробовать в правиле с ip6tables указать "--reject-with icmp-host-prohibited" то получим ошибку:

ip6tables v1.6.0: unknown reject type "icmp-host-prohibited"
Try `ip6tables -h' or 'ip6tables --help' for more information.

В приведенном ниже скрипте правила для iptables и ip6tables можно задавать раздельно для каждого из протоколов. В данном случае, для примера, правила просто продублированы, вы можете их изменить и дополнить для каждого протокола по своему усмотрению. Без изменений, результат работы правил фильтрации у этого скрипта будет такой же как и у предыдущего.

#!/bin/sh
# IPTables (ipv4+ipv6) init script for systemd
# 2018 by Ph0en1x (https://ph0en1x.net)

IP4TABLES_BIN=/sbin/iptables
IP6TABLES_BIN=/sbin/ip6tables

# Flush active rules, custom tables, and set default policy.
Flush_Rules () {
  if [ $1 = "ipv6" ]; then
    IPTABLES=$IP6TABLES_BIN
  else
    IPTABLES=$IP4TABLES_BIN
  fi
    $IPTABLES --flush
    $IPTABLES -t nat --flush
    $IPTABLES -t mangle --flush
    $IPTABLES --delete-chain
    $IPTABLES -t nat --delete-chain
    $IPTABLES -t mangle --delete-chain
    # Set default policies to ACCEPT
    $IPTABLES -P INPUT ACCEPT
    $IPTABLES -P FORWARD ACCEPT
    $IPTABLES -P OUTPUT ACCEPT
}

# Loading rules for IPv4 and IPv6.
Load_Rules () {
  if [ $1 = "ipv6" ]; then
    IPTABLES=$IP6TABLES_BIN
    IPV='IPv6'
    Flush_Rules $1
    # ----------------- IPv6 rules ----------------- #
    # Localhost
    $IPTABLES -A INPUT  -i lo -j ACCEPT
    $IPTABLES -A OUTPUT -o lo -j ACCEPT
    # Default policies 
    $IPTABLES -P INPUT DROP
    $IPTABLES -P FORWARD DROP
    $IPTABLES -P OUTPUT ACCEPT
    # Input filter chain
    $IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    $IPTABLES -A INPUT -j LOG --log-prefix "${IPV} Tables INPUT Dropped:"
    # Forward chain
    $IPTABLES -A FORWARD -j LOG --log-prefix "${IPV} Tables FORWARD Dropped:"
    # disable furtive port scanning
    $IPTABLES -N PORT-SCAN
    $IPTABLES -A PORT-SCAN -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j RETURN
    $IPTABLES -A PORT-SCAN -j DROP
    # ---------------------------------------------- #
  else
    IPTABLES=$IP4TABLES_BIN
    IPV='IPv4'
    Flush_Rules $1
    # ----------------- IPv4 rules ----------------- #
    # Localhost
    $IPTABLES -A INPUT  -i lo -j ACCEPT
    $IPTABLES -A OUTPUT -o lo -j ACCEPT
    # Default policies 
    $IPTABLES -P INPUT DROP
    $IPTABLES -P FORWARD DROP
    $IPTABLES -P OUTPUT ACCEPT
    # Input filter chain
    $IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    $IPTABLES -A INPUT -j LOG --log-prefix "${IPV} Tables INPUT Dropped:"
    # Forward chain
    $IPTABLES -A FORWARD -j LOG --log-prefix "${IPV} Tables FORWARD Dropped:"
    # disable furtive port scanning
    $IPTABLES -N PORT-SCAN
    $IPTABLES -A PORT-SCAN -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j RETURN
    $IPTABLES -A PORT-SCAN -j DROP
    # ---------------------------------------------- #
   fi
}

case $1 in
  start)
    Load_Rules ipv4
    Load_Rules ipv6
    echo "IPTables rules loaded."
    ;;
  stop)
    Flush_Rules ipv4
    Flush_Rules ipv6
    echo "IPTables rules flushed."
    ;;
  restart)
    Flush_Rules ipv4
    Flush_Rules ipv6
    Load_Rules ipv4
    Load_Rules ipv6
    echo "IPTables rules reloaded."
    ;;
  *)
    echo "Usage: systemctl {start|stop|restart} iptables.service"
    exit 1
esac

exit 0

Вместо символа табуляции для форматирования здесь использованы 2 пробела - строки получились короче, удобнее для длинных правил с множеством ключей.

Установка и настройка юнита для автоматического запуска скрипта при старте системы такая же как и для предыдущего скрипта.

Полезные инструменты для IPv4 и IPv6

Для управления и мониторинга состояния iptables.service, а также для просмотра правил IPTables (IPv4 и IPv6) используем следующие команды:

systemctl start iptables.service
systemctl stop iptables.service
systemctl restart iptables.service
systemctl status iptables.service
iptables -nvL
ip6tables -nvL

Наблюдать за попаданием пакетов в правила брандмауэра удобно используя утилитку "watch":

watch -n 1 iptables -nvL
watch -n 1 ip6tables -nvL

Пропинговать хосты для каждого из протоколов можно вот так (пингуем публичные DNS-сервера Google):

ping 8.8.8.8
ping6 2001:4860:4860::8888

Смотрим состояние сокетов используя утилиту ss (socket stats), выведем TCP-сокеты которые прослушиваются (listening), а также информацию о процессах которые их открыли для каждого из протоколов IPv4 и IPv6 по отдельности:

ss -tlnp -f inet
ss -tlnp -f inet6

То же самое только для UDP-сокетов:

ss -ulnp -f inet
ss -ulnp -f inet6

Наблюдаем за TCP и UDP портами под номером 44444 на машинах с интернет-адресами IPv4 и IPv6 (используем nmap):

watch -n 5 "nmap -P0 -sU -p44444 123.123.123.1"
watch -n 5 "nmap -6 -P0 -sU -p44444 2504:fd01:1002:81::6"

Приведенные команды позволят протестировать работоспособность брандмауэра для каждого из протоколов, а также предоставят дополнительную полезную информацию по серверу и статусу его сетевых сокетов.

Заключение

Используя приведенный скрипт для брандмауэра можно защитить свой десктоп или выделенный сервер от вторжений снаружи по протоколам IPv4 и IPv6. Он предельно простой и может быть модифицирован под ваши нужды. Демон инициализации systemd имеет очень широкие возможности и содержит целый ряд мощных инструментов.

Если статья оказалась полезной - помочь проекту можно тут: 👍 ПОМОЩЬ, 🎁 DONATE
3 9192 Linux
Комментарии к публикации (5):
ph0en1x #1ph0en1x
09 Февраль 2018 22:20

Статья дополнена, приведен скрипт с раздельным указанием правил для протоколов IPv4 и IPv6.

0
yuri #2yuri
07 Апрель 2019 19:09

Здравствуйте !
Не подскажите, в чем можеть быть проблема?

systemctl status iptables.service
П iptables.service - IPTables rules
Loaded: error (Reason: Invalid argument)
Active: inactive (dead)

Apr 07 20:39:08 yuri-linmin systemd[1]: /etc/systemd/system/iptables.service:14: Missing '='.

0
ph0en1x #3ph0en1x
07 Апрель 2019 23:16

Здравствуйте.
У вас в файле /etc/systemd/system/iptables.service в строчке под номером 14 что-то прописано или там присутствует какой-то лишний символ. В скрипте из статьи всего 13 строчек. Сотрите все что ниже строчки "WantedBy=multi-user.target", сохраните файл и проверьте исчезла ли проблема.

0
Mr.Hunt #4Mr.Hunt
10 Июль 2019 06:12

Здравствуйте! Подскажите пожалуйста, возможно ли при помощи iptables и ip6tables сделать вот такую штуку:

1.Имеется vps сервер с ipv4 и ipv6 адресами.
2.Имеется роутер с динамическим ipv6 адресом.
3.Имеется ПК, только с ipv4 адресом.

Необходимо иметь доступ по SSH с ПК на роутер.
На роутере стоит скрипт, который при перезагрузке обновляет в DNS запись о новом айпи. Хотел сделать что-то типа прокси из vps, При обращении с ПК по ipv4, по порту 222 на vps, делать форвард через ipv6 до роутера на порт 22. Усложняется задача тем, что адрес у роутера динамический и следовательно желательно писать правило, которое бы выполняло форвард не на ip адрес а на dns имя. Но тут проблема, т.к. iptables (который v4), не может отрезолвить айпи адрес v6, то правило рода: ip6tables -A FORWARD -p tcp --dport 443 -d ipv6.router.com -j ACCEPT становится бесполезным, т.к. необходимо как-то иметь связку между iptables и ip6tables.

0
ph0en1x #5ph0en1x
11 Июль 2019 13:04

Здравствуйте. С IPv6 работал не много, знаю что IPTables пока еще на научился делать подобных вещей. Для маршрутизации трафика "IPv4 <--> IPv6" понадобится дополнительный туннельный интерфейс, попробуйте поискать информацию и примеры, включая в поисковый запрос название вашей ОС на VPS и фразы: "6to4", "6in4".

Еще один вариант - поднять на VPS службу OpenVPN и настроить туннель с поддержкой IPv6. Подключаемся c ПК к IPv4-адресу VPS используя OpenVPN-client, будет поднят туннель, а дальше пробовать коннектиться с ПК к роутеру на сопоставленное ему доменное имя, IPv6 трафик должен пойти через проложенный сетевой туннель.

Поскольку вам нужна всего лишь одна служба (SSH, порт - 22) на роутере, то можно обойтись простым перенаправлением (редиректом) трафика между интерфейсами и портами, один из вариантов - использовать утилиту socat (похожа на netcat, умеет fork'аться от имени указанного пользователя и еще много всего, плюс к безопасности).

socat TCP4-LISTEN:55444,fork,su=nobody TCP6:my-ipv6-router.zzz:22

Где:

  • 55444 - порт, который будет прослушиваться на внешнем IPv4-адресе и через который будет выполняться переброс TCP-трафика в роутер;
  • nobody - пользователь, от имени которого будет работать socat;
  • my-ipv6-router.zzz:22 - доменое имя роутера и порт для подключения к работающей на нем службе SSH.

Программа socat во время подключения к прослушиваемому порту выполняет резолвинг IP-адреса цели, это можно проверить на локальной Linux-машине:

socat TCP4-LISTEN:54444,fork,su=nobody TCP:google.com:80
telnet localhost 54444

В окне телнета вводим "GET" и ЕНТЕР, увидим листинг индексного HTML файла сайта google.com. Теперь в /etc/hosts временно прописываем в сопоставление домену 'google.com' IP-адрес какого-то другого сайта, сохраняем и пробуем снова "зателнетиться" на локальный порт который слушает socat - должны увидеть HTML-код странички уже не от 'google.com'. По завершению не забудьте убрать тестовую запись из /etc/hosts.

Таким образом, вам скорее всего не придется придумывать что-то дополнительно, кроме автозапуска этой команды при старте VPS (можете использовать пример юнита для systemd из этой статьи, поправив его под свои цели).

Если резолвинг DNS-имени роутера в программе socat по какой-то причине не работает, то проще всего написать небольшой скрипт (на BASH или PYTHON) и добавить его в автозапуск системы. Суть работы скрипта: в бесконечном цикле каждые несколько минут пинговать хост роутера по домену, извлекать из вывода IP-адрес и сопоставлять с тем, который указан для запуска процесса socat, если адрес изменился - перезапускать socat с новыми параметрами.

Больше информации и описаний параметров по socat:

man socat

Во всех случаях нужно позаботиться о безопасности. В случае с OpenVPN - настроить авторизацию и шифрование трафика. Для варианта с перенаправлением портов - используя IPTables строго ограничить порт на IPv4 интерфейсе VPS на доступ с других внешних IP, иначе будут подбирать пароли к службе SSH роутера через перенаправленный на IPv4 порт на вашем VPS.

0