Dear All,
Replying to one of my messages back in January about this toppic, Daniel
Hartmeier suggests:
"Instead of using route-to on $int_if, you can let connections go out
through the one interface to the default gateway, and use route-to on a
'pass out on $ext_if1' rule to re-route the outgoing connection to
another interface. Packets will 'try' to get out on the default
interface, but re-routing occurs before they are actually sent out
through the interface.
pass out on $ext_if1 route-to { ($ext_if1 $gwy_if1), \
($ext_if2 $gwy_if2) } round-robin ... keep state
Where $ext_if1 is the interface to your default gateway, where all
connections will go out through by default. Half of them will be
re-routed out on $ext_if2, and half will go out throuh $ext_if1.
You'd use the same construct if you wanted to load-balance outgoing
connections opened by the firewall itself (say, a DNS server there),
which don't arrive in on any interface at all."
Well, I tried to follow this recommendation, but I noticed that, although
PF indeed changed its behaviour and distributed the traffic between both
external connections, the packets sent out through the other external
connection (not the default gateway interface), had the source IP address
of the default interface. As a result, they get lost or discarded by the
ISP.
For example, in a setup where I have
ext_if1:rl0 (default)
IP=200.177.74.209
GW=200.177.74.1
ext_if2:tun0 (vr0)
IP=201.9.168.157
GW=200.164.195.8
When I try to access the web from a client station behind my firewall, if
the round-robin scheme chooses the default interface, then it all works
fine. However, if it chooses the other interface, see what pflog shows:
Feb 10 19:50:00.960284 rule 26/0(match): pass out on tun0:
200.177.74.209.60024> 129.128.5.191.80: S 1008219106:1008219106(0)
win 65535 <mss 1460,nop,nop,sackOK> (DF)
and that can also be confirmed from the output of tcpdump on the vr0
(tun0) interface:
Feb 10 19:50:07.522986 0:d:87:a3:99:94 0:3:e3:5d:d3:7 8864 70:
PPPoE-Session code Session, version 1, type 1, id 0x1169,
length 50 IP: 200.177.74.209.60024 > 129.128.5.191.80:
S 1008219106:1008219106(0)
Rule 26 mentioned above is this:
pass out quick log-all on $ext_if1 route-to \
{ ($ext_if1 <gws_if1>) , ($ext_if2 <gws_if2>) } round-robin \
inet proto tcp from any to any keep state
Now the question is how to tell PF to change the source IP address when it
decides to send the packet through the other interface ?
Thanks in advance.
Regards,
Emilio
ps. here is the pf.conf file
---------------------------------
ext_if1="rl0"
gw_if1="200.177.74.1"
gw_if2="200.164.195.8"
ext_if2="tun0"
int_if="rl1"
lan_net=$int_if:network
table <gws_if1> { $gw_if1 }
table <gws_if2> { $gw_if2 }
tcp_INservices = "{ 22 }"
icmp_types = "echoreq"
priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"
scrub in all random-id fragment reassemble
# nat/rdr
nat on $ext_if1 from $int_if:network to any -> ($ext_if1)
nat on $ext_if2 from $int_if:network to any -> ($ext_if2)
# squid
rdr on $int_if inet proto tcp from $lan_net to any port www -> 127.0.0.1 port
3128
block in log from any to any
block out log from any to any
# loopback
pass quick on lo0 all
block drop in log quick on $ext_if1 from $priv_nets to any
block drop out log quick on $ext_if1 from any to $priv_nets
block drop in log quick on $ext_if2 from $priv_nets to any
block drop out log quick on $ext_if2 from any to $priv_nets
pass in quick log-all on $int_if from $int_if:network to any keep state
pass out quick log-all on $ext_if1 route-to \
{ ($ext_if1 <gws_if1>) , ($ext_if2 <gws_if2>) } round-robin \
inet proto tcp from any to any keep state
# from internal network to firewall
pass in log-all on $int_if from $lan_net to $int_if flags S/SA keep state
# from firewall to internal network
pass out log on $int_if from $int_if to $int_if:network keep state
# firewall services
pass in log-all quick on $ext_if1 reply-to ($ext_if1 $gw_if1) inet proto tcp
from any to ($ext_if1) port $tcp_INservices flags S/SA keep state
pass in log-all quick on $ext_if2 reply-to ($ext_if2 $gw_if2) inet proto tcp
from any to ($ext_if2) port $tcp_INservices flags S/SA keep state
# icmp
pass in log-all quick on $ext_if1 reply-to ($ext_if1 $gw_if1) inet proto icmp
all icmp-type $icmp_types keep state
pass in log-all quick on $ext_if2 reply-to ($ext_if2 $gw_if2) inet proto icmp
all icmp-type $icmp_types keep state
# outside services
pass out on $ext_if1 proto tcp all flags S/SA keep state
pass out on $ext_if2 proto tcp all flags S/SA keep state
pass out on $ext_if1 proto {udp icmp} all keep state
pass out on $ext_if2 proto {udp icmp} all keep state