Настройка 2 интернет каналов и больше с помощью pf в ОС FreeBSD

    Недавно столкнулся с проблемой, настройка двух каналов в интернет на ОС FreeBSD
    Ничего абсолютно сложного не предполагалось, но все же пришлось не много почитать документацию.

    Собственно задача:

    1. создать шлюз с двумя выходами в интернет, один основной, другой резервный.
    2. минимизировать участие человека в смене на бек канал.

    Инструменты:

    ОС FreeBSD 6.x, PF, perl


    Решение:

    FreeBSD был поставлен с минимальной установкой, единственное изменение, которое нужно сделать
    это добавить в ядро модуль PF. Делается это все не сложно.

    cp /usr/src/sys/i386/conf/GENERIC /usr/src/sys/i386/conf/PF
    ee /usr/src/sys/i386/conf/PF


    добавляем строчки:
    # PF

    device pf
    device pflog
    device pfsync


    # ALTQ

    options ALTQ
    options ALTQ_CBQ
    options ALTQ_RED
    options ALTQ_RIO
    options ALTQ_HFSC
    options ALTQ_PRIQ
    options ALTQ_NOPCC


    Далее нужно сохранить и пересобрать ядро:

    cd /usr/src
    make buildkernel KERNCONF=PF
    make installkernel KERNKONF=PF
    reboot


    После загрузки системы нужно подправить /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


    сохраняем.

    далее нужно прописать правила для PF:

    ee /etc/pf.conf

    # Main Setting

    ext_if_1=«rl0» # IPS_1 — интерфейс первого канала
    ext_if_2=«rl1» # IPS_2 — интерфейс второго канал
    int_if=«ae0» # lan — интерфейс внутренний сети
    lo=«lo0» # loopback

    int_net=«172.21.0.0/16» # LAN NETWORK
    ext_addr_1=«222.0.0.2» # IPS_1 wan
    ext_addr_2=«223.0.0.2» # IPS_2 wan
    int_addr=«172.21.0.1» # LAN IP

    gw_1=«222.0.0.1» # IPS_1 gw
    gw_2=«223.0.0.1» # IPS_2 gw

    # services

    tcp_svc=«ssh» — разрешенные порты на внешних интерфейсах.

    #log — логирование пакетов

    set loginterface ae0
    set loginterface rl0
    set loginterface rl1

    # skip iface — не фильтровать loopback,
    # многие сервисы используют данный интерфейс под системные вещи.

    set skip on lo0

    # scrub
    scrub in all

    # NAT
    # Натируем внешние интерфейсы

    nat on $ext_if_1 inet from !(self) -> ($ext_if_1:0) # IPS_1 nat
    nat on $ext_if_2 inet from !(self) -> ($ext_if_2:0) # IPS_2 nat

    # 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 }

    # INCOMING ROUTE
    # маршрутизирем весь входящий трафик, под условием, если пришел на тот то интерфейс,
    # то отправить необходимо ответ с того-то шлюза
    # плюс проставляем теги. Теги помогут нам корректно пробрасывать порты,
    # допустим у нас есть терминал сервер, пробросить можно следующим образом
    # rdr on $ext_if_2 proto tcp from any to $ext_addr_2 port 3389 tag EXT_IF_B -> 172.21.0.1 port 3389
    # rdr on $ext_if_1 proto tcp from any to $ext_addr_1 port 3389 tag EXT_IF_A -> 172.21.0.1 port 3389

    # 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.

    Далее, необходимо в rc.conf добавить основной шлюз:

    ee /etc/rc.conf

    defaultrouter=«222.0.0.1»

    сохраняем.

    Далее нужно поставить пакетик для перла NET_PING:

    cd /usr/ports/net/p5-Net-Ping
    make install


    Далле пишем сам скрипт для переключения каналов в случае падение основного, и обратно в случае поднятия.

    Сохраняем скрипт, делаем его исполняемым, и закидываем в крон на исполнение раз в минуту.

    Все. Перезагружаемся и у Вас все должно работать.

    #!/usr/bin/perl -w

    use strict;
    use warnings;
    use Net::Ping;

    # 1 - автоматический режим переключение канала
    # 2 - принудительное переключение на второй канал.

    my $action = 1;
    my $p = Net::Ping->new("icmp");
    my $host_gw = "222.0.0.1"; # default gw
    my $gw = "223.0.0.1";
    my $now = localtime time;

    if($action == 1){
    my $command = `netstat -rn | grep default`;
    my @b = split('\s+',$command,3);
    if ($p->ping($host_gw,0.05)){
    print "host $host_gw is ok\n";
    if($b[1] ne $host_gw){
    if($b[1] eq ""){
    `route add default 222.0.0.1`;
    }else{
    `route change default 222.0.0.1`;
    open(LOG,">>/change_route.log");
    print LOG "[!] $now Route change to 222.0.0.1\n";
    close(LOG);
    }
    }
    }else{
    print "host $host_gw is bad.\n";
    if($b[1] ne $gw){
    `route change default 223.0.0.1`;
    open(LOG,">>/change_route.log");
    print LOG "[!] $now Route change to 223.0.0.1\n";
    close(LOG);
    }
    }
    $p->close();
    }

    if($action == 2){
    my $command = `netstat -rn | grep default`;
    my @b = split('\s+',$command,3);
    if($b[1] ne $gw){
    if($b[1] eq ""){
    `route add default 223.0.0.1`;
    }else{
    `route change default 223.0.0.1`;
    open(LOG,">>/change_route.log");
    print LOG "[!] $now Route change to 223.0.0.1\n";
    close(LOG);
    }
    }
    }


    оригинал статьи
    • +4
    • 14.9k
    • 4
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 4

      +1
      Что только люди не придумают чтобы BGP не понимать (:
        +1
        А зачем малому офису BGP?
        +1
        Зачем компили ядро если ALTQ неиспользуется? kldload pf отменили?
          0
          ALTQ можно использовать после, шейпить каналы пригодится всегда.
          kldload не надежно, имели прецеденты не стабильной работы. Поэтому предпочитаю компилировать в ядро.

        Only users with full accounts can post comments. Log in, please.