Некий PBR - FreeBSD + pf

Простые/общие вопросы по UNIX системам. Спросите здесь, если вы новичок

Модераторы: vadim64, terminus

Правила форума
Убедительная просьба юзать теги [cоde] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
sudo
мл. сержант
Сообщения: 132
Зарегистрирован: 2011-02-05 10:54:11

Некий PBR - FreeBSD + pf

Непрочитанное сообщение sudo » 2011-02-05 11:17:16

Не знаю, может кому конечно и пригодится, но к сожалению не нашел где оставить статью.
Решение достаточно простое и по моему даже "статьи" не стоит.
Меня больше интересует кривизна моих рук. Иными словами ваше мнение.

Есть 2 интернет канала - первый дорогой, лимитный и стабильный, второй - дешевый, безлимитный, но несколько нестабильный. Эти каналы обеспечивают 2 маршрутизатора - Cisco 2600XM и Draytek Vigor2910VG. За маршрутизаторами стоят внешние (если их так можно назвать) сервера, смотрящие в Интернет внешними интерфейсами, соответственно внутренними в подсеть. Изнутри создать некий FailOver канал большого труда не составило - весь HTTP, FTP и т.п. трафик изнутри гнался по умолчанию через шлюз, который в случае падения своего default-router'a автоматически переключался скриптом, основной смысл имеющий:

Код: Выделить всё

route delete default 192.168.0.2
route add default 192.168.0.1
или еще проще

Код: Выделить всё

route change default 192.168.0.1
и потом обратно, в случае восстановления безлимитного канала.

Примерно то же самое происходило и с остальными серверами. Здесь все просто. Вопрос встал в другом - а как тогда быть с обращениями извне на сервера, учитывая, что их внешних несколько. и соответственно оба канала должны одинаково обеспечивать доступность внешних сервисов (HTTP/S, SMTP, IMAP и т.д. и т.п.) .

Схема значит такая:

router_1 (канал лимитный) - обеспечивает работу внешних служб серверов.
router_2 (канал безлимитный) - обеспечивает интернетами людей.

Оба маршрутизатора воткнуты в отдельный VLAN коммутатора Cisco Catalyst 2950 вместе с внешними интерфейсами серверов.

Задача - что-бы при падении одного из каналов и сервера оставались доступными извне и люди довольными. Людьми и доступными изнутри серверами на "выход" уже понятно, разобрались.
Чтобы не нагружать количеством демонов, протоколов, Jail'ов, допустим у нас 2 канала и 2 сервера со службами:

server_1 = SSH-сервер, имеющий шлюз (default_gateway в rc.conf) router_1
server_2 = WEB-сервер со шлюзом (default_gateway в rc.conf) router_2

router_1 (WAN интерфейс) = 1.1.1.1
router_2 (WAN интерфейс) = 2.2.2.2

router_1 (LAN интерфейс) = 192.168.0.1
router_2 (LAN интерфейс) = 192.168.0.2

server_1 (WAN интерфейс) = 192.168.0.3
server_2 (WAN интерфейс) = 192.168.0.4

Сначала возникла мысль просто тупо пробросить порт. к примеру, на router_1, что-то типа:

Код: Выделить всё

ip nat inside source static tcp 192.168.0.4 80 1.1.1.1 80 extendable
Но эту глупую затею оставил сразу же. Ибо если вспомнить основы TCP/IP, то:
Клиент, устанавливающий соединение, посылает пакет с флагом SYN и ждет от сервера ответа - либо пакет с флагом SYN+ACK, что будет расцениваться клиентом, как удавшееся соединение, либо пакет с флагом RST, после которого клиент, получивший отказ разрывает соединение.

Что получится, если я посылаю пакет на WAN-интерфейс router_2 с запросом на соединение по SSH на 22 порт, где правила port-forwarding'а будут пернаправлять пакет на server_1 ? server_1 ответит пакетом SYN+ACK, но направит его через свой указанный default_gateway, а именно через router_2. В итоге этот пакет зарубится сразу же, а клиент вылетит по таймауту коннекта. И тем самым, естественно часть внешних сервисов серверов будет недоступна. Будут доступны только сервисы, находящиеся на тех серверах, у которых указан рабочий шлюз.

Немного погуглив с минут 10, так ничего толком и не нашел. Были некоторые напоминания про директивы route-to, reply-to, round robin в pf, но примеры не соответствовали моей задаче, во всяком случай вникать в очередной раз в скупой мануал OpenBSD Packet Filter большого желания не было.

В итоге поступил так:

