Настройка маршрутизации между несколькими сетевыми интерфейсами в Linux: практическое руководство 2026 | AdminWiki

Настройка маршрутизации между несколькими сетевыми интерфейсами в Linux: практическое руководство 2026

22 сентября 2026 13 мин. чтения
Содержание статьи

Два и более сетевых интерфейса на одном хосте ломают маршрутизацию из-за конкуренции маршрутов, а не из-за ошибки ядра. Когда на eth0 и eth1 одновременно появляется маршрут по умолчанию, Linux выбирает один из них и отправляет туда весь трафик, для которого нет более точного совпадения. Пакеты приходят на один интерфейс, ответы уходят через другой, и TCP-соединение рассыпается, хотя ping может отвечать.

Решение опирается на три механизма. Метрики разводят одинаковые маршруты по приоритету, отдельные таблицы маршрутизации вместе с правилами ip rule привязывают выбор пути к адресу источника, а параметр rp_filter перестаёт отбрасывать пакеты, когда асимметрия становится штатной схемой. Дополнительно нужно сохранить конфигурацию после перезагрузки, иначе после reboot хост вернётся к тому же поведению.

Ниже: алгоритм выбора маршрута, точный синтаксис ip route add и ip route replace с метрикой, режимы rp_filter, source-based routing, схемы для двух провайдеров, внутренней сети и VPN, а также диагностика через ip route get, tcpdump и conntrack. Команды приведены в синтаксисе iproute2 и не требуют устаревшей утилиты route.

Почему Linux путает маршруты при нескольких интерфейсах

Ядро принимает решение о маршруте для каждого пакета отдельно, опираясь на таблицы маршрутизации и правила ip rule. С одним интерфейсом результат всегда одинаков. С двумя и более интерфейсами, на которых есть маршрут по умолчанию, появляется конкуренция: подходящих записей несколько, и выбор зависит от длины префикса, метрики и порядка добавления записей в таблицу.

Как Linux выбирает маршрут: longest prefix match и metric

Порядок принятия решения выглядит так:

  1. Longest prefix match. Побеждает запись с самым длинным совпадающим префиксом. Маршрут 10.20.0.0/16 выигрывает у 10.0.0.0/8, а оба они выигрывают у 0.0.0.0/0.
  2. Metric. Если префиксы одинаковы, сравниваются метрики. Меньшее значение означает более предпочтительный маршрут.
  3. Равные метрики. При одинаковом префиксе и одинаковой метрике результат зависит от порядка появления записей и состояния интерфейсов, поэтому предсказуемым его назвать нельзя.

Текущее состояние показывает команда ip route show. Типичный вывод сервера с двумя аплинками:

default via 192.168.1.1 dev eth0 proto dhcp metric 100
default via 10.10.0.1 dev eth1 proto static metric 200
10.10.0.0/24 dev eth1 proto kernel scope link src 10.10.0.5

В такой конфигурации весь внешний трафик уйдёт через eth0: у маршрута метрика 100 против 200. Если метрики убрать, обе записи получат одинаковый вес, и выбор станет зависимым от момента добавления.

Значение метрики по умолчанию определяется тем, кто добавил запись. Маршруты к подключённым подсетям и статические записи без параметра metric получают метрику 0. В NetworkManager значение ipv4.route-metric по умолчанию равно -1: это означает автоматический выбор метрики на основе типа устройства, и такая метрика применяется к динамическим маршрутам (включая полученные по DHCP), к статическим маршрутам без явной метрики, к маршрутам префиксов адресов и к маршруту по умолчанию (nm-settings(5)). Отдельно учтите поведение IPv6: ядро принимает значение 0, но приводит его к 1024, поэтому установка свойства в ноль фактически означает 1024; для IPv4 ноль остаётся обычным значением (nm-settings(5)). Точные числа смотрите в выводе ip route show: они зависят от дистрибутива, версии пакета и настроек соединения.

Типичные симптомы: потеря пакетов, неверный интерфейс, асимметрия

  • ping до узла проходит, а TCP-сессия зависает на установке или рвётся после первого ответа.
  • Входящие пакеты видны на одном интерфейсе, ответы уходят через другой.
  • tcpdump фиксирует SYN, пришедший на eth1, и отсутствие SYN-ACK в обратном направлении.
  • В dmesg появляются строки вида martian source 10.0.0.5 on eth0 с указанием адреса, не соответствующего входному интерфейсу.

Причины обычно сводятся к трём: неверный маршрут по умолчанию, асимметричная маршрутизация или строгий rp_filter, отбрасывающий входящие пакеты с несовпадающим обратным маршрутом. Диагностический набор команд:

ip route get 8.8.8.8
ip route get 10.1.5.7 from 192.168.2.5
tcpdump -i any -n host 8.8.8.8
conntrack -L | head

