Почему ваша LAN не доходит до сервиса на клиенте VPN
Клиент VPN может размещать сервис, который LAN не может открыть. Обычно не хватает обратного пути: одного маршрута, пары DNAT или строки SNAT, которую никто не добавляет.
Ваш туннель поднят, сервис слушает, а офисная LAN всё равно ничего не получает обратно. Никто не ломал VPN. Со стороны LAN адрес туннеля ноутбука не существует, пока что-то не скажет LAN, как до него добраться, и ответ должен вернуться тем же путём, которым ушёл запрос. Я видел, как люди трижды пересобирали полностью исправный туннель, прежде чем кто-то посмотрел на обратный путь.
Сломался не туннель
Оба конца находятся в частных диапазонах, и это нормальный случай, а не ошибка конфигурации. Адрес вроде 10.8.0.6 реален внутри туннеля и нигде больше не существует, поэтому у LAN нет причин что-либо туда отправлять. Прежде чем трогать маршрутизацию, убедитесь, что сервис вообще доступен внутри туннеля: на клиенте ss -ltn показывает, привязан ли слушатель к 127.0.0.1, к интерфейсу LAN или к адресу туннеля. Демон, привязанный только к loopback, не отвечает никому, кроме себя, и никакой маршрут, DNAT или проброс порта этого не меняет.
Прокси на порту 80 или 443 — другой инструмент с другой видимостью. Он перемещает запросы, а не пакеты, поэтому это неверный уровень для прямого подключения к базе данных, и именно обращение к нему приводит к тому, что эта проблема оказывается на три инструмента глубже, прежде чем кто-то что-то измерит.
Форма маршрута: скажите LAN, где находится пул
Статический маршрут на шлюзе LAN — самый чистый ответ, когда LAN и пул туннеля не пересекаются. Направьте пул на машину, которая завершает туннель:
ip route add 10.8.0.0/24 via 192.168.1.12
route add -p 10.8.0.0 mask 255.255.255.0 192.168.1.12 # Windows, persistent
Это исправляет только одно направление, поэтому недоделанные версии этого изменения выглядят как прогресс. Стороне туннеля нужна соответствующая половина, иначе ответ покидает клиента по его собственному маршруту по умолчанию и погибает в пути:
push "route 192.168.1.0 255.255.255.0"
Для подсети, которая находится за одним клиентом, а не за сервером, серверу нужны и системный маршрут, и запись iroute в файле этого клиента под client-config-dir. Без iroute OpenVPN знает, что префикс существует, и не имеет представления, какой клиент им владеет: пакеты приходят, а демону не с чем их сопоставить.
Вот миф, который стоит назвать. Маршрут делает адрес достижимым; он не делает противоположную сторону готовой ответить. Партнёры «сайт-сайт» добавляют ещё один слой сверху, потому что удалённый шлюз принимает только источники внутри префиксов из своей политики, а ноутбук, приходящий из домашнего пула, в них не входит.
Форма NAT: DNAT внутрь и строка SNAT, которую все пропускают
Когда нельзя трогать шлюз LAN или нужно опубликовать ровно один порт, трансляция на хосте VPN работает вообще без маршрута в LAN. Опубликуйте порт, пробросьте его и транслируйте источник на пути в туннель:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 10.8.0.6:3000
iptables -A FORWARD -i eth0 -o tun0 -p tcp -d 10.8.0.6 --dport 3000 -j ACCEPT
iptables -t nat -A POSTROUTING -o tun0 -d 10.8.0.6 -p tcp --dport 3000 -j SNAT --to-source 10.8.0.1
Третья строка — та, которая теряется. Пропустите её, и клиент увидит исходный адрес LAN как источник, ответит по своему маршруту по умолчанию, и этот ответ уйдёт в туннель вместо возврата к LAN. Выживет ли соединение, зависит тогда от маршрутизации, которую вы никогда не планировали. С SNAT клиент видит адрес туннеля сервера, поэтому ответ идёт по туннелю назад к единственному хосту, который может отменить трансляцию.
Потребительская прошивка использует собственные имена цепочек и не создаёт эту трансляцию за вас. На Tomato входящее правило попадает в WANPREROUTING, а затем в цепочку фильтрации вроде wanin, и набор правил, который кажется полным, всё равно требует ручной строки POSTROUTING. Это не ошибка прошивки; это набор правил, написанный только для входящего трафика.
Почему правило, которое выглядит правильным, всё равно отбрасывает пакет
Большинство этих сбоев не в том правиле, на которое вы смотрите. Проверьте четыре вещи в этом порядке и остановитесь на первой, которая не выполняется:
- Порядок цепочек.
iptables -Iвставляет сверху, а-Aдобавляет в конец, поэтому более раннее разрешающее или блокирующее правило решает первым. - Не та цепочка. Трафик, адресованный самому маршрутизатору, проходит через INPUT, а пересылаемый трафик её никогда не касается. Публикация одного сервиса может требовать правил в обеих.
- Флаги направления.
-i tun0совпадает с трафиком, приходящим от клиентов, а-o tun0— с уходящим к ним. REJECT с неверным флагом блокирует то, чего вы не планировали. - Ограничение источника. Пересылка, принимающая один адрес клиента, работает от этого клиента и отбрасывает любой другой источник без единого слова.
Правило с нулевым счётчиком пакетов вообще не находится на пути, и чтение счётчиков — самый быстрый способ отделить проблему неверной цепочки от проблемы неверного правила.
Локальный проброс, когда в LAN ничего нельзя изменить
Локальный проброс SSH обходит весь вопрос. Ему не нужен маршрут в LAN, не нужно сотрудничество брандмауэра клиента и не нужен порт, опубликованный где-либо:
ssh -N -f -L 3000:10.8.0.6:3000 user@vpn-host
Тогда сервис появляется на localhost:3000 машины, которая держит туннель, и нигде больше. Это и есть граница: одна рабочая станция, один порт, и проброс умирает вместе с сеансом, если что-то его не перезапустит. Для администратора, проверяющего тестовую базу данных, это правильный инструмент. Для камеры или сканера, до которых должны добраться другие люди, — нет, потому что каждому пользователю понадобился бы свой проброс.
Проверьте оба направления, прежде чем добавлять ещё одно правило
Трансляция оставляет следы, и читать их лучше, чем гадать. На хосте VPN conntrack -L показывает, произошла ли трансляция вообще, iptables -t nat -L -n -v показывает, сдвинулись ли счётчики, а tcpdump -ni any port 3000 показывает, какой адрес источника действительно пришёл. На клиенте ss -ltn подтверждает, что слушатель находится на адресе, до которого туннель может добраться.
Затем выберите форму, которую оставляете. Один опубликованный порт, маршрут для всего пула и проброс для одного администратора — это три разных обязательства, и их смешение — это путь, которым работающая конфигурация превращается в такую, которую через шесть месяцев никто не сможет объяснить. Запишите, какой адрес откуда достижим, и следующий человек, который будет это отлаживать, начнёт с ответа, а не с туннеля.