PF PF Config for Dedicated Servers

I'm just starting to configure PF on my dedicated server and was curious if I was on the right track. I have a couple questions though ..

Am I using options I shouldn't be using? Should I be scrubbing packets?

Before I add the "block all" option, how do I allow MY IP address in regardless? (so I don't accidentally lock myself out).

Code:
EXT_IF="em0"

MAIL="xx.xx.xx.xx"
WHITELIST="xx.xx.xx.xx"

set limit { states 20000, frags 20000 }

set optimization conservative
set block-policy drop
set state-policy if-bound
set skip on lo0

# http://www.openbsd.gr/faq/pf/scrub.html
#scrub in all
scrub in on $EXT_IF all fragment reassemble

# alternate smtp port
rdr on $EXT_IF proto tcp from any to $MAIL port 8025 -> $MAIL port 25

# this is needed so I can send mail with <domain>
rdr on $EXT_IF proto tcp from any to $MAIL port 587 -> $MAIL port 25

# block anything coming from source we have no back routes for
block in log quick on $EXT_IF from no-route to any

# drop broadcast requests quietly.
block in log quick on $EXT_IF from any to 255.255.255.255

# block packets claiming to come from reserved internal address blocks, as
# they are obviously forged and cannot be contacted from the outside world.
block in log quick on $EXT_IF from { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 255.255.255.255/32 } to any

table <blacklist> persist
block quick from <blacklist>

# block ssh scanners
pass in quick on $EXT_IF proto tcp from { $WHITELIST } to any port ssh
pass in log on $EXT_IF proto tcp from any to any port ssh \
        flags S/SA keep state \
        (max-src-conn-rate 3/30, overload <blacklist> flush global)
 
You might forget to remove it ;)

pfctl -f /etc/pf.conf.new && sleep 20 && pfctl -f /etc/pf.conf.old

