I like to keep things simple, so I got rid of all those match and antispoof stuff. You can add them in later if you want.
BTW I wonder why you did not allow out any port domain/DNS (53) out
Code:
EXT = "rl1"
INT = "rl0"
# -- for j65nko only
EXT = re0
INT = bge0
TCPservices = "{ ssh www https }"
UDPservices = "{ domain ntp }"
icmp_types = "{ echoreq, unreach }"
set block-policy drop
set loginterface $EXT
table <blocked> persist # Permanent table of blocked hosts
set skip on lo # Allow all loopback
# match in on $EXT all scrub (no-df)
# match out on $EXT all scrub (no-df random-id)
# --- NAT/RDR section
nat on $EXT from !($EXT) -> ($EXT) # NAT
# --- DEFAULT policy
block log all
block in log quick from <blocked> # Block and forget banned
#antispoof quick for { lo, $EXT, $int_if }
# ---- OUTGOING TRAFFIC
# -- external interface
pass out quick on $EXT tagged OUT_ok
# --- INCOMING TRAFFIC
# - internal interface
pass in quick on $INT inet proto tcp from $INT:network to any port $TCPservices tag OUT_ok
pass in quick on $INT inet proto tcp from $INT:network to any port $UDPservices tag OUT_ok
# - external interface
# Allow SSH on the external interface, but add the client to blocked
# table if it tries to connect more than X times in Y seconds
pass in quick on $EXT inet proto tcp to ($EXT) port ssh \
(max-src-conn-rate 2/150, overload <blocked> flush global)
# Turn on when we want externals to PING
# pass in quick on $EXT inet proto icmp to ($EXT) icmp-type $icmp_types