Чому ваш VPN обривається, коли змінюється Wi-Fi або вмикається Ethernet
'Новий SSID, роумінг між точками доступу та підключений кабель рвуть тунель у трьох різних місцях. Перевірте адресу джерела, потім маршрут, потім протокол.'
Дві речі повідомляють як одну несправність: ноутбук перейшов до іншої мережі Wi-Fi або кабель увімкнули, поки Wi-Fi продовжував працювати. Клієнт досі каже «підключено», значок виглядає здоровим, а тунель нічого не передає. Під поверхнею можуть зсунутися лише три частини стану - зв’язок, локальна адреса, маршрут за замовчуванням - і те, яка зсунулася, визначає, чи тунель відновиться сам, чи знадобиться перепідключення. Я перевіряю їх саме в цьому порядку, бо зміна налаштувань облікового запису жодного разу не виправила жодної з них.
Зв’язок, адреса і маршрут рухаються незалежно
Роумінг між точками доступу однієї мережі - зазвичай подія L2. Радіо переасоціюється, інтерфейс зберігає адресу і шлюз, і ніщо, від чого залежить тунель, не змінюється, тому прогулянка великим офісом іноді минає непоміченою. Підключення до іншого SSID - не це: старий інтерфейс може впасти, DHCP видає нову адресу, новий шлюз і нові розв’язувачі, а зовнішній потік, який використовував тунель, перестає існувати.
Ethernet додає третю форму. Wi-Fi ніколи не падає, тому подія зв’язку взагалі не спрацьовує, але дротовий інтерфейс з’являється зі своєю адресою і часто виграє маршрут за замовчуванням за метрикою. Тунель далі йде шляхом, який уже не є пріоритетним, або клієнт тримає свій сокет прикріпленим до тієї бездротової мережі, у якій почав. З браузера обидва виглядають однаково: сторінки завмирають тієї миті, коли кабель клацає.
Тож перше питання не в тому, чи змінився Wi-Fi. А в тому, чи змінилася адреса, до якої ви прив’язані, або маршрут до кінцевої точки, поки тунель працював.
Зовнішній сокет прикріплений до адреси, яка щойно зникла
Кожен тунель - це зовнішній потік: локальна адреса і порт розмовляють з адресою і портом сервера. У Linux це UDP-сокет, прив’язаний до старого джерела; коли інтерфейс, що тримає адресу, видаляється, надсилання або падають з EADDRNOTAVAIL, або виходять через новий інтерфейс із джерелом, якого сервер ніколи не бачив.
Далека сторона тримає своє прикріплення. SA IKEv2 без MOBIKE ідентифікується парою адрес, а OpenVPN сесія прив’язана до адреси партнера, яку вона вивчила, а відображення NAT належить приватній адресі, порту і публічній адресі, що його створили. Перейдіть за інший NAT, і кожна відповідь іде на відображення, якого вже немає. Ніщо на вашій машині не налаштовано неправильно; п’ятірка вказує на мережу, яку ви залишили.
Прочитайте стан, перш ніж будувати теорії:
ss -unpпоказує локальну адресу і порт, які кожен сокет тунелю справді тримає.ip route get 203.0.113.10друкує адресу джерела і пристрій, які ядро використало б для кінцевої точки зараз.wg show wg0 endpoints,swanctl --list-sasабо журнал клієнта показує адресу партнера, з яким далека сторона думає, що говорить.
Якщо адреса сокета і пошук маршруту не збігаються, ви знайшли розрив, і жодна зміна облікових даних його не зачепить.
Що кожен протокол робить з новою адресою джерела
Клієнти поглинають зміну різною мірою, і таблиця - це те, з чим я порівнюю конфігурацію клієнта, замість того щоб вгадувати з поведінки перепідключення.
| Tunnel | Recovery behaviour | Failure signature |
|---|---|---|
| WireGuard | Updates the peer endpoint when an authenticated packet arrives from a new address; no handshake needed if traffic continues. | Handshake current, no return traffic; wg show still lists the old endpoint. |
| IKEv2/IPsec | MOBIKE (RFC 4555) moves the SA to the new address; without it the responder discards packets from an unknown source. | DPD or keepalive timeouts, then a full rekey or a dead SA. |
| OpenVPN over UDP | --float accepts a packet from a new source mid-session; otherwise the session stays tied to the original peer address. | Idle until ping-restart fires, then a visible reconnect. |
| OpenVPN over TCP | The tunnel is a byte stream, so a changed source address breaks it outright. | Immediate reset and a new connection attempt. |
Правило роумінгу WireGuard працює лише в один бік: клієнт має спершу надіслати з нової адреси. Сокет, досі прив’язаний до старого інтерфейсу, ніколи цього не робить, тому тунель може виглядати живим, поки його таймер рукостискання старіє. опис протоколу точно вказує умову оновлення кінцевої точки, і його варто прочитати перед зміною конфігурації.
MOBIKE узгоджується, а не припускається. Якщо сервер його не пропонує, клієнт має встановити з’єднання заново, і це факт, який ви підтверджуєте зі списку SA або журналу, а не виводите з коліщатка, що обертається.
Шлях визначає пріоритет маршруту, а не значок Wi-Fi
Коли обидва інтерфейси підняті, ядро вибирає за метрикою і довжиною префікса. ip route show default перелічує кандидатів, а ip route get 203.0.113.10 вирішує справжнє рішення, включно з адресою джерела. Дротовий маршрут за замовчуванням з метрикою 100 і бездротовий з 600 означають, що кінцева точка зсувається тієї миті, коли кабель сідає, тоді як кожна програма, що відкрила сокет раніше, зберігає своє старе джерело.
Windows робить те саме з автоматичними метриками інтерфейсів, зміщеними за швидкістю зв’язку. Get-NetRoute -DestinationPrefix 0.0.0.0/0 сортує кандидатів, а Find-NetRoute -RemoteIPAddress 203.0.113.10 повертає інтерфейс і джерело, які вибрав би стек. Клієнт, що прив’язує свій зовнішній сокет до одного інтерфейсу, продовжує ним користуватися після перевороту метрики; це рішення про прив’язку, а не помилка маршрутизації.
Android робить поділ видимим: ConnectivityManager повідомляє доступні мережі й окремий маршрут за замовчуванням, а VPN-програма, що прив’язує сокет до об’єкта Network, тримає цю прив’язку, доки не переприв’яже. У macOS scutil --nwi друкує основний інтерфейс і порядок, який використала б система.
DNS, MTU і IPv6 рухаються разом із підключенням
Нове підключення приносить нові розв’язувачі. З systemd-resolved DNS задається для кожного зв’язку, resolvectl status показує, який зв’язок відповідає на ім’я, а гостьова мережа, що роздає власний розв’язувач, може залишити просунутий тунелем DNS невикористаним, доки зв’язок знову не стане пріоритетним. Захопний портал погіршує це: на перший запит HTTPS відповідає портал, а не кінцева точка, і клієнт записує мертвий сервер.
MTU шляху теж змінюється. Ethernet і Wi-Fi зазвичай несуть 1500 байтів, PPPoE 1492, а мобільні зв’язки часто менше. Тунель, що успадкував менший MTU, застрягає на великих пакетах, поки малі запити проходять, і це читається як наполовину зламане з’єднання. ping -M do -s 1472 203.0.113.10 надсилає пакет у 1500 байтів з установленим DF; тиша означає, що шлях менший, ніж ви припускали.
IPv6 - друга половина. Мережа, що видає новий префікс, змінює джерело, яке використав би клієнт із двома стеками, а тунель лише для v4 залишає трафік v6 зовні, доки політика не наздожене. ip -6 route show default і ip -6 addr show відповідають, чи має новий зв’язок узагалі шлях v6.
Відтворіть перехід, а не описуйте його
Виберіть один нешкідливий запит і виконайте ті самі три команди з обох боків зміни: ip -br addr, ip route show default, ip route get 203.0.113.10. Потім дивіться, чи тунель ще випускає пакети - tcpdump -ni any udp port 51820 для WireGuard, відповідний порт для всього іншого. Пакети, що виходять зі старого джерела, означають проблему прив’язки. Пакети з нового джерела без відповіді означають далеку сторону або NAT посередині.
Занотуйте, яка подія збіглася з першою несправністю: падіння зв’язку, зміна адреси або зміна маршруту за замовчуванням. Вони вказують на різних відповідальних - клієнта, якого треба переприв’язати, адресу, яку треба отримати заново, або маршрут, що належить файлу конфігурації, а не постійному правилу обходу.
Перш ніж назвати це виправленим, підтвердьте, що блок прямого трафіку ще тримається під час розриву і що імена розв’язуються через нове підключення. Якщо клієнт тримає стару кінцеву точку після перемикання, спершу виправте налаштування роумінгу або float. Якщо він роумінг виконує правильно і все одно не отримує відповіді, подивіться на ідентичність партнера на сервері й NAT на шляху, і збережіть обидва мережеві контексти в записі, щоб наступна людина могла їх порівняти.