Появилась мысль пробрасывать порты на маршрутизаторах не непосредственно на конечный пункт сервисов, а на сам сервер, который непосредственно имеет default_gateway данного роутера. Иными словами это выглядит как-то так:

Код: Выделить всё

rdr on $ExtIf inet proto tcp from any to ($ExtIf) port 22 -> 192.168.0.3 port 22
Да, это все прекрасно перебрасывалось на server_1 с router_2, но была небольшая проблема...Дело в том, что source address (адрес отправителя) при этом оставался исходным, т.е. адресом непосредственно клиента, в итоге server_1 снова не понимал, откуда ему пришел пакет и слал ответ через свой router_1. Что по сути повторило ситуацию с простым port-forwarding'ом на маршрутизаторах.

NAT ? NAT !

NAT подменит дейтаграмму IP-пакета source address на адрес непосредственно внешнего интерфейса server_2, в итоге мы имеем достаточно удобную и гибкую картину фильтрации, учитывая еще тот момент, что за маршрутизаторами сервера имеют свою "серую" подсеть + применим тегирование пакетов:

Код: Выделить всё

rdr on ($ExtIf) inet proto tcp from any to ($ExtIf) port 22 tag SSH_REDIRECT -> 192.168.0.3  port 22
nat on ($ExtIf) inet proto tcp from any to 192.168.0.3 port 22 tagged SSH_REDIRECT -> ($ExtIf) port 1024:65535

Что нам скажет tcpdump ?

server_2

Код: Выделить всё

[19:45 root@blackice /home/alex]# tcpdump -nettti pflog0 port 22
tcpdump: WARNING: pflog0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 96 bytes
000000 rule 16/0(match): pass in on xl0: x.x.x.x.56175 > 192.168.0.4.22:  tcp 12 [bad hdr length 16 - too short, < 20]
000028 rule 41/0(match): pass out on xl0: 192.168.0.4.61080 > 192.168.0.3.22:  tcp 28 [bad hdr length 0 - too short, < 20]
^C
2 packets captured
11 packets received by filter
0 packets dropped by kernel
server_1

Код: Выделить всё

[19:46 root@darkstar /home/alex]# tcpdump -nettti pflog0 port 22
tcpdump: WARNING: pflog0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 96 bytes
00:00:00.000000 rule 34/0(match): pass in on msk1: 192.168.0.4.16079 > 192.168.0.3.22:  tcp 28 [bad hdr length 0 - too short, < 20]
00:00:09.985336 rule 129/0(match): pass out on msk1: 192.168.0.3.60888 > 192.168.0.4.22:  tcp 28 [bad hdr length 0 - too short, < 20]

Ну правила типа на обоих серверах

Код: Выделить всё

pass in log on ... tagged SSH_REDIRECT ...
pass out log on ... tagged SSH_REDIRECT ...
я опущу, это и ежу понятно.
Тоже самое делаем и на server_2, только уже применяя к 80-му порту.
___________________________________
Не знаю, насколько красивым получилось данное решение, но факт остается фактом - сервера прекрасно обрабатывают запросы с обоих каналов.

P.S. Предлагающие BGP, OSPF - идут лесом в сад. Нужен был простой способ реализовать PBR, применимый к pf.
Последний раз редактировалось f_andrey 2011-02-05 16:44:04, всего редактировалось 1 раз.
Причина: Автору, выбирайте пожалуйста раздел соответствуюший тематике вашего сообщения.

Хостинговая компания Host-Food.ru
Хостинг HostFood.ru
 

Услуги хостинговой компании Host-Food.ru

Хостинг HostFood.ru

Тарифы на хостинг в России, от 12 рублей: https://www.host-food.ru/tariffs/hosting/
Тарифы на виртуальные сервера (VPS/VDS/KVM) в РФ, от 189 руб.: https://www.host-food.ru/tariffs/virtualny-server-vps/
Выделенные сервера, Россия, Москва, от 2000 рублей (HP Proliant G5, Intel Xeon E5430 (2.66GHz, Quad-Core, 12Mb), 8Gb RAM, 2x300Gb SAS HDD, P400i, 512Mb, BBU):
https://www.host-food.ru/tariffs/vydelennyi-server-ds/
Недорогие домены в популярных зонах: https://www.host-food.ru/domains/

Аватара пользователя
Alex Keda
стреляли...
Сообщения: 35198
Зарегистрирован: 2004-10-18 14:25:19
Откуда: Made in USSR
Контактная информация:

Re: Некий PBR - FreeBSD + pf

Непрочитанное сообщение Alex Keda » 2011-02-20 23:28:32

как-то сложно всё...
Убей их всех! Бог потом рассортирует...