Using PF ALTQ to schedule NAT jail traffic

Bryan Alves bryanalves at gmail.com
Sun Jan 4 04:00:56 UTC 2009


I'm using a FreeBSD box to do the routing, NAT, and firewall duties for my
home network.  There are also a couple of jails located on the machine,
providing various services.  One of these jails is running a torrent client
24/7.  I isolated the torrent client to a jail in an attempt to more
effectively schedule packets going to and from it.

However, I'm having problems properly tagging packets that are originating
from the jail destined for the internet.

First, my ifconfig:

-------------------------
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 9000
        options=19b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,TSO4>
        ether 00:1b:21:29:b0:b0
        inet 192.168.10.1 netmask 0xffffff00 broadcast 192.168.10.255
        inet 192.168.10.200 netmask 0xffffffff broadcast 192.168.10.200
        inet 192.168.10.201 netmask 0xffffffff broadcast 192.168.10.201
        inet 192.168.10.202 netmask 0xffffffff broadcast 192.168.10.202
        inet 192.168.10.203 netmask 0xffffffff broadcast 192.168.10.203
        inet 192.168.10.204 netmask 0xffffffff broadcast 192.168.10.204
        media: Ethernet 1000baseTX <full-duplex>
        status: active
em1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=19b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,TSO4>
        ether 00:1b:21:29:b0:ab
        inet 173.48.75.167 netmask 0xffffff00 broadcast 173.48.75.255
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x3
        inet6 ::1 prefixlen 128
        inet 127.0.0.1 netmask 0xff000000
pflog0: flags=141<UP,RUNNING,PROMISC> metric 0 mtu 33160
------------------------------


And now my current PF rules:

---------------------------------------------
ext_if          = "em1"

int_if          = "em0"
localnet        = $int_if:network
torrent_ports   = "57100:57199"
web_ports       = "81"
gateway         = "192.168.10.1"
httpd_jail      = "192.168.10.200"
samba_jail      = "192.168.10.201"
slimserver_jail = "192.168.10.202"
torrent_jail    = "192.168.10.203"
desktop         = "192.168.10.111"

set loginterface $ext_if
scrub on $ext_if

altq on $ext_if bandwidth 4550Kb hfsc queue { q_high, q_med, q_low }
  queue q_high        bandwidth 25% priority 6 qlimit 250 hfsc
  queue q_med         bandwidth 45% priority 4 qlimit 250 hfsc (default)
  queue q_low         bandwidth 30% priority 3 qlimit 500 hfsc

nat on $ext_if from $localnet to any -> ($ext_if)

#Port Forwards
rdr on $ext_if proto tcp from any to any port ssh            -> $gateway
rdr on $ext_if proto tcp from any to any port $web_ports     -> $httpd_jail
rdr on $ext_if proto tcp from any to any port $torrent_ports ->
$torrent_jail

#Nat Reflection
rdr on $int_if proto tcp from $localnet to $ext_if port ssh -> $gateway
rdr on $int_if proto tcp from $localnet to $ext_if port $web_ports ->
$httpd_jail
no nat on $int_if proto tcp from $int_if to $localnet
nat on $int_if proto tcp from $localnet to $gateway port ssh -> $int_if
nat on $int_if proto tcp from $localnet to $httpd_jail port $web_ports ->
$int_if

antispoof for $ext_if
#block in quick on $ext_if from <blacklisted> to any
block log all

pass on lo0

#Allow all LAN traffic
pass in on $int_if from $localnet to any keep state
pass out on $int_if from any to $localnet keep state
#Tag special traffic so it gets queued right
pass in on $int_if from $desktop      to any tag DESKTOP
pass in on $int_if from $torrent_jail to any tag TORRENT
pass in on $int_if from $httpd_jail   to any tag HTTPD

#In on ext_if
pass in on $ext_if proto tcp          from any to $httpd_jail   port
$web_ports     keep state     queue (q_high)
pass in on $ext_if proto { tcp, udp } from any to $torrent_jail port
$torrent_ports keep state     queue (q_low)
pass in on $ext_if proto tcp          from any to any           port
ssh            modulate state queue (q_high)
pass in on $ext_if proto gre          from any to
any                               keep state     queue (q_high)
pass in on $ext_if proto tcp          from any to any           port
pptp           keep state     queue (q_high)

#Out on ext_if
pass out on $ext_if proto tcp           all modulate state queue (q_med)
pass out on $ext_if proto { udp, icmp } all keep state     queue (q_med)
pass out on $ext_if proto gre           all keep state     queue (q_high)
#Queue tagged traffic
pass out on $ext_if proto { tcp, udp } from any to any tagged TORRENT queue
(q_low)
pass out on $ext_if from any to any tagged DESKTOP queue (q_high)
pass out on $ext_if from any to any tagged HTTPD   queue (q_high)
------------------------------------------------

The behavior of tagging NAT traffic so that it gets queued on the outside
interface works correctly in the case of the DESKTOP tag, which is a
different physical machine.  No packets pass through the firewall and get
tagged with either TORRENT or HTTPD, however.  Torrent traffic from
192.168.10.203 which originates from the jail passes through on the "pass
out on $ext_if proto tcp all modulate state queue (q_med) rule instead,
since it wasn't tagged on it's way through the NAT.  The 2nd "in on ext_if"
rule properly catches packets and puts them into the right queue, and
statefully the responses from these pass through it as well.  It's the
packets that non-statefully originate from the jail that I can't catch.

I suspect this has something to do with jail using lo0 to manage the
traffic, but I'm not sure how to fix it.  I tried to tcpdump the lo0, em1,
and em0 interfaces to find this traffic, but I can't find the traffic at all

How can I modify my rules and/or aliases so that I can properly tag all
traffic that originates from a specific jail?


More information about the freebsd-pf mailing list