You can put that in a simple script. It will load the new rules (pf.conf.new), sleep for 20 seconds (enough time to figure out if you're locked out), then load the old rules (pf.conf.old) again. That way you'd be locked out for a couple of seconds at the most.
 
Leave the custom options like if-bound out for now, turn them on only if you know that you'll need them. For scrub this is enough:

Code:
scrub on $EXT_IF all

Add a rule as the first pass in rule to allow everything in from your known address:

Code:
pass in quick on $EXT_IF inet from $MYIP to any

The to any may look excessive but if you experiment with rdrs the destination address may not always be the external address on EXT_IF.
 
Ok, before I give my PF config a test run - can anyone let me know if I made any rookie mistakes?

Code:
EXT_IF="em0"

MAIL="xx.xx.xx.xx"
WHITELIST="xx.xx.xx.xx"
SSH="xxx"
ALLOWED_ICMP_TYPES="echoreq"

set limit { states 20000, frags 20000 }

set optimization conservative
set block-policy drop
# set state-policy if-bound
set skip on lo0

# The "quick" option on a filtering rule has the effect of canceling any
# further rule processing and causes the specified action to be taken.
# http://www.openbsd.org/faq/pf/filter.html#quick

# http://www.openbsd.gr/faq/pf/scrub.html
scrub on $EXT_IF all

# alternate smtp port
rdr on $EXT_IF proto tcp from any to $MAIL port 8025 -> $MAIL port 25

# this is needed so I can send mail with <domain>
rdr on $EXT_IF proto tcp from any to $MAIL port 587 -> $MAIL port 25

# set a default deny everything policy.
block log all

# block anything coming from source we have no back routes for
block in log quick on $EXT_IF from no-route to any

# drop broadcast requests quietly.
block in log quick on $EXT_IF from any to 255.255.255.255

# block packets claiming to come from reserved internal address blocks, as
# they are obviously forged and cannot be contacted from the outside world.
block in log quick on $EXT_IF from 10.0.0.0/8 to any
block in log quick on $EXT_IF from 172.16.0.0/12 to any
block in log quick on $EXT_IF from 192.168.0.0/16 to any
block in log quick on $EXT_IF from 255.255.255.255/32 to any

# block probes that can possibly determine our operating system by disallowing
# certain combinations that are attempting to fingerprint the server.
# * F : FIN  - Finish; end of session
# * S : SYN  - Synchronize; indicates request to start session
# * R : RST  - Reset; drop a connection
# * P : PUSH - Push; packet is sent immediately
# * A : ACK  - Acknowledgement
# * U : URG  - Urgent
# * E : ECE  - Explicit Congestion Notification Echo
# * W : CWR  - Congestion Window Reduced
block in log quick on $EXT_IF proto tcp flags FUP/WEUAPRSF
block in log quick on $EXT_IF proto tcp flags WEUAPRSF/WEUAPRSF
block in log quick on $EXT_IF proto tcp flags SRAFU/WEUAPRSF
block in log quick on $EXT_IF proto tcp flags /WEUAPRSF
block in log quick on $EXT_IF proto tcp flags SR/SR
block in log quick on $EXT_IF proto tcp flags SF/SF

# With modulate state, the Initial Sequence Number (ISN) of outgoing connections is randomized. This is
# useful for protecting connections initiated by certain operating systems that do a poor job of choosing ISNs.
pass out on $EXT_IF proto { tcp, udp, icmp } from any to any modulate state

# Allow my IP address (so I don't get locked out)
pass in quick on $EXT_IF inet from $WHITELIST to any

# normally, a client connects to the server and we handshake with them, then
# proceed to exchange data. by telling pf to handshake proxy between the client
# and our server, tcp syn flood attacts from ddos become uneffective because
# a spoofed client cannot complete a handshake.

# Allows inbound ssh traffic with synproxy handshaking.
pass in on $EXT_IF proto tcp from any to any port $SSH flags S/SA synproxy state

# Allows inbound www traffic with synproxy handshaking.
pass in on $EXT_IF proto tcp from any to any port { 80, 443 } flags S/SA synproxy state

# Allow mail (postfix, dovecot) with synproxy handshaking.
pass in on $EXT_IF proto tcp from any to any port { 25, 143, 587, 993, 995 } flags S/SA synproxy state
pass out on $EXT_IF proto tcp from any to any port { 25, 143, 587, 993, 995 } flags S/SA synproxy state

# Allow ICMP
pass in log quick inet proto icmp all icmp-type $ALLOWED_ICMP_TYPES keep state

# Allow NTP
pass in on $EXT_IF proto { tcp, udp } from any to any port ntp
pass out on $EXT_IF proto { tcp, udp } to any port ntp

table <blacklist> persist
block quick from <blacklist>

# block ssh scanners
pass in quick on $EXT_IF proto tcp from { $WHITELIST } to any port $SSH
pass in log on $EXT_IF proto tcp from any to any port $SSH \
        flags S/SA keep state \
        (max-src-conn-rate 3/30, overload <blacklist> flush global)

One thing I am not sure about is the (2) NTP rules - are they both needed if I only have this running in cron?

Code:
3  0 * * * ntpdate -v -b 0.freebsd.pool.ntp.org >/dev/null 2>&1

Any input is greatly appreciated!
 
There's no incoming connection with NTP so you can remove the pass in. And you have multiple lines dealing with SSH:
Code:
# Allows inbound ssh traffic with synproxy handshaking.
pass in on $EXT_IF proto tcp from any to any port $SSH flags S/SA synproxy state
<snip>
# block ssh scanners
pass in quick on $EXT_IF proto tcp from { $WHITELIST } to any port $SSH
pass in log on $EXT_IF proto tcp from any to any port $SSH \
        flags S/SA keep state \
        (max-src-conn-rate 3/30, overload <blacklist> flush global)
 
You might want to allow ICMP pings and traceroutes heading outbound.

Code:
# Ping
pass out inet proto icmp all keep state
pass in inet proto icmp all icmp-type $ICMP_TYPES keep state

# Traceroute
pass out on $EXT_IF inet proto udp from $EXT_HOST to any port 33433 >< 33626 keep state
 
Back
Top