Команда ip route get отвечает на конкретный вопрос: какой маршрут, через какой интерфейс и с каким адресом источника ядро выберет для этого получателя. Если src не совпадает с адресом интерфейса, на который физически пришёл запрос, проблемы с ответом гарантированы.

Выбор маршрута по умолчанию и управление метриками

Приоритетный маршрут по умолчанию задаётся метрикой. Меньшая метрика означает, что именно эта запись будет выбрана для всего трафика без более точного совпадения.

Как задать метрику для default route

ip route add default via 192.168.1.1 dev eth0 metric 100
ip route replace default via 192.168.1.1 dev eth0 metric 100
ip route del default via 10.10.0.1 dev eth1

Команда ip route add возвращает ошибку RTNETLINK answers: File exists, если маршрут с таким префиксом в этой таблице уже есть. Команда ip route replace перезаписывает существующую запись и удобна в скриптах переключения канала. Команда ip route del удаляет запись; указывайте шлюз и интерфейс, чтобы не снять лишний маршрут.

Настройка на дисках зависит от сетевого менеджера. В NetworkManager метрика задаётся параметром ipv4.route-metric, в systemd-networkd ключом Metric= в секции [Route], в ifupdown строкой up ip route add ... metric N в файле /etc/network/interfaces. Проверить, кто управляет интерфейсом, помогает команда systemctl status NetworkManager systemd-networkd --no-pager.

Приоритет маршрутов: что важнее - metric или префикс

Префикс важнее метрики. Ядро сравнивает метрики только среди записей с одинаковой длиной префикса, поэтому более точный маршрут перебивает маршрут по умолчанию независимо от значения metric.

ip route add 10.0.0.0/8 via 10.10.0.1 dev eth1 metric 500
ip route add default via 192.168.1.1 dev eth0 metric 1

Трафик к адресу 10.1.2.3 уйдёт через eth1, хотя у маршрута метрика 500: префикс /8 специфичнее, чем /0, а метрика 1 у default route на этот выбор не влияет.

Таблица main с номером 254 используется по умолчанию, таблица local с номером 255 хранит маршруты к собственным адресам хоста. Ядро проходит по цепочке правил: правило с приоритетом 0 обращается к local, правило 32766 к main, правило 32767 к таблице default. Полный порядок выводит ip rule show.

Базовые операции со статическими маршрутами и метриками разобраны в руководстве по ip route, таблицам и статическим маршрутам. Сбои с выбором шлюза и конфликтами записей описаны в материале про маршрут по умолчанию и ошибки gateway.

Асимметричная маршрутизация и rp_filter: как не терять пакеты

Маршрутизация становится асимметричной, когда путь запроса и путь ответа проходят через разные интерфейсы. Для сервера с двумя аплинками это штатная ситуация, но она разбивается о проверку обратного пути в ядре.

Что такое rp_filter и когда он блокирует трафик

Параметр rp_filter (reverse path filtering) заставляет ядро искать обратный маршрут к адресу источника каждого входящего пакета. В строгом режиме со значением 1 маршрут обязан указывать на тот же интерфейс, с которого пакет пришёл. Если запрос пришёл на eth1, а таблица маршрутизации отправляет ответ через eth0, пакет отбрасывается до того, как его увидит приложение, а в dmesg появляется строка про martian source.

Эффективное значение для интерфейса определяется как максимум из net.ipv4.conf.all.rp_filter и net.ipv4.conf.интерфейс.rp_filter: именно максимум из conf/{all,interface}/rp_filter используется при проверке источника на этом интерфейсе (IP Sysctl — The Linux Kernel documentation). Поэтому снять проверку на одном интерфейсе не получится, если параметр all остался на единице. Значение по умолчанию — 0, но некоторые дистрибутивы включают rp_filter сами, так что проверяйте фактическое состояние; при асимметричной маршрутизации рекомендуется loose-режим (IP Sysctl — The Linux Kernel documentation). Проверка текущих значений:

sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.eth1.rp_filter

Настройка rp_filter: строгий, loose и отключение

Значение 0 выключает проверку, 1 включает строгий режим, 2 включает loose mode. В loose mode ядро проверяет, что обратный маршрут существует хотя бы через какой-то интерфейс, и не требует совпадения с входным. Для сервера с несколькими аплинками и при асимметричной маршрутизации это рекомендуемый компромисс.

sysctl -w net.ipv4.conf.all.rp_filter=2
sysctl -w net.ipv4.conf.default.rp_filter=2
sysctl -w net.ipv4.conf.eth1.rp_filter=2

Для сохранения после перезагрузки создайте файл /etc/sysctl.d/99-routing.conf с теми же строками без префикса sysctl -w и примените его командой sysctl --system.

