Отредактируйте /etc/iproute2/rt_tables, добавьте (или замените строки isp1/isp2, если уже добавляли):
100 domru 200 rt
Проверка:
grep -E "domru|rt$" /etc/iproute2/rt_tables
Создайте /etc/sysctl.d/99-multiwan.conf:
net.ipv4.conf.all.rp_filter = 2 net.ipv4.conf.default.rp_filter = 2
Применить:
sysctl --system
Проверка:
sysctl net.ipv4.conf.all.rp_filter
должно вернуть:
net.ipv4.conf.all.rp_filter = 2
Добавьте в /etc/nftables.conf таблицу маркировки:
nfttable inet mangle {
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
meta mark set ct mark
iifname "ppp0" ct mark == 0 ct mark set 0x1
iifname "ppp1" ct mark == 0 ct mark set 0x2
meta mark set ct mark
}
chain output {
type route hook output priority mangle; policy accept;
meta mark set ct mark
}
}
Проверьте синтаксис без применения, затем примените:
nft -c -f /etc/nftables.conf # только проверка nft -f /etc/nftables.conf # применение
Проверка:
nft list table inet mangle
#!/bin/bash LOG=/var/log/check_providers.log LAN_NET="192.168.0.0/16" LAN_DEV="eth0" log() { echo "--- $1" echo "$(date +'%Y-%m-%d %H:%M:%S') $1" >> "$LOG" } # правила ip rule для fwmark — создаём, если отсутствуют /usr/sbin/ip rule list | grep -q "fwmark 0x1 lookup domru" || \ /usr/sbin/ip rule add fwmark 0x1 table domru priority 100 /usr/sbin/ip rule list | grep -q "fwmark 0x2 lookup rt" || \ /usr/sbin/ip rule add fwmark 0x2 table rt priority 200 check_provider() { local IF=$1 TABLE=$2 METRIC=$3 /usr/sbin/ip a show dev "$IF" &> /dev/null if [ $? -ne 0 ]; then echo "--- интерфейс $IF не поднят" /usr/sbin/ip route flush table "$TABLE" 2>/dev/null return fi # маршрут по умолчанию в таблице main /usr/sbin/ip route show default | grep -q "$IF" if [ $? -ne 0 ]; then log "интерфейс $IF поднят, но маршрут по умолчанию отсутствует - восстанавливаем" /usr/sbin/ip route add default dev "$IF" scope link metric "$METRIC" fi # маршрут по умолчанию в таблице провайдера (ответный трафик) /usr/sbin/ip route show table "$TABLE" default 2>/dev/null | grep -q "$IF" if [ $? -ne 0 ]; then log "интерфейс $IF поднят, но в таблице $TABLE нет маршрута по умолчанию - восстанавливаем" /usr/sbin/ip route replace default dev "$IF" scope link table "$TABLE" fi # маршрут в локальную сеть в таблице провайдера /usr/sbin/ip route show table "$TABLE" | grep -q "$LAN_NET" if [ $? -ne 0 ]; then log "в таблице $TABLE нет маршрута в локальную сеть - восстанавливаем" /usr/sbin/ip route replace "$LAN_NET" dev "$LAN_DEV" table "$TABLE" fi } check_provider ppp0 domru 50 check_provider ppp1 rt 200
chmod +x /usr/local/sbin/check_providers.sh
/usr/local/sbin/check_providers.sh
Проверьте результат:
ip rule
Ожидается:
0: from all lookup local 100: from all fwmark 0x1 lookup domru 200: from all fwmark 0x2 lookup rt 32766: from all lookup main 32767: from all lookup default
ip r show table domru
default dev ppp0 scope link 192.168.0.0/16 dev eth0 scope link
ip r show table rt
default dev ppp1 scope link 192.168.0.0/16 dev eth0 scope link
Основная таблица должна остаться без изменений:
ip r
default dev ppp0 scope link metric 50 default dev ppp1 scope link metric 200 192.168.0.0/16 dev eth0 proto kernel scope link src 192.168.30.1
Проверка выбора маршрута для помеченного трафика:
ip route get 8.8.8.8 mark 0x1 # должен показать dev ppp0 ip route get 8.8.8.8 mark 0x2 # должен показать dev ppp1
Проверка меток на соединениях (пакет conntrack, если не установлен — apt install conntrack):
conntrack -L -o extended 2>/dev/null | grep -v "mark=0 "
Реальный тест: с внешнего хоста (телефон с мобильным интернетом, VPS) подключитесь к серверу по IP каждого провайдера — например SSH или проброшенный порт. Соединение через IP резервного провайдера (ppp1) должно работать, хотя основной default указывает на ppp0. До внедрения policy routing такое соединение не устанавливалось бы.
Создайте /etc/ppp/ip-up.d/check-providers:
bash#!/bin/bash /usr/local/sbin/check_providers.sh >/dev/null 2>&1
chmod +x /etc/ppp/ip-up.d/check-providers
Это закрывает окно между переподключением ppp-сессии и следующим запуском скрипта по cron: таблицы domru/rt восстановятся сразу при поднятии линка.