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

Начните с точки зрения клиента

Клиент в этом примере находится в пуле VPN 10.62.0.0/24 и подключается к 10.62.0.1 по порту 8080. Этот адрес принадлежит самому шлюзу, поэтому пакет приходит в ядро шлюза, а не к другому участнику. За шлюзом LAN — 172.21.4.0/24. Шлюз занимает 172.21.4.10, а устройство, которое действительно обслуживает HTTP, — 172.21.4.40.

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

Ограничьте трансляцию назначения намеренно

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

iptables -t nat -A PREROUTING -i tun0 -s 10.62.0.0/24 -d 10.62.0.1 -p tcp --dport 8080 -j DNAT --to-destination 172.21.4.40:80

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

Пусть граница перенаправления согласится

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

iptables -A FORWARD -i tun0 -o lan0 -d 172.21.4.40 -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Безусловное разрешение для каждого потока DNAT шире этого решения и позволит также отображения, добавленные позже кем-то другим. Назовите назначение и порт, а остальное оставьте закрытым. Если счётчики на правиле перенаправления остаются нулевыми, а счётчики NAT растут, пакет отбрасывается до вашего правила. Читайте порядок цепочек, а не добавляйте вторую копию.

Устройство должно как-то ответить

После трансляции устройство видит источник в 10.62.0.0/24. Его ответ идёт на шлюз по умолчанию, которым является маршрутизатор LAN, а не VPN-шлюз, если что-то не скажет ему иначе. Это исправляют две схемы, и они не эквивалентны. Маршрут на устройстве или на маршрутизаторе LAN отправляет 10.62.0.0/24 на 172.21.4.10, сохраняя источник клиента. Ограниченная трансляция источника вместо этого скрывает клиента за LAN-адресом шлюза.

ip route add 10.62.0.0/24 via 172.21.4.10 dev eth1
iptables -t nat -A POSTROUTING -s 10.62.0.0/24 -d 172.21.4.40 -o lan0 -p tcp --dport 80 -j SNAT --to-source 172.21.4.10

Выбирайте по тому, что нужно сервису. Политика для каждого клиента и содержательные журналы требует маршрутизируемой формы; устройство, которому нельзя дать маршрут, или сервис, которому просто нужно видеть адрес LAN, указывают на транслируемую форму. Не хватайтесь за глобальное правило masquerade, чтобы заработал один ответ. Оно скрывает каждого клиента от каждого назначения и тихо ломает политики, зависящие от адресов источника.

Не проверяйте с самого шлюза

Запрос, созданный на шлюзе к 10.62.0.1, выходит через цепочку OUTPUT, а не через входящую PREROUTING. Его неудача или успех ничего не говорят о правиле, обращённом к клиенту, и именно так люди делают вывод, что рабочее правило сломано.

conntrack -L | grep 172.21.4.40
tcpdump -ni any 'port 8080 or port 80'

Запустите настоящий клиентский запрос и прочитайте оба. Запись conntrack показывает применённую трансляцию, а перехваты показывают, прошёл ли запрос в LAN и вернулся ли ответ в сторону туннеля. После изменения правил используйте новое соединение, потому что существующее состояние сохраняет прежнее отображение и будет продолжать сбоить по-старому. Затем подтвердите весь разговор: адрес устройства, разрешение перенаправления и маршрут ответа описывают один и тот же поток.

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