Назад
# Пример использования policy routing. Tags: linux, network Policy routing - способ в linux управлять маршрутизацией пакетов на основе различных правил, таких как src-адрес, маркировка пакета, поля TOS(тип сервиса), входящего интерфейса и других параметров, а не только dst-адреса ip пакета. Например, ваш роутер подключен к 2 провайдерам. Самый простой способ (до появления policy-routing'а) распределить на основе dst-адреса: ``` # важный трафик к youtube пускаем через отдельный канал ip route add 173.194.220.91 via x.x.x.x dev eth0 ip route add default via y.y.y.y dev eth1 ``` Самый практичный способ - это распределить трафик между двумя аплинками на основе весов. Например, если скорость одного провайдера в 2 раза выше, то это можно сделать так (способ на чистом iproute2): ``` ip route add default scope global nexthop via x.x.x.x dev eth0 weight 67 \ nexthop via y.y.y.y dev eth2 weight 33 ``` При этом маршруты будут кешироваться, чтобы пакеты из одного соединения не шли через разные ip адреса. Работать должно как для форвардинга, так и для обычного исходящего трафика и NAT. (Только непонятно что будет при подключени к этому роутеру из вне, уйдет ли ответный пакет с того же интерфейса, с которого пришел запросный) Самый универсальный способ - использовать маркировку fwmark в iptables. Уж в iptables пакеты можно промаркировать как вам заблагорассудится. Пример маркировки: ``` iptables -A PREROUTING -i eth0 -t mangle -p tcp --dport 25 -j MARK --set-mark 1 ip rule add from 10.0.0.0/8 fwmark 1 table uplink1 ``` Еще один способ - распределить полосы по пользователям (подходит если кому-то нужен выделенный канал или если вас не волнует полная утилизация каналов). Для NAT не подойдет. Здесь нужно применить policy-routing: ``` ip rule add from x.x.x.x table uplink1 ip route add default via y.y.y.y dev eth0 ip route add default via z.z.z.z dev eth1 table uplink1 ``` Именно этот вариант я расскажу подробнее, т.к. мы его применяем у себя в офисе. #### Как мы это используем Есть у нас роутер для офиса, к нему подведен аплинк провайдера (аплинк1). Скорость нас не очень устраивала, но у нас был еще один аплинк со скоростью получше для выделенного сервера(аплинк2). Решили, чтобы видяшки с youtube не забивали нам весь канал, пустить весь офисный трафик через аплинк2, но критичные сервисы, типа ip телефонии, оставить на аплинке1. Получилась примерно такая картина: ``` ip route add
via
dev eth0 ip route add default via
``` Ip аплинка2 - это адрес сервера. На нем был настроен NAT. Появилась проблема: стало невозможно подключиться к роутеру по его внешнему ip. Он просто посылал ответные пакеты через default-маршрут, через аплинк2. Кеши маршрутов не срабатывали, в кеше оказывался маршрут через аплинк2, а хотелось чтобы кеш заполнялся по входящему пакету - но это так не работает. Помог policy-routing: ``` ip rule add from
table uplink1 ip route add default via
dev eth0 table uplink1 ``` Т.е. мы создаем правило, что для пакетов с нашего локального адреса искать маршрут нужно в таблице uplink1, где default маршрут прописан правильно. #### Как это настроить в CentOS Заводим таблицы роутинга в файле /etc/iproute2/rt_tables: ``` # # reserved values # 255 local 254 main 253 default 0 unspec # # local # 200 uplink1 ``` В каталоге /etc/sysconfig/network-scripts/ настраиваем интерфейсы. Настраиваем интерфейс (у нас это туннель) до сервера в ifcfg-tun0: ``` DEVICE=tun0 TYPE=IPIP ONBOOT=yes MTU=1400 MY_OUTER_IPADDR= PEER_OUTER_IPADDR=x.x.x.x MY_INNER_IPADDR=y.y.y.y/24 PEER_INNER_IPADDR= # не работает для tun GATEWAY=y.y.y.z # не работает для tun DEFROUTE=yes ``` Прописываем в файле route-tun0 ``` default via <адрес сервера в туннеле> ``` На данный момент, весь трафик идет через туннель до сервера и далее в аплинк2. Настраиваем роутинг для аплинка1 в route-eth0: ``` default via
dev eth0 table uplink1
via
dev eth0 ``` Прописываем правила policy-routing в rule-eth0: ``` # Для пакетов с локального адреса ищем маршруты в таблице uplink1 from
table uplink1 # Спец.сеть, которая тоже ходит через uplink1 from 10.170.0.0/16 table uplink1 ``` Готово. И ssh на адрес eth0 работает! > Если возникают проблемы, попробуйте отключить rp_filter. > > Когда используется схема с несколькими таблицами маршрутизации, может возникнуть проблема с доставкой пакета от одного из аплинков на белый адрес (c NAT такой проблемы быть не должно) в локальной сети. Проблема в том, что когда приходит пакет, к нему применяется основная таблица маршрутизации, в которой может не быть маршрута из дополнительной таблицы маршрутизации, где находятся маршруты этого аплинка. В таком случае при включённом reverse path filtering (по умолчанию), пакет будет отброшен, т. к. интерфейс, через который он пришёл, не соответствует тому, через который происходила бы отправка в обратную сторону. > Спасибо хорошему описанию этой проблемы [на хабре](https://habr.com/ru/post/279777/#comment_10177604) #### Проблемы Основная проблема сейчас, что не настроен механизм автоматического fallback, если сервер или аплинк2 недоступны. Приходится вручную переключать default route на аплинк1. Но об этом как-нибудь в другой раз.