Роутер на FreeBSD. Два канала связи. Основной + резервный.
FreeBSD, Заметки на полях Добавить комментарийНе так давно друг попросил помочь с настройкой на FreeBSD возможности переключения каналов связи с сетью Интернет с основного на резервный (при неполадках на основном), и обратно (при восстановлении связи на основном канале).
Естественно хотелось бы – чтобы это происходило автоматом
В результате поисков – была обнаружена статейка «2 канала на ОС FreeBSD«. Но в процессе реализации там были обнаружены некоторые опечатки и недоработки ![]()
В результате все было доведено до логического завершения. Решение предлагается далее.
Реализовывалось все это на FreeBSD 7.1-RELEASE.
Далее требуется установленный perl. (Подсказочка – установите просто Midnight Commander если у Вас его еще нет
При его инсталляции perl установится по зависимостям).
Далее нам потребуется PF. Но устанавливать его дополнительно, или пересобирать ядро вовсе нет необходимости. PF был интегрирован в основную систему, начиная с FreeBSD 5.3 в ноябре 2004. Единственный минус, что без пересборки ядра Вам не будут доступны ALTQ в PF. ALTQ (Alternate Queuing) предоставляет управление пропускной способностью Quality of Service (QoS), позволяющее гарантировать пропускную способность для различных сервисов на основе фильтрующих правил.
Включаем PF в файле /etc/rc.conf (Вносим и сохраняем).
- gateway_enable="YES" # Включить поддержку работы в режиме шлюза
- pf_enable="YES" # Включить PF (загрузить модуль если необходимо)
- pf_rules="/etc/pf.conf" # определение правил для pf
- pf_flags="" # дополнительные флаги для запуска pfctl
- pflog_enable="YES" # запустить pflogd(8)
- pflog_logfile="/var/log/pflog" # где pflogd должен сохранять протокол
- pflog_flags="" # дополнительные флаги для запуска pflogd
-
Далее создаем конфигурационный файл /etc/pf.conf для PF, где прописываем все правила и фильтры.
- # Main Setting
-
- ext_if_1="vr0" # IPS_1 - интерфейс первого канала
- ext_if_2="vr1" # IPS_2 - интерфейс второго канал
- int_if="rl0" # lan - интерфейс внутренний сети
- lo="lo0" # loopback
-
- int_net="192.168.254.0/25" # LAN NETWORK
- ext_addr_1="10.199.88.111" # IPS_1 wan
- ext_addr_2="10.233.3.46" # IPS_2 wan
- int_addr="192.168.254.2" # LAN IP
-
- gw_1="10.199.88.110" # IPS_1 gw
- gw_2="10.233.3.45" # IPS_2 gw
-
- # services
-
- tcp_svc="ssh"
-
- #log - логирование пакетов
-
- set loginterface $ext_if_1
- set loginterface $ext_if_2
- set loginterface $int_if
-
- # skip iface - не фильтровать loopback,
- # многие сервисы используют данный интерфейс под системные вещи.
-
- set skip on lo0
-
- # scrub
- scrub in all
-
- # NAT
- # Натируем внешние интерфейсы
-
- nat on $ext_if_1 inet from $int_net -> ($ext_if_1:0)
- nat on $ext_if_2 inet from $int_net -> ($ext_if_2:0)
- # INCOMING ROUTE
- # маршрутизирем весь входящий трафик, под условием, если пришел на тот то интерфейс,
- # то отправить необходимо ответ с того-то шлюза
- # плюс проставляем теги. Теги помогут нам корректно пробрасывать порты,
- # допустим у нас есть терминал сервер, пробросить можно следующим образом
- rdr on $ext_if_2 proto tcp from any to $ext_addr_2 port 3389 tag EXT_IF_B -> 192.168.254.17 port 3389
- rdr on $ext_if_1 proto tcp from any to $ext_addr_1 port 3389 tag EXT_IF_A -> 192.168.254.17 port 3389
- # BLOCK ALL
- # первоночально необходимо заблокировать весь входящий трафик
- block in
- # antispoof
- antispoof quick for $int_if
- # ICMP
- # разрешаем icmp на внешних интерфейсах и маршрутизирем их по свои шлюзам
- # чтобы не возникло ситуации пингуем один внешний адрес, а ответ идет по второму шлюзу.
- # IPS_1
- pass in on $ext_if_1 reply-to ($ext_if_1 $gw_1) inet proto icmp to ($ext_if_1) tag EXT_IF_A icmp-type echoreq code 0
- pass in on $ext_if_1 inet proto icmp from ($ext_if_1:network) to ($ext_if_1) icmp-type echoreq code 0
- # IPS_2
- pass in on $ext_if_2 reply-to ($ext_if_2 $gw_2) inet proto icmp to ($ext_if_2) tag EXT_IF_B icmp-type echoreq code 0
- pass in on $ext_if_2 inet proto icmp from ($ext_if_2:network) to ($ext_if_2) icmp-type echoreq code 0
- # allow tcp ports
- # разрешаем на внешних интерфейсах сервисы и маршрутизирем их, выше у нас разрешен только ssh
- # для udp аналогичная запись за изменением только proto tcp на proto udp
- # IPS_1
- pass in on $ext_if_1 reply-to ($ext_if_1 $gw_1) inet proto tcp to ($ext_if_1) port { $tcp_svc }
- pass in on $ext_if_1 inet proto tcp from ($ext_if_1:network) to ($ext_if_1) port { $tcp_svc }
- # IPS_2
- pass in on $ext_if_2 reply-to ($ext_if_2 $gw_2) inet proto tcp to ($ext_if_2) port { $tcp_svc }
- pass in on $ext_if_2 inet proto tcp from ($ext_if_2:network) to ($ext_if_2) port { $tcp_svc }
- # IPS_1
- pass in quick from ($ext_if_1:network) tagged EXT_IF_A keep state
- pass in quick reply-to ($ext_if_1 $gw_1) tagged EXT_IF_A keep state
- # IPS_2
- pass in quick from ($ext_if_2:network) tagged EXT_IF_B keep state
- pass in quick reply-to ($ext_if_2 $gw_2) tagged EXT_IF_B keep state
- # FIREWALL
- # разрешаем все во внутреннем пространстве шлюза
- pass out inet from (self:network)
- pass in inet proto icmp to (self:network)
- # LOCAL NETWORK
- # Разрешаем весь трафик на выход из локальной сети
- pass quick on $int_if
- # OUTGOING ROUTE
- # Маршрутизирем исходящий трафик
- pass out route-to ($ext_if_1 $gw_1) inet from ($ext_if_1) keep state
- pass out route-to ($ext_if_2 $gw_2) inet from ($ext_if_2) keep state
- pass out inet from { $ext_if_1 $ext_if_2 } to (self:network)
-
Этого файла с правилами будет достаточно чтобы обеспечить «хождение трафика» по двум каналам, с правильной маршрутизацией.
В подробности впадать не буду, если захотите посмотреть, что означает каждое правило, то почитайте документацию к PF.
Далее, необходимо в /etc/rc.conf добавить основной шлюз:
- defaultrouter="10.199.88.110"
-
Тот же самый IP, который прописывали как gw_1 в файле /etc/pf.conf
Cохраняем.
Далее нужно поставить пакетик для перла NET_PING:
- cd /usr/ports/net/p5-Net-Ping
- make install clean
-
Далее напишем собственно скрипт для переключения каналов в случае падение основного, и обратно в случае поднятия.
-
- #!/usr/bin/perl -w
- use strict;
- use warnings;
-
- use Net::Ping;
- my $p = Net::Ping->new("icmp");
- my $gw1 = "10.199.88.111"; # шлюз по умолчанию
- my $gw2 = "10.233.3.46"; # резервный шлюз
- my $log_file = "/var/log/change_route.log"; # путь и имя файла лог
-
- my $command = `netstat -rn | grep default`;
-
- if ($p->ping($gw1,0.05)){
- if($b[1] ne $gw1){
- if($b[1] eq ""){
- `route add default $gw1`;
- }else{
- `route change default $gw1`;
- }
- }
- }else{
- if($b[1] ne $gw2){
- `route change default $gw2`;
- }
- }
- $p->close();#
-
Сохраняем скрипт, делаем его исполняемым
- chmod +x имя_файла_вашего_скрипта.pl
-
И закидываем в крон на исполнение раз в минуту. Т.е. добавляем в файл /etc/crontab строку
- * * * * * root perl /путь_к_файлу/имя_вашего_скрипта.pl
-
Все. Перегружаем сервер! И если сделали все верно и правильно, то у Вас все уже должно работать
5 ответов to “Роутер на FreeBSD. Два канала связи. Основной + резервный.”
Ответить
Вы должны войти на сайт чтобы просмотреть это сообщение.

Январь 7th, 2010 at 19:58
…Видел уже где то…
Январь 12th, 2010 at 12:25
…Спс …
Январь 16th, 2010 at 03:25
…Хм.. …
Апрель 13th, 2010 at 02:22
……Кино фильмы онлайн…
Май 27th, 2010 at 17:20
СПС.…Я тут…