До подсети за конечной точкой туннеля можно добраться тремя способами, и минута сбора фактов обычно исключает два. Факты таковы: должны ли тамошние серверы различать пользователей, станет ли кто-то оттуда когда-нибудь подключаться к вашему диапазону, и кто может редактировать дальний маршрутизатор. Ответьте на эти три вопроса, и дизайн выберется сам. Остальное предполагает, что вы управляете конечной точкой и можете редактировать её межсетевой экран.

Три варианта и что каждый из них на самом деле меняет

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

What the far side needsPrefix mappingPer-host DNATRouted prefix
Users visible to its logsOnly without source NATSame conditionYes, unchanged
To start a connection toward youNo, alias is localNo, same reasonYes, both ends route
To absorb a new hostYes, arithmetic onlyNo, one rule per addressYes, it simply routes
To require no config changeYes, with source NATYes, same conditionNo, it needs a route back

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

Пары префиксов и почему размеры должны совпадать

NETMAP — это цель таблицы nat, работающая с парой префиксов одинаковой длины. Внутри у неё нет таблицы по адресам: она отбрасывает префикс, сохраняет биты хоста и присоединяет их к новому префиксу, поэтому /24 отображается на /24 и никогда на /25. Позиция определяет направление: совпадение по назначению в PREROUTING переписывает, куда идёт пакет, а совпадение по источнику в POSTROUTING переписывает, откуда он пришёл.

Хост на 192.168.2.17 виден вашим клиентам как 10.50.1.17, и последний октет — не украшение, это одно и то же число с обеих сторон. Добавьте завтра хост на 192.168.2.40, и его псевдоним будет 10.50.1.40, без правил, которые нужно редактировать.

Клиентам всё ещё нужен маршрут к диапазону псевдонимов, указывающий на вашу машину, если только псевдоним не попадает в подсеть, до которой они уже достают. Шлюзу маршрут для псевдонима не нужен, потому что трансляция назначения выполняется в PREROUTING, до поиска маршрута. Пересылка тоже должна быть включена, иначе ядро отбросит пакет после перезаписи. Три команды ниже — это вся настройка на шлюзе в стиле Debian с клиентами на br0, псевдонимом на 10.50.1.0/24 и туннелем на tun0.

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -i br0 -d 10.50.1.0/24 -j NETMAP --to 192.168.2.0/24
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

Ответ должен сам найти обратный путь

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

Masquerade на выходе — более короткий путь: одно правило в POSTROUTING, и дальняя сторона видит адрес вашего туннеля, поэтому собственный маршрут ей не нужен. Цена — все пользователи схлопываются в один адрес, и журналы по пользователям перестают что-либо значить. Если оставить источник нетронутым, эта информация сохраняется, но тогда удалённый сайт должен отправлять ответы для диапазона клиентов обратно через туннель.OpenVPN сервере это отправляемая через push push "route 10.50.9.0 255.255.255.0", плюс route 192.168.2.0 255.255.255.0 строка.

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

conntrack -L -d 10.50.1.17
iptables -t nat -L PREROUTING -v -n

Читайте запись в обоих направлениях: исходный кортеж сохраняет ваш псевдоним в назначении, а кортеж ответа несёт реальный адрес. Если кортежа ответа нет, проблема в обратном пути, а не в правиле. Если счётчики PREROUTING ни разу не сдвинулись, пакет так и не дошёл до этого хука.

Коллизии и поиск, который выполняется первым

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

На шлюзе, ip route get 192.168.2.17 должно указывать на устройство туннеля; локальный bridge означает, что дальний диапазон затенён и никакое правило nat это не исправит. Если ваша сеть уже использует 192.168.2.0/24, перенумеруйте удалённый сайт, а не наслаивайте сопоставление на коллизию.

Проверка с реального клиента, а затем сохранение

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

curl -sv http://10.50.1.17/ -o /dev/null
ss -tn dst 10.50.1.17
conntrack -L -d 10.50.1.17

Два-три успешных соединения доказывают арифметику, но ничего не говорят о сохранности или о следующем инженере. Сохраняйте правила там, где их читает процесс загрузки, что в Debian и Ubuntu означает iptables-save > /etc/iptables/rules.v4 с включённым netfilter-persistent. Сопоставление, исчезающее при перезагрузке, хуже отсутствия, потому что сбой приходит без недавнего изменения, которое можно было бы обвинить.

Оставьте заметку рядом с правилами: диапазон псевдонимов, реальный диапазон, причина пары и какая сторона может инициировать. Эта заметка отделяет проект от кучи правил, которые никто не смеет удалить. Она же решает позднейший вопрос, когда удалённый сайт добавляет хост, а адрес, который никто не настраивал, уже отвечает. Если в заметке сказано, что дальней стороне нужен обратный маршрут, следующий человек знает, что удаление правила masquerade ломает связность. Документация здесь дешёвая; заново открывать зависимость от NAT в три часа ночи — нет.

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