2017-10-26 policy routing с Linux

by Vasil Kolev

В последно време на няколко места по различни случаи ми се налага да подкарвам policy routing под Linux, та тук мисля да систематизирам защо и как.

1) Какво е policy routing

Съвсем просто, routing, който не се базира САМО на destination IP адрес. В linux това се реализира чрез правила (rules), които на база на нещо решават да се гледа друга routing таблица, не стандартната.

2) Защо ни трябва

Основният use case е когато имаме два или повече default route-а, и искаме да можем за трафик, който е дошъл от единия да излизаме навън пак през него. Примерът, който ще дам по-долу е с два internet доставчика, но при мен се налага като конфигурирам bgp с някой, да слагам policy routing за адресите, които са на самия link да си излизат от верния интерфейс, за да мога да вляза от там, ако нещо се е ошашкало по bgp-то.

3) Как се настройва за крайна машина

Примерът, който ще дам е какво правим, ако имаме два доставчика, които ще кръстя pesho и gosho (ако искате, PeshoNet и GoshoCom).

pesho ви е дал link, на който имате адрес 10.1.1.30/24 с default gw 10.1.1.1 и сте го вързали на eth0, gosho ви е дал 10.2.2.40/24 с default gw 10.2.2.254 и сте го вързали на eth1.

Давам настройките директно с команди, как да интегрирате това в настройките на дистрибуцията си варира твърде много (мога да кажа, че в debian с pre-up и down директиви в interfaces файла може да се направи цялото нещо).

Ако просто ги настроите директно, routing таблицата ще изглежда по следния начин:

~ # ip r
default via 10.1.1.1 dev eth0
default via 10.2.2.254 dev eth1
10.1.1.0/24 dev eth0  proto kernel  scope link  src 10.1.1.30
10.2.2.0/24 dev eth1  proto kernel  scope link  src 10.2.2.40

Това никаква работа не върши, понеже ако отвън дойде пакет за 10.1.1.30, може да излезе от другия link и обратно, а това доставчиците никак не го обичат и филтрират. За това просто в тая таблица оставяте само единия от двата default-а и продължаваме нататък.

Първо, харесваме си числата 1 и 2, даваме 1 на pesho, 2 на gosho, и ги описваме в /etc/iproute2/rt_tables (там има и други неща, това са редовете за добавяне):


...
1 pesho
2 gosho
...

Смисълът от това е, че можем да пишем неща като ip r show table pesho вместо ip r show table 1.

Имайки тези таблици, ги попълваме с каквито пътища имаме:

ip route add 10.1.1.0/24 dev eth0 table pesho
ip route add default via 10.1.1.1 table pesho
ip route add 10.2.2.0/24 dev eth1 table gosho
ip route add default via 10.2.2.254 table gosho

И след това пишем самите правила:

ip rule add from 10.1.1.30 iif lo table pesho
ip rule add from 10.2.2.40 iif lo table gosho

Тук има нужда от малко обяснение – “iif lo” означава “идващи от локалната машина”, останалото е в общи линии просто – ако source адресът е този, гледай конкретната таблица.

До тук е setup-а, ако имате просто една машина и нищо повече…

4) Как се настройва при NAT

Какво правим, ако имаме отзад една мрежичка, да кажем стандартната 192.168.0.0/24, на eth7?

Като за начало, трябва да добавим тази мрежа и в другите две таблици:

for t in pesho gosho; do ip route add 192.168.0.0/24 dev eth7 table $t; done

(някой би написа командите, но ми се е налагало да правя това за 10 таблици и почва да става досадно)

Съответно, да речем, че си имате едни прости правила за nat, които казват, че маскирате трафика навън:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

и някакво правило, че имате някакво web сървърче навътре на 192.168.0.100 порт 8080:

iptables -t nat -A PREROUTING -d 10.1.1.30/32 -i eth0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.0.100:80
iptables -t nat -A PREROUTING -d 10.2.2.40/32 -i eth1 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.0.100:80

Тук за изходящите връзки, ако решите да смените през кой доставчик, съществуващите ще тръгнат да излизат през новия път (и няма да работят), а ако имате входящи от този, през който не ви е текущия default route, пак ще се опитват да излязат от грешното място, понеже маскирането се случва някъде след routing-а. Решението е т.нар. “CONNMARK”, с който може 1) да маркирате определени връзки, 2) маркировката да се пренася в/у пакетите, и после 3) по маркировката да решавате коя таблица да ползвате.

Това се случва в mangle:

iptables -t mangle -A PREROUTING -i eth0 -m conntrack --ctstate NEW -j CONNMARK --set-xmark 0x1/0xffffffff
iptables -t mangle -A PREROUTING -i eth1 -m conntrack --ctstate NEW -j CONNMARK --set-xmark 0x2/0xffffffff
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff

Тези неща се превеждат като “по единия интерфейс маркирай с 1, по другия с 2, на вход сипвай маркировката от connection-а в пакета (restore-mark), на изход сипвай от пакета на connection-а” (взех ги от един готов save-нат iptables, за това са с тия пълни маски, мисля, че по принцип не бяха нужни). Другото, което трябва е да добавим routing правила, които да взимат решение коя таблица се гледа:

ip rule add fwmark 0x1 table pesho
ip rule add fwmark 0x2 table gosho

5) Load balancing, failover, такива неща

Това е голяма гадост. Писал съм преди по темата за fail-over,като изключим gwping-а и може би една добавка ако той сменя връзката, понеже е умряла, да трепе всичкия state в conntrack-а, няма какво да добавя.

За load balancing бих препоръчал нещо сравнително статично, определени неща през единия доставчик и други през другия, с нещо, което ги трие, когато изпадне единия доставчик. Бях провеждал експеримент в initLab да правя 2 connection-а през единия доставчик и един през другия или някакви такива неща, резултатът беше доста неприятен.

Tags:

3 Responses to “2017-10-26 policy routing с Linux”

  1. Добри Стефанов Says:

    Привет,

    Благодаря за готиното HOWTO! Мернах една печатна грешка $p => $t

    for t in pesho gosho; do ip route add 192.168.0.0/24 dev eth7 table $p; done

    Поздрави,
    Добри

  2. Vasil Kolev Says:

    @Добри, благодаря, поправих го :)

  3. vladimir Says:

    thumbs up

Leave a Reply