
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
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);
}
}
}