Hi,

I have two ISPs and a LAN. I need to load balance outgoing connections
from the LAN between the ISPs.

My router is running OpenBSD 4.6-stable, up-to-date.

                      -----------------
                      |               |
ISP 1 ---(isp1 box)---+-ext1_if       |
                      |               |
                      |        int_if-+--- LAN
                      |               |
ISP 2 ---(isp2 box)---+-ext2_if       |
                      |               |
                      -----------------
                           OpenBSD 

int_if -> interface to LAN
int_net -> 192.168.0.0/24

ext1_if -> interface to ISP 1 (192.168.1.2)
ext1_gw -> ISP 1 gateway (192.168.1.1)

ext2_if -> interface to ISP 2 (192.168.2.2)
ext2_gw -> ISP 2 gateway (192.168.2.1)

There is no default route (empty /etc/mygate).

Following http://www.openbsd.org/faq/pf/pools.html#outgoing I ended up
with the following :

---sysctl.conf---
net.inet.ip.forwarding=1
---sysctl.conf---

---pf.conf---
set debug loud
set block-policy return
#set optimization aggressive
#set timeout src.track 300
set skip on lo

nat log on $ext1_if from $int_net -> ($ext1_if)
nat log on $ext2_if from $int_net -> ($ext2_if)

block log 

pass in log on $int_if route-to \
{ ($ext1_if $ext1_gw), ($ext2_if $ext2_gw) } \
from $int_net

pass in log on $int_if from $int_net to $int_if

pass out log 
pass out log on $ext1_if route-to ($ext2_if $ext2_gw) from $ext2_if
pass out log on $ext2_if route-to ($ext1_if $ext1_gw) from $ext1_if
---pf.conf---

Everything works fine with this setup but https and some ftp servers are
very sensitive to IP changes, so I did add sticky-address to bind a
connection to an ISP and fix this issue :

pass in log on $int_if route-to \
{ ($ext1_if $ext1_gw), ($ext2_if $ext2_gw) } sticky-address \
from $int_net

This works when only one PC open a connection. When another PC open
a connection the first one has no longer access to the internet. After
some time in tcpdump and /var/log/messages, it seems because packets
are routed to the wrong interface.

/var/log/messages analysis :

192.168.0.78 tries a connection :
    /bsd: pf_map_addr: selected address 192.168.2.1
    /bsd: pf_map_addr: selected address 192.168.2.2
    /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.1
    /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.2
    /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.1
    /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.2

Looks ok, now 192.168.0.29 tries a connection too :
    /bsd: pf_map_addr: selected address 192.168.1.1
    /bsd: pf_map_addr: selected address 192.168.1.2
    /bsd: pf_map_addr: src tracking maps 192.168.0.29 to 192.168.1.1
    /bsd: pf_map_addr: src tracking maps 192.168.0.29 to 192.168.1.2
    /bsd: pf_map_addr: src tracking maps 192.168.0.29 to 192.168.1.1
    /bsd: pf_map_addr: src tracking maps 192.168.0.29 to 192.168.1.2

Looks good, now 192.168.0.78 retries a connection :
    /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.1
    /bsd: pf_map_addr: selected address 192.168.1.2
    [and that's all]

This is confirmed by tcpdump (on pflog0, bge0, em0 and em1) : the
packets are routed to the wrong interface. Three SYN are sent, then
client bail out. Tests were quickly done, so there is no state/track
timeout here.

Is there something I am doing wrong ?

Reply via email to