Configuring 2 Internet channels and more using pf in FreeBSD OS

    Recently I ran into a problem, setting up two channels on the Internet on the FreeBSD OS.
    Nothing absolutely complicated was supposed, but still I had to read a lot of documentation.

    Actually the task:

    1. create a gateway with two Internet connections, one primary, another backup.
    2. minimize human participation in the change to the back channel.

    Tools:

    OS FreeBSD 6.x, PF, perl


    Solution:

    FreeBSD was installed with minimal installation, the only change that needs to be done
    is to add the PF module to the kernel. This is not all complicated.

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


    add the lines:
    # PF

    device pf
    device pflog
    device pfsync


    # the ALTQ

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


    Next you need to save and rebuild the kernel:

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


    After loading the system you need to correct / etc /rc.conf
    Add the following:

    gateway_enable = "YES"
    pf_enable = "YES" # Enable PF (load the module if necessary)
    pf_rules = "/ etc / pf.conf" # define rules for pf
    pf_flags = "" # additional flags to run pfctl
    pflog_enable = "YES" # run pflogd (8)
    pflog_logfile = "/ var / log / pflog" # where pflogd should save the protocol
    pflog_flags = "" # save additional flags to start pflogd


    .

    Next, you need to write the rules for PF:

    ee /etc/pf.conf

    # Main Setting

    ext_if_1 = "rl0" # IPS_1 - interface of the first channel
    ext_if_2 = "rl1" # IPS_2 - interface of the second channel
    int_if = "ae0" # lan - internal network interface
    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” - allowed ports on external interfaces.

    #log - packet logging

    set loginterface ae0
    set loginterface rl0
    set loginterface rl1

    # skip iface - do not filter loopback,
    # many services use this interface for system things.

    set skip on lo0

    # scrub
    scrub in all

    # NAT
    # Nate external interfaces

    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
    # the first thing you need is to block all incoming traffic

    block in

    # antispoof
    antispoof quick for $ int_if

    # ICMP
    # we allow icmp on external interfaces and route them through our gateways
    # so that we don’t have a situation, we ping one external address, and the answer goes through the second gateway.

    # 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
    # allow services on the external interfaces and route them, above we only allow ssh
    # for udp a similar entry after changing only proto tcp to 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
    # with the router all incoming traffic, under the condition, if you came to that interface,
    # you need to send a response from that gateway
    # plus we put down tags. Tags will help us to forward ports correctly.
    # let's say we have a terminal server, you can
    forward it as follows # 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
    # allow everything in the internal space of the gateway
    pass out inet from (self: network)
    pass in inet proto icmp to (self: network)

    # LOCAL NETWORK
    # Allow all traffic to exit the local network
    pass quick on $ int_if

    # OUTGOING ROUTE
    # Router outgoing traffic

    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)

    These rules are enough to allow two channels to travel, with correct routing.
    I won’t go into details, if you want to see what each rule means, then read the PF documentation.

    Next, you need to add the main gateway to rc.conf:

    ee /etc/rc.conf

    defaultrouter = "222.0.0.1"

    save.

    Next, you need to put the packet for the NET_PING pearl :

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


    Dulle we write the script itself to switch channels in case the main one falls, and back in case of a raise.

    We save the script, make it executable, and drop it in crowns for execution once a minute.

    All. We reboot and everything should work for you. original article

    #!/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);
    }
    }
    }



    Also popular now: