UFW сбрасывает DNS-сервер VPN, как только поднимается туннель
Политика запрета по умолчанию в UFW охватывает и интерфейс туннеля. Упорядочите трафик по направлению, разрешите протолкнутый резолвер на tun0 и затем откройте внешний путь.
Имена перестают разрешаться в тот момент, когда подключается VPN, хотя ping до публичного адреса ещё отвечает, а состояние файрвола не показывает ничего, что выглядело бы неправильно. В политике ничего не изменилось; изменилось то, что появился новый интерфейс, и запрет по умолчанию покрывает его с первого пакета. UFW решает по направлению и интерфейсу, поэтому правило, написанное для беспроводного канала, ничего не говорит о трафике, покидающем туннель. Исправление — это горсть узких правил, применённых в определённом порядке.
Симптом появляется только после того, как туннель поднят
Политика запрета по умолчанию делает ровно то, что ей сказано: всё без подходящего правила отклоняется, на каждом существующем интерфейсе. Туннеля не было, когда писались правила, поэтому ни одно из них не может его поймать, и запрет, который был всегда, теперь действует на разрешение имён. Прямой трафик к буквальному адресу может ещё работать, если его покрывает более широкое разрешение, и поэтому ping до публичного резолвера удаётся, а поиск имени — нет. Пробел — это правило для интерфейса, которого политика никогда не видела.
Это же объясняет, почему сбой чисто обращается вспять: уберите туннель, и имена снова разрешаются, потому что запрос возвращается на интерфейс, у которого есть правила. Политика, которая сбоит только при поднятом туннеле, — не проблема DNS, и настройка самого резолвера тратит здесь больше всего времени. Прочитайте список интерфейсов, прежде чем читать конфигурацию резолвера.
Три направления, три разных набора правил
Одна сессия касается правил более чем в одном направлении, и туннель добавляет второй интерфейс почти к каждому из них. Если сначала упорядочить трафик по направлению и интерфейсу, остальное становится механическим, потому что каждой строке ниже нужно своё правило на своём месте. В примерах используются tun0 и пул 10.8.0.0/24, поэтому подставьте имена и диапазоны из собственного вывода клиента.
| Direction | Example packet | Rule that admits it | Written on |
|---|---|---|---|
| Client to the pushed resolver | A DNS query to 10.8.0.1 | Destination port 53 over the tunnel | The client's tun0 |
| Client to the VPN server | A handshake to the server's public address | Server address and port on the physical link | The client's physical interface |
| Server to a service | SSH from the pool to port 22 | Source pool, destination port, tunnel interface | The server's tun0 |
| Anyone to the listener | The VPN listener itself | 1194/udp on the public side | The server's public interface |
Две строки часто путают, потому что обе упоминают туннель. Правило для резолвера пропускает трафик, который клиент отправляет в туннель, а правило для SSH пропускает трафик, который сервер оттуда получает; они живут на разных машинах и сбоят независимо. Строка, которую забывают чаще всего, — вторая, потому что клиент вообще не может построить туннель, пока его трафик к публичному адресу сервера не разрешён. Работайте сверху вниз, и у каждого сбоя есть одна возможная причина.
Протолкнутому резолверу нужно собственное правило
Несёт ли туннель DNS, зависит от того, что присылает сервер. Сервер, который проталкивает опцию резолвера, устанавливает приватный адрес в конфигурацию клиента, и этот адрес маршрутизируется только через туннель. Если сервер ничего не проталкивает, клиент сохраняет уже имеющийся резолвер, и правилам ниже нечего разрешать. Прежде чем что-либо писать, проверьте протолкнутое состояние и текущий результат запроса:
dig +short @10.8.0.1 example.com
resolvectl status tun0
sudo ufw status numberedВывод состояния называет используемый резолвер и канал, к которому он привязан, а поиск маршрута за ним показывает, какой интерфейс понёс бы запрос к этому адресу. Когда резолвер находится на другом канале, проблема раньше файрвола, и никакое правило не поможет. Когда оба согласны насчёт туннеля, нужны два правила, потому что UDP несёт большинство запросов, а TCP перехватывает, когда ответ обрезан. Запишите оба значения, потому что именно их назовут правила:
sudo ufw allow out on tun0 to 10.8.0.1 port 53 proto udp comment 'pushed resolver'
sudo ufw allow out on tun0 to 10.8.0.1 port 53 proto tcp comment 'truncated answers'Откройте внешний путь раньше внутреннего
Клиент должен достичь публичного адреса сервера до того, как туннель появится, поэтому правило для него сидит на физическом канале и должно быть на месте первым. Политика, которая разрешает резолвер, но забывает сервер, оставляет клиента совершенно неспособным построить туннель, и этот симптом обычно списывают на kill switch. Затем разрешите службы, которые вам действительно были нужны через туннель, по одному узкому правилу за раз, вместо того чтобы открывать интерфейс целиком. Узкие правила — причина, по которой запрет может остаться на месте.
sudo ufw allow out to 198.51.100.10 port 1194 proto udp comment 'vpn server'
sudo ufw allow out on tun0 to any port 443 proto tcp comment 'web through tunnel'Порядок важен при тестировании, потому что первое правило — то, что вообще позволяет туннелю подняться. Добавьте его, подключитесь и подтвердите, что туннель поднят, прежде чем добавлять правило службы, потому что сделать оба сразу значит, что сбой ничего не скажет о том, какая половина неверна. Замените адрес из документации выше на конечную точку, для которой настроен клиент.
Завершите сторону клиента, намеренно отключившись. Запрет всё ещё должен отклонять трафик, который вы намеренно исключили, потому что резолвер, отвечающий при поднятом туннеле, покрывает лишь половину политики, которая при сомнении запрещает.
Подключившийся клиент ещё не допущен
У сервера есть своё направление, которое нужно учесть, и клиент, завершивший рукопожатие, всё равно не достигает ничего, что работает на сервере, пока сервер его не допустит. Правило публичного слушателя позволяет туннелю только существовать; оно не впускает трафик туннеля. На сервере это два правила плюс одна проверка, что служба действительно слушает:
sudo ufw allow 1194/udp comment 'openvpn listener'
sudo ufw limit in on tun0 from 10.8.0.0/24 to any port 22 proto tcp comment 'admin over tunnel'
ss -ltn | grep ':22'Пул в правиле должен быть равен диапазону, который выделяет сервер, а номер туннеля должен совпадать с созданным сервером, потому что правило для другого интерфейса неотличимо от отсутствия правила. limit намеренно для административного порта, потому что оно ограничивает повторные подключения, а не принимает их без предела. Проверка слушателя отделяет закрытый порт от отброшенного пакета, которые со стороны клиента выглядят одинаково. Нумерованные правила тоже не вся картина: правила before в UFW и любая написанная вручную строка nftables совпадают раньше и всё ещё могут отклонить пакет, который список вроде бы разрешает.