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

Решайте по имени, а не по шлюзу

Проверка проста: меняется ли этот адрес, когда клиент переподключается? Если да, имя нужно создавать из сеанса VPN. Если нет, оно относится к статической записи, которую можно прочитать и просмотреть.

Name kindSource of truthWhere it lives
Connected clientThe address OpenVPN just assignedGenerated hosts file, rewritten per session
Service behind the tunnelA fixed address you choseStatic address= drop-in
Anything with a certificate nameThe certificate, not the poolEither, but the name must match the certificate

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

Динамический путь: learn-address и пул

OpenVPN знает назначение, так пусть он вам его и сообщит. Эти параметры сервера делают назначение устойчивым и пригодным для скриптов:

client-config-dir /etc/openvpn/ccd
ifconfig-pool-persist /etc/openvpn/ip-pool 60
script-security 2
learn-address /etc/openvpn/learn-address.sh

learn-address запускает ваш скрипт каждый раз, когда адрес добавляется, обновляется или удаляется, и передаёт операцию, адрес и общее имя. Минимальный скрипт добавляет по одной строке на клиента и убирает её при удалении:

#!/bin/sh
HOSTS=/etc/openvpn/hosts.lan
case "$1" in
  add|update) echo "$2 $3" >> "$HOSTS" ;;
  delete)     sed -i "/^$2 /d" "$HOSTS" ;;
esac
kill -HUP $(cat /var/run/dnsmasq.pid)

На устройстве tun второй аргумент — это туннельный адрес клиента, поэтому строку можно использовать напрямую. На устройстве tap OpenVPN вместо этого передаёт MAC-адрес клиента, потому что сегмент tap может нести и другие протоколы помимо IPv4, и тогда адрес нужно найти в файле пула по общему имени, прежде чем что-либо писать.

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

Статический путь: address= и расширение домена

Направьте dnsmasq на созданный файл вместо системного файла hosts и дайте ему домен, чтобы короткие имена разворачивались в полные:

domain=corp.example
no-hosts
addn-hosts=/etc/openvpn/hosts.lan
listen-address=127.0.0.1,10.8.0.1
bind-interfaces

Если domain задан, строка вида 10.8.0.6 alice отвечает и для alice, и для alice.corp.example. Держите listen-address только на шлюзе туннеля и loopback, потому что резолвер, случайно опубликованный на интерфейсе LAN, — это служба, которую вы не собирались предлагать.

Службы, которые никогда не приходят из пула, получают собственные записи. Поместите их в отдельный drop-in файл в каталоге конфигурации дистрибутива, чтобы обновление пакета не могло их перезаписать:

address=/files.corp.example/10.8.0.20
address=/db.corp.example/10.9.0.5

Передайте резолвер, иначе ничего не произойдёт

Резолвер, который никто не спрашивает, ничего не меняет. Сервер должен объявить его:

push "dhcp-option DNS 10.8.0.1"
push "dhcp-option DOMAIN corp.example"

Клиенты Windows применяют оба параметра сами. Большинство клиентов Linux — нет: им нужна поддерживаемая интеграция с резолвером, например хук update-resolv-conf дистрибутива или обработка DNS в NetworkManager, либо вручную заданные домен поиска и сервер имён. Проверяйте фактический резолвер клиента, а не предполагайте, что push соблюдён, потому что проигнорированный push выглядит точно так же, как сервер, который не отвечает.

Проверьте на трёх уровнях

Сначала спросите сервер напрямую, затем клиент, затем приложение:

dig +short @10.8.0.1 alice.corp.example
getent hosts files.corp.example

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

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

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