IPFW | One ISP | Two xDSL/internet channels | Load balancing

Hello World.

I've been working on IPFW config to achieve following goal:
Load balance of outgoing and return traffic from LAN to Internet using two simultaneous PPPoE connections to ISP.

I've solved this problem using following config:

Code:
#!/bin/sh

# Delay
echo "5 seconds delay..."
sleep 5

#Flush out list before we begin.
ipfw -q -f flush
ipfw -q -f nat flush
ipfw -q pipe flush
ipfw -q queue flush

################################################################################

#Set rules command prefix
cmd="ipfw -q"

pif0="adsl1"
pif0ip=`ifconfig $pif0 inet | grep inet | awk '{print $2}'`
pif0gw=`ifconfig $pif0 inet | grep inet | awk '{print $4}'`

pif1="adsl2"
pif1ip=`ifconfig $pif1 inet | grep inet | awk '{print $2}'`
pif1gw=`ifconfig $pif1 inet | grep inet | awk '{print $4}'`

pifs="adsl*"
lif="lan0"
wwwpubif="vlan150"

wwwpub="192.168.147.0/24"
zuznet="192.168.1.0/24"
boundips="192.168.1.5, 192.168.1.15"


################################################################################

$cmd add 50 count log ip from any to any 25, 587, 2525, 465, 475 in recv $lif // Counting mail requests

$cmd add 100 allow ip from any to any via lo0
$cmd add     deny ip from any to 127.0.0.0/8
$cmd add     deny ip from 127.0.0.0/8 to any

$cmd add 500 allow ip from any to any via vlan10\*
#$cmd add     allow ip from any to any out xmit $wwwpubif keep-state
$cmd add     deny ip from $wwwpub to $zuznet setup in recv $wwwpubif // Restrict access from public wi-fi to zuzex local network

# Deprectated #
#$cmd add 1000 setfib 0 ip from 172.20.0.0/24 to 192.168.1.0/24 via $lif
#$cmd add      setfib 0 ip from 192.168.1.0/24 to 172.20.0.0/24 via $lif

$cmd add 1100 skipto 2040 ip from any to any out xmit $lif tagged 101 keep-state
$cmd add      skipto 2080 ip from any to any out xmit $lif tagged 102 keep-state

# Next few IF's will keep firewall rules consistent in cases if pppoe connections will go down
if [ ! -z $pif0ip ] && [ ! -z $pif1ip ] ; then
  $cmd add 1500 deny gre from 192.168.1.253 to any // This rule will drop first GRE packet from dustbox when VPN initiates
  $cmd add 1900 skipto 2040 ip from $boundips to any in recv $lif
  $cmd add 2000 prob 0.5 skipto 2080 ip from any to any in recv $lif // Load balancing
fi

if [ ! -z $pif0ip ] ; then
  $cmd add 2040 setfib 0 ip from any to any via $lif keep-state
  $cmd add 2050 allow tag 101 ip from any to any via $lif
fi

if [ ! -z $pif1ip ] ; then
  $cmd add 2080 setfib 1 ip from any to any via $lif keep-state
  $cmd add 2090 allow tag 102 ip from any to any via $lif
fi

################################################################################

$cmd add 3050 deny ip from any to 192.168.0.0/16 in recv $pifs
$cmd add      deny ip from 192.168.0.0/16 to any in recv $pifs
$cmd add      deny ip from any to 172.16.0.0/12 in recv $pifs
$cmd add      deny ip from 172.16.0.0/12 to any in recv $pifs
$cmd add      deny ip from any to 10.0.0.0/8 in recv $pifs
$cmd add      deny ip from 10.0.0.0/8 to any in recv $pifs
$cmd add      deny ip from any to 169.254.0.0/16 in recv $pifs
$cmd add      deny ip from 169.254.0.0/16 to any in recv $pifs

################################################################################

if [ ! -z $pif1ip ]; then
  $cmd add 11000 fwd $pif1gw all from $pif1ip to any via $pif0 // Send reply to necessary interface
fi

################################################################################

#$cmd add 13000 allow icmp from any to any // allow ping ME from outside
$cmd add 13010 allow ip from any to me 8022 in recv $pifs // sshd server
$cmd add       skipto 31000 log ip from any to me 22 in recv $pifs // Airlock sshd
$cmd add       skipto 31000 log ip from any to me 80 in recv $pifs // Apache webserver on mainframe
$cmd add       skipto 31000 log ip from any to me 443 in recv $pifs // Apache webserver on mainframe
$cmd add       skipto 31000 log ip from any to me 3399 in recv $pifs // MSTSC to 192.168.1.114
$cmd add       skipto 31000 log ip from any to me 3377 in recv $pifs // MSTSC to 192.168.1.37
$cmd add       skipto 31000 log ip from any to me 1723 in recv $pif0 // PPTP server on DUSTBOX
$cmd add       skipto 31000 gre from any to me in recv $pif0 // PPTP server on DUSTBOX
$cmd add       skipto 31500 log ip from any to me 1723 in recv $pif1 // PPTP server on DUSTBOX
$cmd add       skipto 31500 gre from any to me in recv $pif1 // PPTP server on DUSTBOX

