Короткий ответ
Стек выбирает маршрут так: (1) самая длинная маска, которая покрывает цель (longest prefix match); (2) среди равных prefix — меньшая метрика / приоритет таблицы; (3) connected/on-link значит «ARP на этом NIC», не «через шлюз». Default 0.0.0.0/0 — самый короткий префикс, проигрывает любому 10.0.20.0/24. Не читайте route print сверху вниз как приоритет строк.
Проверка истины: Windows Find-NetRoute -RemoteIPAddress, Ubuntu ip route get. Якоря: LAN 10.0.10.0/24, gw 10.0.10.1, DNS 10.0.10.2.
Симптомы и как отличить
- Копия на
10.0.10.10внезапно идёт в VPN; - интернет через Wi‑Fi при воткнутом кабеле;
ping 10.0.20.10unreachable при «живом интернете».
Отличия: нет подходящего префикса — нет маршрута. Prefix врёт из-за маски — маска. Таблица верная, путь разный обратно — асимметрия.
Возможные причины
- Два default с разными метриками.
- VPN опубликовал
10.0.0.0/8и перебил LAN/24или наоборот недостаточно специфичен. - Persistent
route -pиз старой заявки. - Policy routing (fwmark) мимо main — таблица, которую вы смотрите, не та.
- Weak Host / несколько NIC, ответ не с того интерфейса.
Диагностика
1. Снять таблицу целиком
Get-NetRoute -AddressFamily IPv4 |
Sort-Object @{e={ [int]($_.DestinationPrefix -split '/')[1] }; Descending=$true}, RouteMetric |
Format-Table DestinationPrefix, NextHop, RouteMetric, ifIndex, InterfaceAlias
Get-NetIPConfigurationip route
ip -4 route show table all
ip ruleip rule важнее, чем кажется: lookup 220 у WireGuard/policy может обойти main.
2. Спросить стек про конкретный IP
Find-NetRoute -RemoteIPAddress 10.0.10.2 | Format-List
Find-NetRoute -RemoteIPAddress 10.0.20.10 | Format-List
Find-NetRoute -RemoteIPAddress 1.1.1.1 | Format-Listip route get 10.0.10.2
ip route get 10.0.20.10
ip route get 1.1.1.1Смотрите dev, via, src. via 10.0.10.1 — через шлюз. Нет via — on-link, будет ARP.
3. Longest prefix на пальцах
Цель 10.0.10.2:
| Префикс в таблице | Длина | Покрывает 10.0.10.2? |
|---|---|---|
| 0.0.0.0/0 | 0 | да |
| 10.0.0.0/8 | 8 | да |
| 10.0.10.0/24 | 24 | да |
| 10.0.10.2/32 | 32 | да |
Победит /32, иначе /24, не default. Поэтому host-маршрут на DNS важнее «широкого VPN /8».
Цель 10.0.20.10 при наличии только 10.0.10.0/24 и default: победит default via 10.0.10.1 (если шлюз умеет дальше). Если VPN дал 10.0.20.0/24 — он длиннее default и победит.
4. Метрика при равной длине
Два 0.0.0.0/0: Ethernet metric 25, Wi‑Fi 50 — кабель. Наоборот — «интернет уехал в Wi‑Fi». Windows: RouteMetric + InterfaceMetric. Ubuntu: metric в ip route.
Get-NetIPInterface -AddressFamily IPv4 | Format-Table InterfaceAlias, InterfaceMetric, ConnectionState5. On-link ловушка
10.0.0.0/8 connected на VPN-NIC: 10.0.10.1 могут пытаться ARP в туннель, не в LAN. Ping шлюза офиса умрёт. Лечится более специфичным 10.0.10.0/24 dev eth0 (обычно connected LAN сам /24 и побеждает /8). Если LAN почему-то /32 only — сломаетесь.
Сверьте ARP: Get-NetNeighbor 10.0.10.1 на каком InterfaceAlias.
Решение
Сценарий A. Нужен LAN, VPN слишком широкий
Добавьте split: 10.0.20.0/24 в туннель, не 10.0.0.0/8. LAN 10.0.10.0/24 должен остаться connected на eth.
Сценарий B. Два default
Поднимите InterfaceMetric кабеля выше (меньше число = предпочтительнее). Или отключите лишний адаптер на тесте.
Set-NetIPInterface -InterfaceAlias 'Ethernet' -InterfaceMetric 10
Set-NetIPInterface -InterfaceAlias 'Wi-Fi' -InterfaceMetric 50Сценарий C. Мусор persistent
Get-NetRoute -PolicyStore PersistentStore
Remove-NetRoute -DestinationPrefix '0.0.0.0/0' -NextHop 192.168.0.1 -Confirm:$falseТолько свой ошибочный next-hop.
Сценарий D. Добавить филиал на шлюзе, не на ПК
Клиенту достаточно default 10.0.10.1. Маршрут 10.0.20.0/24 живёт на 10.0.10.1.
6. Разбор на живых адресах лаборатории
Возьмите три цели: 10.0.10.2 (DNS в LAN), 10.0.20.10 (филиал), 1.1.1.1 (интернет). На здоровом ПК 10.0.10.10/24 gw 10.0.10.1 ожидайте: DNS on-link на Ethernet; филиал via 10.0.10.1 либо via VPN, если split так задуман; интернет via default. Если 10.0.10.2 via VPN — слишком широкий prefix туннеля, чините AllowedIPs. Если филиал on-link — маска /8 или /16. Два default: смотрите InterfaceMetric, не порядок строк route print. PersistentStore: старый 192.168.0.1 победит в командировке и в офисе — удалите. ip rule на Ubuntu: таблица 220 с более специфичным префиксом важнее main default; смотрите ip route get, не только ip route. Не учите коллег «верхняя строка главная». После VPN disconnect таблица должна вернуть LAN default без ручного route add. Проверка: три Find-NetRoute/ip route get, ping шлюза, traceroute филиала. Соседняя статья про отсутствие маршрута начинается там, где get уже unreachable.
Добавьте в шпаргалку: /32 > /24 > /16 > /8 > /0; метрика только при равной длине; NextHop 0.0.0.0 на Windows = on-link; не путать AD Cisco с метрикой хоста.
Как проверить, что проблема устранена
Find-NetRoute -RemoteIPAddress 10.0.10.2
Find-NetRoute -RemoteIPAddress 10.0.20.10
Find-NetRoute -RemoteIPAddress 1.1.1.1
ping -n 2 10.0.10.1
ping -n 2 10.0.10.2
tracert -d 10.0.20.10ip route get 10.0.10.2
ip route get 10.0.20.10
ip route get 1.1.1.110.0.10.2 — через LAN NIC, не VPN. Филиал — ожидаемый via. Интернет — default via 10.0.10.1 (или осознанный VPN). Повторите методику трёх инструментов.
Если не помогло
ip route getверный, пакеты всё равно не там — nft PBR/mark, смотритеip rule.- IPv6 default живой, IPv4 таблица «для галочки».
- Windows Hyper-V vEthernet default metric сюрприз.
- Multipath ECMP:
nexthopнесколько, hash делит потоки.
Профилактика
- Не публиковать
10.0.0.0/8в VPN без нужды. - Инвентаризация PersistentStore.
- Документ: какие prefix через какие if.
- Метрики NIC: кабель < Wi‑Fi, VPN по политике split.
FAQ
Почему в route print сверху 0.0.0.0, и все думают, что он главный?
Это default, он последний по длине. Windows группирует по сетевым маскам: сначала /32, потом /24… Читайте по маске, не по «первой строке».
/24 и /24 на двух NIC до одной сети?
Одинаковая длина — метрика и connected. Два интерфейса в один L2 без нужды — петля/непредсказуемость.
NextHop 0.0.0.0 в Windows?
On-link. Не «шлюз ноль».
ip route get vs ping как проверка?
get показывает выбор. Ping проверяет, что next-hop отвечает. Нужны оба.
Метрика 0 лучше 1?
Меньше — предпочтительнее. 0 на Linux часто connected. Не ставьте 0 на default вручную без понимания.
Нужно ли знать ADSC/administrative distance как в Cisco?
На хосте Windows/Ubuntu вы видите метрику ОС, не Cisco AD. На самом маршрутизаторе 10.0.10.1 — уже его таблица (OSPF/static distance). Не путайте route print ПК с show ip route ядра.