Чому другий тунель VPN ламає перший?
Другий клієнт VPN встановлює дві половинні маршрутні записи за замовчуванням, і перший тунель гасне: прочитайте, який маршрут перемагає, потім розділіть за профілем, таблицею або простором імен.
Встановлення другого клієнта VPN, щоб дістатися до однієї мережі замовника, — звичний спосіб, з якого це починається, і перший тунель гасне, поки обидва клієнти повідомляють про успіх. Кожен клієнт встановив маршрут за замовчуванням, другий був конкретнішим, і ядро тепер дотримується його для всього, крім власного зовнішнього з'єднання першого тунелю. Нічого не впало, і жоден профіль не помилковий. Один маршрут замінив інший, і рішення полягає в тому, щоб визначити, який тунель має володіти маршрутом за замовчуванням.
Симптом: другий клієнт тихо перемагає
OpenVPN: параметр redirect-gateway def1 не перезаписує 0.0.0.0/0. Він додає 0.0.0.0/1 і 128.0.0.0/1: разом вони охоплюють кожну адресу IPv4, і кожен префікс довжиною перемагає звичайний маршрут за замовчуванням. Початковий маршрут за замовчуванням залишається в таблиці й більше не використовується для звичайного трафіку, а маршрут до хосту VPN-сервера не дає тунелю перехопити власні зовнішні пакети. Обидва клієнти роблять так, а другий просто встановлює свою пару пізніше.
Тому перший тунель здається мертвим, а не відключеним. Його інтерфейс піднято, канал керування живий, і трафік програм більше до нього не доходить. Зворотна скарга має той самий відсутній push: телефон, який підключається, але нічого не надсилає, зазвичай говорить із сервером, який ніколи не оголошував redirect-gateway, тож пристрій зберігає свій маршрут за замовчуванням і досягає лише пулу.
Зробіть знімок маршрутів до і після підключення другого клієнта. Два половинні маршрути, що з'являються в таблиці, — це вся зміна, і вони пояснюють обидві скарги. Ніщо інше в таблиці не має рухатися, щоб симптом з'явився. Тому видалення другого клієнта миттєво відновлює перший.
Прочитайте, який тунель справді перемагає
Не виводьте переможця з порядку запуску клієнтів або зі значка в лотку. Запитайте ядро, який маршрут воно використає для призначення за межами обох приватних мереж, і прочитайте повернутий інтерфейс.
ip route show
ip route get 198.51.100.24
route print -4
Find-NetRoute -RemoteIPAddress 198.51.100.24
Перші дві команди — відповідь Linux, останні дві — еквівалент Windows. Виконайте їх, поки обидва тунелі піднято, потім відключіть один і виконайте знову. Різниця між двома виводами — той факт, який потрібен перед вибором рішення, і це займає менше часу, ніж читання журналу будь-якого клієнта.
Запишіть результат, включно з іменем інтерфейсу та префіксом, що збігся. Заявка, у якій сказано, що другий VPN зламав перший, — це опис симптому, а не маршрутне твердження, на яке можна спертися. Перевірка перетворює його на факт, який наступний інженер відтворить однією командою.
Windows: не дозволяйте одному профілю володіти маршрутом за замовчуванням
Windows зберігає збережені профілі, а вбудований клієнт дозволяє одному залежати від іншого, щоб перший піднімався автоматично, коли другий набирає з'єднання. Профіль, підключений останнім, зазвичай утримує маршрут за замовчуванням, тож практичний власник — останнє підключення, а не перше. Дайте кожному профілю власні push-маршрути та ввімкніть split tunneling для того, який не повинен володіти маршрутом за замовчуванням.
Set-VpnConnection -Name "Contoso" -SplitTunneling $true
rasdial Contoso
Split tunneling змінює це: до таблиці потрапляють лише префікси, надіслані сервером, що залишає маршрут за замовчуванням у першого тунелю. Проєкт усе одно зазнає невдачі, якщо обидва сервери надсилають маршрут за замовчуванням, бо тоді перемагає останнє з'єднання і жодне налаштування на боці клієнта цього не змінює. Виправте push на боці сервера або прийміть одного власника.
Профілі, які запускає програма, — інша функція, і про неї варто знати: профіль Windows може запускатися, коли стартує вказаний виконуваний файл, а фільтри трафіку вирішують, що він несе. Це налаштування профілю, а не правило брандмауера, і воно вирішує іншу проблему, ніж конфлікт маршруту за замовчуванням.
Linux: тримайте другий тунель поза головною таблицею
Запуск двох екземплярів openvpn --config на одній машині поміщає обидва клієнти в одну таблицю, і три варіанти розділяють їх із зростаючою ізоляцією. Найлегший — взагалі не давати другому клієнту редагувати таблицю: route-nopull з явними маршрутами або скрипт route-up, який встановлює лише задумане. Тоді другий тунель несе рівно названі вами префікси й нічого більше. Тоді ви вирішуєте, які префікси куди йдуть, замість того щоб виявляти це потім.
Маршрутизація за політиками — середній варіант. Правило вибирає окрему таблицю для однієї адреси джерела або позначки брандмауера, і ця таблиця несе маршрути другого тунелю. Фільтрація зворотного шляху тут є пасткою, бо відповідь, що прийшла на інший інтерфейс, ніж вибрала б таблиця, відкидається, тож перевірте налаштування rp_filter, перш ніж робити висновок, що тунель зламано.
ip rule add from 10.44.7.0/24 table 100
ip route add default dev tun1 table 100
sysctl net.ipv4.conf.all.rp_filter
Мережеві простори імен — найважчий і найчистіший варіант. Запустіть другий клієнт усередині ip netns, дайте йому пару veth і ввійдіть у цей простір імен, щоб користуватися ним. Перешкоди зникають, бо кожен простір імен має власні таблиці замість спільної, і це варте додаткового налаштування, коли обидва тунелі мають залишатися піднятими тижнями.
За програмами, і ланцюг як окрема проблема
Іноді другий тунель має використовувати лише одна програма. У Linux маршрутизація за політиками за користувачем, cgroup або портом дає цей результат, і одне призначення можна прикріпити до інтерфейсу, взагалі не торкаючись маршруту за замовчуванням. Програма, що прикріпила свій сокет до одного інтерфейсу, взагалі не звертається до таблиці маршрутизації, тож лаунчер може далі використовувати фізичний адаптер, доки адресу не вибрано в його власних налаштуваннях.
Ланцюг — це інша операція, ніж запуск двох тунелів поруч. Зв'язати A поверх B означає, що адреса внутрішнього сервера має бути доступною зсередини зовнішнього тунелю. Зовнішній клієнт також не повинен вважати зашифровані пакети внутрішнього клієнта витоком. Один клієнт усередині віртуальної машини — груба, але надійна версія; обидва на одному хості потребують описаної вище роботи з маршрутами плюс зовнішнього шляху до внутрішнього сервера, який ніколи не входить у внутрішній тунель.
Запишіть власника маршруту за замовчуванням, список префіксів кожного тунелю і шлях DNS. Ці три факти перетворюють наступний інцидент на довідку, а не на розслідування.