Разместите службу на ноутбуке за NAT уровня оператора, направьте этот ноутбук на VPS через VPN, и никто снаружи не сможет до него добраться. Вы добавляете правило NAT назначения на VPS и получаете нечто худшее, чем тишина: соединения открываются и затем зависают. Ответ не пропадает, он уходит по собственному маршруту по умолчанию самого клиента, а значит, сервер его никогда не видит. Пройдите эти пять проверок по порядку и остановитесь на первой, которая не выполняется.

Убедитесь, что сервер вообще будет пересылать

Отметьте этот пункт, прежде чем писать хотя бы один перевод. Правило DNAT для пакета, который ядро отказывается пересылать, принимается разборщиком правил и затем отбрасывается путём пересылки, что даёт тайм-аут, похожий на проблему с межсетевым экраном.

sysctl net.ipv4.ip_forward
sysctl -w net.ipv4.ip_forward=1

Задать это в работающем ядре — не то же самое, что задать его через перезагрузку. Запишите net.ipv4.ip_forward=1 в файл в /etc/sysctl.d/, выполните sysctl --system, а затем прочитайте значение обратно вместо того, чтобы верить, что файл подхвачен. Контейнеру, который управляет своим пространством имён сети, нужно то же значение внутри этого пространства, а не только на хосте.

Если обратное чтение по-прежнему ноль, остановитесь здесь. Ничего дальше не заработает.

Закрепите адрес туннеля, прежде чем на него сошлётся любое правило

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

client-config-dir /etc/openvpn/ccd
ifconfig-push 10.77.0.14 10.77.0.13

Эта пара — клиентский конец и конец партнёра туннеля точка-точка, причём сервер привязан к общему имени сертификата. В топологии подсети второе значение читается вместо этого как маска сети, поэтому пишите форму, соответствующую используемой топологии. Затем переподключите клиента и прочитайте адрес на самом клиенте, потому что взгляд сервера на пул не доказывает, что настроил клиент.

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

Переводите в обе стороны

Перевод назначения отправляет входящий пакет клиенту. Именно перевод источника заставляет клиента отвечать серверу, а не первоначальному отправителю, и это то правило, которое люди упускают.

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 29443 -j DNAT --to-destination 10.77.0.14:29443
iptables -t nat -A POSTROUTING -d 10.77.0.14 -p tcp --dport 29443 -j SNAT --to-source 10.77.0.13

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

Прочитайте оба правила обратно с помощью iptables -t nat -S и убедитесь, что имя интерфейса — то, которое несёт публичный адрес. На хосте, который уже фильтрует через nftables, напишите перевод в цепочке NAT nftables соответствующего семейства адресов, а не смешивайте инструменты.

Пропустите таблицу фильтрации

Таблицы NAT переписывают заголовки; они не дают разрешения. При политике DROP по умолчанию пересылаемому потоку нужно собственное разрешение, плюс обратное направление, которое большинство политик уже покрывают правилом established,related.

iptables -A FORWARD -i eth0 -o tun0 -p tcp --dport 29443 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Проверьте политику цепочки FORWARD, прежде чем что-либо добавлять, потому что порядок раннего DROP решает, будет ли ваше правило вообще учтено. На хосте, чья фильтрация живёт в nftables, добавьте эквивалентное правило в перехватчик forward таблицы inet и убедитесь, что базовая цепочка действительно видит пересылаемый трафик, а не только локальный вход. Если счётчик пакетов на новом правиле остаётся нулевым, а счётчики NAT растут, пакет отбрасывается до вашего правила. Это сигнал прочитать порядок цепочек, а не добавить вторую копию того же правила.

Докажите это из внешней сети

Проверьте из несвязанной сети. Проба с другой машины в том же LAN может пройти через поддержку hairpin NAT и никогда не задействует путь, который использует удалённый клиент, поэтому зелёный результат там доказывает неверное.

tcpdump -ni any port 29443
conntrack -L | grep 29443

Запустите захват на сервере и на клиенте одновременно. Захват на сервере показывает, уходит ли переведённый пакет в сторону туннеля; захват на клиенте показывает, приходит ли запрос и куда адресован ответ. Запись перевода в conntrack -L доказывает, что правило совпало, а её отсутствие доказывает, что пакет так и не дошёл до цепочки NAT.

Сканеры портов — слабое доказательство. Они сообщают порт как закрытый, пока приложение не привязано и не слушает, поэтому используйте настоящее соединение с настоящей службой. Когда это наконец заработает, держите экспозицию на одном этом порту: пересылка SSH или панели администратора потому, что первое правило показалось неудобным, — гораздо более крупное решение, чем публикация службы.

Похожие статьи