################################################################################

$cmd add 30000 deny log ip from any to any in via $pifs setup // Reject and Log all setup of incoming connections from the outside

################################################################################

if [ ! -z $pif0ip ]; then
  $cmd nat 101 config if $pif0 same_ports reset \
                        redirect_port tcp 192.168.1.253:10022 $pif0ip:22 \
                        redirect_port tcp 192.168.1.250:80 $pif0ip:80 \
                        redirect_port tcp 192.168.1.250:443 $pif0ip:443 \
                        redirect_port tcp 192.168.1.253:1723 $pif0ip:1723 \
                        redirect_proto gre 192.168.1.253 $pif0ip \
                        redirect_port tcp 192.168.1.114:3389 $pif0ip:3399 \
                        redirect_port tcp 192.168.1.37:3389 $pif0ip:3377
fi

if [ ! -z $pif1ip ]; then
  $cmd nat 102 config if $pif1 same_ports reset \
                        redirect_port tcp 192.168.1.253:10022 $pif1ip:22 \
                        redirect_port tcp 192.168.1.250:80 $pif1ip:80 \
                        redirect_port tcp 192.168.1.250:443 $pif1ip:443 \
                        redirect_port tcp 192.168.1.253:1723 $pif1ip:1723 \
                        redirect_proto gre 192.168.1.253 $pif1ip \
                        redirect_port tcp 192.168.1.114:3389 $pif1ip:3399 \
                        redirect_port tcp 192.168.1.37:3389 $pif1ip:3377
fi

################################################################################

$cmd pipe 100 config bw 256Kbit/s queue 60 gred 0.002/10/30/0.1
$cmd queue 100 config pipe 100 queue 60 mask src-ip 0xffffffff gred 0.002/10/30/0.1

$cmd pipe 101 config bw 1024Kbit/s queue 60 gred 0.002/10/30/0.1
$cmd queue 101 config pipe 101 queue 60 mask dst-ip 0xffffffff gred 0.002/10/30/0.1

################################################################################

# NAT
if [ ! -z $pif0ip ]; then
  $cmd add 31000 pipe 100 ip from $wwwpub to any out xmit $pif0 // Public Wi-Fi Shaping out
  $cmd add       nat 101 ip from any to any via $pif0 // adsl1 nat
  $cmd add       pipe 101 ip from any to $wwwpub in recv $pif0 // Public Wi-Fi Shaping in
  $cmd add       skipto 35000 tag 101 ip from any to any in recv $pif0
fi

if [ ! -z $pif1ip ]; then
  $cmd add 31500 pipe 100 ip from $wwwpub to any out xmit $pif1 // Public Wi-Fi Shaping out
  $cmd add       nat 102 ip from any to any via $pif1 // adsl2 nat
  $cmd add       pipe 101 ip from any to $wwwpub in recv $pif1 // Public Wi-Fi Shaping in
  $cmd add       skipto 35000 tag 102 ip from any to any in recv $pif1
fi

################################################################################

$cmd add 35000 allow tcp from any to any established // Allow TCP through if setup succeeded

$cmd add 50000 allow all from any to any
$cmd add 65534 deny all from any to any
comments:
1. adslX - two NG interfaces which controlled by MPD5 as PPPoE client
2. wwwpub - public wi-fi network which have access to Internet

So the problem is that each outgoing connection will be balanced in rule 2000. This breaks for example outgoing ftp/pptp and etc. connections.

I'm wondering if this possible to automatically stick local IP to certain FIB if there is activity from this IP. The key word here is automatically.
For example 192.168.1.22 opens connection to http://www.freebsd.org. Some daemon discovers this activity from 192.168.1.22 and adds 192.168.1.22 with 50% probability to IPFW table 2 which is forced to use FIB(routing table) 2. If there is no activity from 192.168.1.22 after 10 minutes then this IP will be removed from all tables. And so on...
So the point is that each local client will be forced to use only certain FIB while there is activity. In case of 30+ clients this will produce actually good load balance with sticky session to external IP which is important for some services.

I've being thinking about "arpalert" daeamon or some other apr monitor daemons as one of the possible solutions. But I still have doubts about that.

What do you think? Does anybody have ideas on how this should work?
 
Back
Top