Настройка multirouting в FreeBSD.
На FreeBSD, выступающей в качестве шлюза, помимо всего прочего имеется интерфейс re1 (192.168.203.14/26) и интерфейс re3 (192.168.91.4/24). Оба эти интерфейса имеют доступ к сети 192.168.91.0/24, но у каждого интерфейса эта сеть своя, т.е. это две сети в разном VRF. Необходимо организовать доступ к этим сетям так, что бы каждый интерфейс видел свою сеть.
Реализация
На FreeBSD это можно реализвать с помощью утилиты setfib (доступна с версии FreeBSD7). Для того, что бы реализовать поддержку multirouting, нужно пересобрать ядро с «options ROUTETABLES=2». На данный момент максимально поддерживается до 16 независимых таблиц маршрутизации, поэтому есть смысл подумать про запас.
FIB — forwarding information base или forwarding table, проще говоря таблица маршрутизации.
Все маршруты, которые задавались командой
# route add ...
попадают в fib 0 (по-умолчанию).
Для того, чтобы прописать маршрут в другую таблицу необходимо выполнить
# setfib 1 route add
У меня имеется 2 интерфейса, с маршрутами которых надо разобраться:
re1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=9b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM> ether 52:54:00:66:9d:3d inet 192.168.203.14 netmask 0xfffffff0 broadcast 192.168.203.15 media: Ethernet autoselect (100baseTX ) status: active re3: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=9b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM> ether 52:54:00:af:76:12 inet 192.168.91.4 netmask 0xffffff00 broadcast 192.168.91.255 media: Ethernet autoselect (100baseTX ) status: active
Проверяю таблицы маршрутизации. Таблица большая, а меня интересует только то, что касается сети 192.168.91.0/24 и сам интерфейс.
# netstat -rn
Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire ... 192.168.91.4 lo0 UHS 0 0 lo0 192.168.91.0/24 52:54:00:af:76:12 US 0 0 re3 ...
Теперь проверяю fib 1 маршруты
# setfib 1 netstat -rn
В нем по-умолчанию описаны все интерфейсы:
Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire 127.0.0.1 link#7 UH 0 0 lo0 192.168.0.0/16 192.168.203.1 UGS 0 3 re1 192.168.91.0/24 link#5 U 0 20 re3 192.168.203.0/28 link#3 U 0 0 re1
Теперь мне надо прояснить как все должно выглядеть в идеальном случае. Итак, fib 0 должна содержать все маршруты и интерфейсы, кроме re3. fib 1 наоборот должна содержать re1 (остальные, в том числе default — по необходимости)
При создании интерфейса re3 в fib 1 создается лишний маршрут — 192.168.91.0/24 (этот диапазон у меня описан в 192.168.0.0/16). Значит при описании статических маршрутов в rc.conf его нужно будет убивать.
Это можно сделать с помощью /etc/rc.local. Согласно /etc/rc.d/local, этот файл будет обрабатываться при загрузке.
Содержание /etc/rc.local:
#!/bin/sh setfib 1 route add 192.168.0.0/16 192.168.203.1 setfib 1 route delete 192.168.91.0/24
Теперь мне надо разобраться с входящим трафиком.
Допустим, что трафик идет с 192.168.91.2 на 192.168.203.14 через интерфейс re1 и соответственно должен уходить через этот же интерфейс. Однако, в соответствии с release-notes:
«A packet received on an interface for forwarding uses FIB #0.»
И там же сказано:
ipfw setfib fibnum
will make the matched packet use the FIB specified in fibnum. The rule processing continues at the next rule.
Значит мне в правилах ipfw надо прописать:
${fwcmd} add 25 setfib 1 ip from { 192.168.0.0/16 } to 192.168.203.14 in recv re1
Эта запись говорит о том, что пакеты, которые пришли из сети 192.168.0.0/16 на адрес 192.168.203.14 через интерфейс re1 должны использовать fib1 По идее с исходящими пакетами нужно делать тоже самое, однако я не до конца вкурил каким образом это работает. Например udp пакеты от ntp сервера с адреса 192.168.203.14 на адрес 192.168.91.2 уходили через re3, а должны через re1. Помогла следующая запись, но нужно это сделать через setfib, иначе при изменении шлюза придется прописывать его и в маршрутах и в правилах ipfw. А это не правильно.
${fwcmd} add 3013 fwd 192.168.203.1 ip from 192.168.203.14 to 192.168.0.0/16
Итого
Добавить в ядро поддержку multirouting, прописав «options ROUTETABLES=2»
Внести все необходимые записи в таблицы маршрутизации с помощью «setfib 0 route add …» и «setfib 1 route add»
Для того, что бы изменения вступали в силу при перезагрузке можно использовать «/etc/rc.local»
В правила firewall внести изменения для привязки пакетов, попадающих под условие к определенной fib
Проверка
Фокус заключается в том, что теперь ping 192.168.91.2 может идти либо через re1, либо через re3:
# setfib 0 ping 192.168.91.2
пойдет через таблицу маршрутизации по умолчанию (0), и соответственно через интерфейс re3
# setfib 1 ping 192.168.91.2
пойдет через первую таблицу маршрутизации, и соответственно через интерфейс re1
# tcpdump -i [interface] icmp
Покажет как бегают пакеты
для того чтобы не набирать каждый раз
# setfib 1 telnet [host]
в /etc/profile добавляю новые alias
t() { setfib 1 telnet $@ } p() { setfib 1 ping $@ }
Проверяю, что команды p и t работают как надо
sshd
Встала проблема в организации доступа по ssh через таблицу маршрутизации, отличной от 0 (по-умолчанию).
Попытка заставить работать это дело через ipfw с указанием setfib 1 на различные варианты пакетов ожидаемого результата не принесло. (возможно, плохо курил, ибо по идее это должно решаться именно там)
Решение заключается в том, что я запускаю два sshd демона на разных интерфейсах. Создаю два конфигурационных файла, например sshd_config, sshd_config_fib1, для sshd в одном указываю
ListenAddress [ip1]
Во втором
ListenAddress [ip2]
Первый демон будет запускаться по /etc/rc.d/sshd, а второй прописываю в rc.local
setfib 1 /usr/sbin/sshd -f /etc/ssh/sshd_config_fib1
в итоге получаю два сокета
root sshd 21183 3 tcp4 [ip1]:22 *:*
root sshd 14733 3 tcp4 [ip2]:22 *:*
каждый из них висит использую свою таблицу маршрутизации.