Почему маршрут VPN не показывает шлюз в выводе ip route
Строка с устройством и без шлюза — это прямой маршрут, а не сломанный. Прочитайте пункт назначения, dev и scope, затем подтвердите с помощью ip route get.
Таблицы маршрутизации часто читают как сломанные каждый раз, когда столбец шлюза остаётся пустым, хотя строка обычно полна сама по себе. Поле via появляется только тогда, когда ядро передаёт пакет адресу следующего перехода; маршрут, привязанный к интерфейсу, достигает своих пунктов назначения вместо этого через разрешение на канальном уровне или через партнёра точка-точка. Чтение столбцов слева направо говорит, в каком случае вы находитесь, и это чтение должно произойти до того, как кто-либо изменит маршрут по умолчанию. Большинство заявок о недостающем шлюзе заканчиваются на этом различии.
Читайте строку маршрута столбец за столбцом
Каждая запись начинается с пункта назначения и длины его префикса, затем добавляет модификаторы в фиксированном словаре: via, dev, proto, scope, src и metric. Строка вроде 198.51.100.0/24 dev tun0 proto kernel scope link src 198.51.100.2 плотна, но полностью определена. В ней ничего не отсутствует, и никакой адрес маршрутизатора не подразумевается.
Интересна именно нехватка via. Без следующего перехода ядро разрешает пункт назначения прямо на указанном интерфейсе, что для туннеля означает передачу кадра туннельному устройству и предоставление инкапсуляции действовать дальше. proto kernel фиксирует, что запись была установлена автоматически при назначении адреса, а не введена администратором. scope link говорит, что пункт назначения достижим на этом канале без прохождения через маршрутизатор, а src называет адрес, который ядро предпочтёт как источник для подходящего трафика.
Теперь прочитайте маршрут по умолчанию так же: default via 192.0.2.254 dev eth0 proto static metric 100. Здесь via присутствует, потому что пакету действительно нужен следующий переход, и этот переход сам должен быть достижим на eth0. Эти две строки не являются вариантами друг друга; они отвечают на разные вопросы о том, куда идёт трафик.
Две формы маршрута, которые путают между собой
Маршрут подсети туннеля и маршрут по умолчанию выглядят похоже на снимке экрана и ведут себя совершенно по-разному. Используйте таблицу ниже как подсказку для чтения полей, а затем подтвердите реальные числа на машине, которую отлаживаете, вместо того чтобы доверять примеру из руководства.
| Piece of the line | What it settles | What it says nothing about |
|---|---|---|
| The destination and mask | Which packets are eligible to match | Where those packets leave the host |
via plus its address | Which next hop receives them, and therefore that a router is involved | Whether that router is reachable or sane |
dev | Which interface carries the encapsulated or raw packet | Whether the interface is up or has a carrier |
proto and scope | Who installed the entry and how far the destination is considered to be | Whether a firewall later drops the traffic |
То, чего таблица не может сказать, — это намерение. Прямой маршрут в частный диапазон через туннель — это намеренный проект раздельного туннеля; та же форма на хосте, который должен отправлять всё через VPN, является симптомом. Намерение живёт в конфигурации, создавшей запись, поэтому посмотрите на инструмент, который её установил, прежде чем заключать, что ядро сделало что-то не так.
Точно так же отсутствующий шлюз не даёт разрешения его придумать. Если маршруту действительно нужен следующий переход, этот переход должен быть достижим на интерфейсе, который его несёт, а для туннеля точка-точка адрес партнёра — не тот же объект, что локальный адрес. Обращение с локальным адресом туннеля как с Ethernet-маршрутизатором — распространённый способ получить маршрут, который выглядит правильным и ничего не пересылает.
Спросите ядро, какую строку оно действительно использует
Чтение таблицы — не то же самое, что выполнение поиска, потому что перед ответом ядро обращается к правилам политики, нескольким таблицам и кэшированным записям. Глагол, выполняющий настоящий поиск, — ip route get, и он печатает маршрут, который выбрал бы пакет с такими свойствами.
ip route get 203.0.113.37 from 198.51.100.2 iif tun0
Подставьте пункт назначения, который действительно важен, затем добавьте from или iif, когда трафик выбран по источнику или пересылается, потому что обычный локальный поиск может выбрать другой путь, чем пересылаемый клиент. Ответ называет интерфейс, выбранный адрес источника и любой следующий переход, а это та же информация, с которой пакет был бы маршрутизирован в тот момент.
Если ответ вас удивляет, напечатайте правила до любых изменений: ip -4 rule show перечисляет их в порядке приоритета, а клиент VPN, который устанавливает собственную таблицу или правило для отмеченных пакетов, вообще не появится в основной таблице. Перечисление всех таблиц закрывает этот пробел.
ip -4 route show table all | grep -E 'tun|default'Проверьте нижележащий уровень, прежде чем заменять маршрут по умолчанию
Собственные пакеты туннеля должны достичь удалённой конечной точки, и делают это через физический интерфейс, используя маршрут, существовавший до поднятия VPN. Замена всего маршрута по умолчанию без закрепления этой конечной точки отправляет инкапсулированные пакеты в туннель, который они должны построить, и соединение рушится. Сначала подтвердите путь к конечной точке поиском только по её адресу.
Держите три вещи раздельно, когда вносите изменение: маршрут к конечной точке, который должен остаться на физическом интерфейсе, частные диапазоны, которые должны войти в туннель, и маршрут по умолчанию, который решает всё остальное. Разделите их в этом порядке, применяйте по одному и повторяйте поиск после каждого шага. Неудачный ping после этого сам по себе доказывает очень мало, поскольку разрешения, маршрутизация ответов, DNS и сам сервис находятся ниже правильного маршрута.
Запишите четыре значения, которые дала вам строка перед редактированием: пункт назначения, следующий переход или его отсутствие, устройство и выбранный источник. Если более позднее изменение сдвинет любое из них, вы знаете, какое решение было действительно изменено, и можете восстановить одну запись вместо того, чтобы угадывать всю таблицу.