Полное отключение со значением 0 снимает защиту от спуфинга адресов источника: узел сможет отправить пакет с чужим IP, и ядро не отбросит его на входе. Понижайте значение до нуля точечно, на конкретном интерфейсе, когда loose mode не помогает.

Source-based routing: маршрутизация по источнику

Source-based routing убирает асимметрию без отключения rp_filter: ответ уходит через тот же интерфейс, с которого пришёл запрос, потому что выбор маршрута привязан к адресу источника, а не только к адресу получателя.

Создание отдельной таблицы маршрутизации

echo '100 eth1' >> /etc/iproute2/rt_tables
ip route show table 100
ip rule show

Файл /etc/iproute2/rt_tables связывает номер таблицы с понятным именем, команды работают и с числом. Номера 0 (unspec), 253 (default), 254 (main) и 255 (local) зарезервированы, поэтому для своих таблиц берите значения из диапазона 1-252. Параметр ip route show table 100 удобен для проверки, что в новой таблице действительно есть нужные записи.

Правила ip rule для выбора таблицы по источнику

ip route add 192.168.2.0/24 dev eth1 scope link table 100
ip route add default via 192.168.2.1 dev eth1 table 100
ip rule add from 192.168.2.0/24 table 100 pref 100
ip rule del from 192.168.2.0/24 table 100

Ключ pref задаёт приоритет правила: чем меньше число, тем раньше правило проверяется. Маршрут по умолчанию нужно добавить в таблицу 100 отдельно, иначе для внешних адресов там не окажется совпадения и ядро вернётся к следующему правилу. Запись scope link для подключённой подсети страхует от ситуации, когда таблица не наследует локальные маршруты из main.

Готовые схемы привязки трафика к интерфейсу, подсети или метке fwmark собраны в статьях профиль маршрутизации для нескольких интерфейсов и policy routing на сервере с проверкой через ip route get и tcpdump.

Практические сценарии для серверов с несколькими аплинками

Два аплинка: failover и балансировка

Переключение при отказе строится на разных метриках: основной канал с metric 100, резервный с metric 200. Пока существует запись с меньшей метрикой, весь внешний трафик идёт через неё.

Автоматического переключения при молчащем провайдере не произойдёт. Если кабель вынут или линк опущен, ядро убирает связанные маршруты и начинает работать запись с метрикой 200. Если линк поднят, а внешний узел не отвечает, таблица не меняется: нужен внешний контроль (keepalived, скрипт с проверкой доступности и ip route replace) или маршрутизирующий демон вроде FRR и BIRD с BFD.

Распределение трафика между каналами делают через equal-cost multipath:

ip route add default scope global nexthop via 192.168.1.1 dev eth0 weight 1 nexthop via 10.10.0.1 dev eth1 weight 1

Ядро распределяет потоки по хешу из адресов и портов, поэтому одна TCP-сессия целиком уходит в один канал. Побочный эффект: асимметрия становится постоянной, заранее настройте rp_filter=2 или source-based routing. В схемах с NAT балансировка даёт рваные соединения, если у каналов разные внешние адреса.

Внутренняя сеть и внешний интерфейс

Схема: eth0 смотрит в интернет и держит default route, eth1 обслуживает внутреннюю сеть. Для внутреннего диапазона достаточно точного маршрута:

ip route add 10.0.0.0/8 via 10.10.0.1 dev eth1

Исходящие запросы во внутреннюю сеть после этого работают. Обратный трафик от внутренних клиентов потребует source-based routing, если ядро выбирает для ответа адрес из внешнего диапазона. Проверить фактический путь помогают ip route get 10.1.5.7 и ip route get 10.1.5.7 from 192.168.2.5: во втором случае видно, какой интерфейс выбран для ответа конкретному источнику.

VPN и политика маршрутизации

ip route add 172.16.0.0/12 dev tun0
ip route add default via 10.10.0.1 dev eth1 table 200
ip rule add from 172.16.5.10 table 200 pref 200

Маршрут по умолчанию через eth0 остаётся нетронутым, в туннель уходит только указанный диапазон. Если вы настраиваете WireGuard через wg-quick и указываете маршрут по умолчанию, утилита добавляет правила политики: ip -4 rule add not fwmark 51820 table 51820 и ip -4 rule add table main suppress_prefixlength 0, а также маршрут ip -4 route add 0.0.0.0/0 dev wg0 table 51820 (Wg-quick Default Firewall Rules | Pro Custodibus). Номер таблицы и метка совпадают: 0xca6c — это 51820 в шестнадцатеричном виде (Understanding modern Linux routing (and wg-quick)). Такая схема защищает собственный трафик туннеля от заворота в него же. Если ответы из туннеля приходят на другой интерфейс, проверьте rp_filter для tun0 или wg0 и при необходимости переведите интерфейс в loose mode.

