Policy routing или раздаем инет через 2 или более интерфейсов (ipfw, pf) во FreeBSD



Настройка policy routing

В данной статье рассматривется тот случай, когда на сервере имеется два сетевых интерфейса через которые, в зависимости от тех или иных обстоятельств, будет идти трафик в интернет.
Сразу оговорюсь что в данный момент времени я использую pf, а примеры с использованием ipfw приведены учитывая прошлый опыт, поэтому могут быть не столь полными. Также я надеюсь что (в случае с ipfw) имеется опыт настройки natd и соответствующих правил. Для pf также приветствуется знание синтаксиса :).

В общем случаем конфигурация используется следущая:
rl0 - 10.10.10.254 (ip - шлюз провайдера №1, наш ip 10.10.10.10)
rl1 - 20.20.20.254 (ip - шлюз провайдера №2, наш ip 20.20.20.10)
rl2 - 30.30.30.30 (ip - адрес в локальной сети)

Приступим.
IPFW

Запускаем nat на интерфейсах:
natd -a 10.10.10.10 -p 8668
natd -a 20.20.20.20 -p 8778

Далее создаем правила для файрвола:
ipfw add divert 8668 ip from 30.30.30.100 to any
#в данном случае вместо 30.30.30.100 можно подставить ip тех кого пускать через данный интерфейс
#или вместо any написать то, куда люди будут ходить через данный интерфейс
ipfw add divert 8778 ip from 30.30.30.0/24 to any
#аналогично первому комментарию
#
#сам policy
ipfw add fwd 10.10.10.254 ip from 10.10.10.10 to any
ipfw add fwd 20.20.20.254 ip from 20.20.20.10 to any
#возвращаем пакеты
ipfw add divert 8668 ip from any to 10.10.10.10
ipfw add divert 8778 ip from any to 20.20.20.10

Привожу ещё один пример, в котором 1 пользователь ходит в сеть через первый канал и видит локальные ресурсы второго провайдера, а остальные наоборот:
ipfw add divert 8778 ip from 30.30.30.100 to 100.100.100.0/24
#100.100.100.0/24 внутренняя сеть провайдера номер 1
ipfw add divert 8668 ip from 30.30.30.100 to any
ipfw add divert 8668 ip from 30.30.30.0/24 to 110.110.110.0/24
##110.110.110.0/24 внутренняя сеть провайдера номер 2
ipfw add divert 8778 ip from 30.30.30.0/24 to any
ipfw add fwd 10.10.10.254 ip from 10.10.10.10 to any
ipfw add fwd 20.20.20.254 ip from 20.20.20.10 to any
ipfw add divert 8668 ip from any to 10.10.10.10
ipfw add divert 8778 ip from any to 20.20.20.10

Вот собственно и всё.

Дописать pbr для доступа к сервисам с внешних интерфейсов и динамические правила для ipfw
PF

Теперь pf, привожу кусок моего конфига:
(в данном случае возможно придется настроить обычную маршрутизацю, в зависимости от поставленной задачи)
#Внешние и внутренний интерфейсы.
#
ext_if_a = "rl0" #первый провайдер
ext_if_b = "rl1" #второй провайдер
int_if = "rl2" #локалка
#Шлюзы для каналов.
#
ext_gw_a = "10.10.10.254" #для tun0
ext_gw_b = "20.20.20.254" #для tun1
net = "30.30.30.0/24" #локалка
#TCP/UDP сервисы, обслуживаемые маршрутизатором, то к чему имеется доступ на внешних интерфейсах
#
tcp_svc = "990" #как пример, что то нужно вписать иначе будет биг ошибка :)
udp_svc = "6000" #аналогично
#Натим, важный момент, именно тут определяется кого куда пускать
#Синтаксис ната, грубо говоря, таков: nat on _интерфейс_ from _откуда_ to _куда_ -> _интерфейс_или_ип_адрес
#
nat on $ext_if_a from {$net} -> ($ext_if_a:0)
nat on $ext_if_b from {$net} -> ($ext_if_b:0)
#Разрешаем сети ходить в интернет, всё остальное блокируем
#
block in on { $ext_if_a $ext_if_b }
block return-rst in on { $ext_if_a $ext_if_b } proto tcp
pass out on { $ext_if_a $ext_if_b } keep state
#Исходящие пакеты в канал, соответствующий адресу источника. Здесь и начинается policy
#
pass out route-to ($ext_if_a $ext_gw_a) from ($ext_if_a) to !(self:network)
keep state
pass out route-to ($ext_if_b $ext_gw_b) from ($ext_if_b) to !(self:network)
keep state
#А вот policy для входящих пакетов на внешние интерфейсы
#
pass in on $ext_if_a reply-to ($ext_if_a $ext_gw_a) proto udp
to port { $udp_svc } keep state
pass in on $ext_if_a proto udp from ($ext_if_a:network) to port { $udp_svc }
keep state
#
pass in on $ext_if_a reply-to ($ext_if_a $ext_gw_a) proto tcp
to port { $tcp_svc } flags S/SA keep state
pass in on $ext_if_a proto tcp from ($ext_if_a:network) to port { $tcp_svc }
flags S/SA keep state
#
pass in on $ext_if_b reply-to ($ext_if_b $ext_gw_b) proto udp
to port { $udp_svc } keep state
pass in on $ext_if_b proto udp from ($ext_if_b:network) to port { $udp_svc }
keep state
#
pass in on $ext_if_b reply-to ($ext_if_b $ext_gw_b) proto tcp
to port { $tcp_svc } flags S/SA keep state
pass in on $ext_if_b proto tcp from ($ext_if_b:network) to port { $tcp_svc }
flags S/SA keep state

http://wiki.bsdportal.ru/doc:policy
Обновлено: 12.03.2015