State table and counters: pfctl -s info (or -si)

/etc/pf/base.pf

#       $FreeBSD: src/etc/pf.conf,v 1.2.2.1 2006/04/04 20:31:20 mlaier Exp $
#       $OpenBSD: pf.conf,v 1.21 2003/09/02 20:38:44 david Exp $
#
# See pf.conf(5) and /usr/share/examples/pf for syntax and examples.
# Required order: options, normalization, queueing, translation, filtering.
# Macros and tables may be defined and used anywhere.
# Note that translation rules are first match while filter rules are last match.

# Macros: define common values, so they can be referenced and changed easily.
ext_if="tun0"   # replace with actual external interface name i.e., dc0
int_if="rl0"    # replace with actual internal interface name i.e., dc1
int_net="{ 172.16.44.0/24, 172.16.45.0/24, 172.16.46.0/24, 192.168.1.0/24, 192.168.2.0/24, 10.0.0.0/8 }"

# Options: tune the behavior of pf, default values are given.

# Flush states?
#set timeout { tcp.first 10, tcp.opening 10, tcp.established 10 }
#set timeout { tcp.closing 10, tcp.finwait 10, tcp.closed 10 }

#set timeout { interval 10, frag 30 }
#set timeout { tcp.first 120, tcp.opening 30, tcp.established 86400 }
#set timeout { tcp.closing 900, tcp.finwait 45, tcp.closed 90 }
#set timeout { udp.first 60, udp.single 30, udp.multiple 60 }
#set timeout { icmp.first 20, icmp.error 10 }
#set timeout { other.first 60, other.single 30, other.multiple 60 }
#set timeout { adaptive.start 0, adaptive.end 0 }
#set limit { states 10000, frags 5000 }
#set loginterface none
#set optimization normal
set block-policy return
#set block-policy drop
#set require-order yes
set fingerprints "/etc/pf.os"

# Normalization: reassemble fragments and resolve or reduce traffic ambiguities.
scrub in all

altq on $ext_if bandwidth 288Kb cbq queue { ack, ssh, dflt, bulk, down }
queue ack  bandwidth 32Kb  priority 7 cbq(rio, borrow)
queue ssh  bandwidth 128Kb priority 5 cbq(rio, borrow)
queue dflt bandwidth 8Kb   priority 4 cbq(rio, borrow, default)
queue bulk bandwidth 8Kb   priority 2 cbq(rio, borrow)
queue down bandwidth 8Kb   priority 0 cbq(rio, borrow)

# Translation: specify how addresses are to be mapped or redirected.
# nat: packets going out through $ext_if with source address $int_net will
# get translated as coming from the address of $ext_if, a state is created for
# such packets, and incoming packets will be redirected to the internal address.
nat-anchor "dynamic/*"
binat-anchor "dynamic/*"

nat on $ext_if from $int_net to any -> ($ext_if:0)

# rdr outgoing FTP requests to the ftp-proxy
rdr on $int_if proto tcp from any to !vitani port ftp -> 127.0.0.1 port 8021

rdr-anchor "dynamic/*"

# Filtering: the implicit first two rules are
pass in all
pass out all

# Default to block all on external interface
block in on $ext_if all

# Reject instead of drop for ident (irc servers hate that)
block return-rst in on $ext_if proto tcp from any to ($ext_if) port ident

# Keep state for all outgoing packets, and queue in default
pass out on $ext_if proto { tcp, udp, icmp } all modulate state queue (dflt, ack)

# Queue download-tagged packets
pass out on $ext_if tagged DOWNLOAD modulate state queue (down, ack)

# Queue all outgoing SSH connections in ssh queues
pass out on $ext_if proto tcp from any to any port { 22, 13022 } modulate state queue (bulk, ssh)

# FTP stuff
pass on $ext_if inet proto tcp from any to any user proxy keep state queue (dflt, ack)

# NTP stuff
pass out on $ext_if proto udp from any to any port 123 keep state queue ack

# RDP (MSTSC) stuff
pass out on $ext_if proto tcp from any to any port 3389 keep state queue (ssh, ack)

anchor "dynamic/*"