Диагностика и устранение конфликтов маршрутов

Команды для проверки текущих маршрутов и правил

ip route show
ip route show table all
ip rule show
ip -s route show
ip route get 8.8.8.8
ip neigh
ss -tnp

Команда ip route show выводит таблицу main, а ip route show table all показывает все таблицы, включая созданные вручную. Команда ip -s route show добавляет счётчики использования записей: если по нужному маршруту трафик не идёт, счётчик остаётся нулевым, и это прямое указание, что правило или таблица выбраны неверно. Команда ip rule show полезна для проверки порядка правил, ip neigh показывает состояние ARP-таблицы, ss -tnp связывает проблемный сокет с процессом.

Для разбора трафика применяйте tcpdump с фильтром по узлу и флагам пакетов, а для проверки, дошёл ли пакет до приложения, состояние соединений из conntrack. Счётчики интерфейсов и ошибок удобно смотреть через ip -s link show.

Типичные ошибки и способы их исправления

  1. Одинаковые метрики у маршрутов по умолчанию на двух интерфейсах. Решение: развести метрики значениями 100 и 200 или перейти на ECMP с явным weight.
  2. Отсутствие source-based routing при двух аплинках. Симптом: ответы уходят не в тот канал. Решение: отдельная таблица и правило ip rule add from ... table ...
  3. Строгий rp_filter=1 при асимметрии. Симптом: martian source в dmesg, SYN без ответа. Решение: перевести all и проблемный интерфейс в loose mode со значением 2.
  4. Правила ip rule и маршруты не сохранены после перезагрузки. Решение: перенести конфигурацию в systemd-networkd, NetworkManager или скрипт в /etc/network/if-up.d/.
  5. Устаревшие записи conntrack после смены маршрута. Решение: conntrack -F для полного сброса или conntrack -D -d адрес для выборочного удаления. Учтите, что сброс всей таблицы разрывает активные сессии.
  6. Нет маршрута к подключённой подсети в дополнительной таблице. Решение: добавить запись с флагом scope link в ту же таблицу.

Сохранение настроек после перезагрузки

Команды ip route и ip rule действуют до перезагрузки или до перезапуска сетевого менеджера. Синтаксис iproute2 стабилен, и команды ip route add, ip route replace и ip rule add одинаково работают на ядрах 6.x; перед работой в продакшене сверяйте поведение на тестовом хосте, поскольку значения по умолчанию у сетевых менеджеров отличаются.

Настройка через systemd-networkd

Файл /etc/systemd/network/10-eth1.network с маршрутом и правилом политики:

[Match]
Name=eth1

[Network]
Address=192.168.2.5/24

[Route]
Gateway=192.168.2.1
Metric=200

[RoutingPolicyRule]
From=192.168.2.0/24
Table=100

Применение и проверка: systemctl enable --now systemd-networkd, затем systemctl restart systemd-networkd и networkctl status eth1. Секция [RoutingPolicyRule] в systemd.network принимает набор настроек, и для нескольких правил указывают несколько таких секций (systemd.network(5) — Arch manual pages). Поддержка policy routing появилась в systemd 235, поэтому секцию можно использовать, если версия systemd 235 или выше; на более старых сборках правило придётся добавлять скриптом рядом с интерфейсом (iproute2 — How to do policy routing with systemd? — Server Fault).

Настройка через NetworkManager

nmcli con mod eth1 ipv4.routes '10.0.0.0/8 10.10.0.1'
nmcli con mod eth1 ipv4.route-metric 200
nmcli con mod eth1 +ipv4.routing-rules 'priority 100 from 192.168.2.0/24 table 100'
nmcli con up eth1

Изменения вступают в силу после повторного поднятия соединения. Результат проверяйте командой nmcli -f ipv4.routes,ipv4.route-metric,ipv4.routing-rules con show eth1, а затем контрольным ip rule show и ip route show table 100.

В Debian и Ubuntu со старым ifupdown строки вида up ip route add ... metric N в /etc/network/interfaces ещё работают, но при наличии netplan или systemd-networkd конфигурация будет перезаписана менеджером. Выбирайте один инструмент на хост, чтобы маршруты и правила не дублировались и не конфликтовали. Краткая шпаргалка с командами ip route, iptables и policy routing собрана в материале базовая настройка маршрутизации трафика в Linux.

Перед изменениями на рабочем сервере снимите текущее состояние командами ip route show table all, ip rule show и ip -s link show, сохраните вывод и меняйте по одной записи за раз. Такой порядок позволит вернуть конфигурацию пошагово, если после очередного правила часть соединений перестанет устанавливаться.

Поделиться:
Сохранить гайд? В закладки браузера