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: работа
October 27th, 2017 at 13:37
Привет,
Благодаря за готиното HOWTO! Мернах една печатна грешка $p => $t
for t in pesho gosho; do ip route add 192.168.0.0/24 dev eth7 table $p; done
Поздрави,
Добри
October 27th, 2017 at 13:51
@Добри, благодаря, поправих го :)
October 28th, 2017 at 12:45
thumbs up