Клієнт у LAN коректно досягає свого VPN, і все ж його DNS-запити з’являються на неправильному висхідному каналі. Це не витік у звичайному сенсі; це те, що відбувається, коли маршрутизатор перестає пересилати запит і відповідає сам. Перехоплення переписує призначення на локальний сокет, а потім резолвер відкриває другу, не пов’язану розмову з власною адресою джерела та власним рішенням про маршрутизацію. Позначки, накладені на потік клієнта, описують першу розмову і геть нічого про другу.

Позначка не подорожує разом із запитом

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

Саме тому маршрут політики, прив’язаний до адреси клієнта в LAN, ніколи не збігається з висхідним запитом. Новий сокет належить dnsmasq, а не клієнту, і ядро оцінює маршрут для трафіку самого маршрутизатора. Правила джерела, правила інтерфейсу та правила позначок бачать різний кортеж. Припущення, що позначка поширюється, — найпоширеніша помилка в цій конфігурації, і вона невидима в записі на боці клієнта.

Дві розмови справді поділяють ім’я та час, і саме це змушує їх виглядати як один потік, коли швидко переглядаєш запис.

Де пересилання стає локальним розв’язанням

Почніть із з’ясування, чи порт 53 перенаправляється, чи транслюється на інший хост, чи залишається недоторканим, бо три випадки поводяться по-різному. Перенаправлення на локальний порт завершує пересилання, тоді як трансляція на іншу машину тримає пакет у русі й зберігає кортеж клієнта осмисленим.

Подивіться на обидва протоколи. Резолвер, доступний через UDP і TCP, буде перевірено через обидва, а набір правил, що охоплює лише UDP, залишає тиху діру для великих відповідей. Правила, які генерує власний менеджер конфігурації маршрутизатора, теж рахуються, а редагування згенерованого файлу зазвичай програє наступному перезавантаженню.

sudo nft list ruleset | grep -n -B2 -A4 'dport 53'
sudo iptables -t nat -L -n -v | grep -E ':53|dns'
sudo ss -lunp | grep ':53'

Ці виводи по черзі відповідають на три питання: що переписує запит, що його приймає і який процес володіє слухаючим сокетом. Щойно власник відомий, політиці до upstream є де жити.

Дайте резолверу власну політику виходу

Upstream, прив’язаний до домену, — найчистіший інструмент, коли тунель потрібен лише деяким іменам. dnsmasq приймає рядок server, обмежений доменом, з необов’язковим інтерфейсом або адресою джерела, що спрямовує запит із вибраного пристрою. Саме це спрямування змушує другу розмову йти за VPN.

server=/corp.example/10.30.0.53@tun_work
log-queries

Домен, адреса та інтерфейс вище — це заповнювачі для ваших власних значень. Вибір домену та контроль виходу залишаються окремими рішеннями: маршрут має існувати, адресу джерела має дозволяти upstream-резолвер, а брандмауер має дозволяти відповідь. Лише спрямування через інтерфейс не є fail-closed, бо зниклий тунель може залишити резолвер падати на інший шлях. Тримайте будь-який публічний запасний шлях далеко від простору імен, який має залишатися приватним.

Помістіть рядок до того власника конфігурації, який підтримує маршрутизатор, а не у згенерований файл, інакше наступне перезавантаження зітре виправлення.

Що не може зберегти спільний кеш

Один пересилач з одним кешем обслуговує кожного клієнта в LAN, і це руйнує розрізнення, потрібне деяким мережам. Якщо два клієнти мають розв’язувати те саме ім’я по-різному, спільний сокет не має способу відновити, хто з клієнтів запитав. Політика для кожного клієнта має жити в окремих екземплярах резолвера або у функції пересилання, що зберігає ідентичність.

Відповідь із кешу теж не є доказом щодо нового шляху. Відповідь може прийти з пам’яті, поки маршрут до upstream залишається зламаним.

Правила для порту 53 нічого не кажуть про застосунки, які говорять DNS поверх HTTPS або поверх TLS. Ці запити ніколи не доходять до перенаправлення, тому політика, побудована лише на порту 53, описує підмножину трафіку і має бути задокументована як підмножина.

Перевіряйте другу розмову, а не першу

Перевірте на одному імені, яке ви контролюєте, і спостерігайте за обома боками. Запис на боці клієнта доводить, що запит залишив LAN; лише бік маршрутизатора доводить, куди він пішов далі.

sudo tcpdump -ni tun_work udp port 53
ip route get 10.30.0.53
dig +short corp.example @10.30.0.53

Очищуйте кеш перед кожною спробою, бо тепла відповідь приховує зламаний upstream. Повторіть через TCP, потім повторіть із вимкненим тунелем, щоб побачити, що робить резолвер, коли його бажаний шлях зник. Саме ця остання поведінка вирішує, чи проєкт є fail-closed, чи просто щасливий.

Схожі статті