Simple web server pf.conf

Features:

  • Default policy is to block and log all traffic that is not specifically allowed. This also affects the outgoing connections initiated by the server, for example DNS lookups. For performance reasons the default policy rule is the last rule. Be careful not to accidentally delete it.
  • If for some reason something is being blocked, you can run tcpdump(1) on the pflog(4) device to see what is going on:
    Code:
    [cmd]#  tcpdump -eni pflog0[/cmd]
    [noparse]tcpdump: WARNING: pflog0: no IPv4 address assigned
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 65535 bytes
    
    13:49:39.025997 rule 17..16777216/0(match): block in on re0: 31.3.237.245.56167 > w.x.y.z.445: Flags [S], seq 14
    74166783, win 512, length 0
    13:54:13.874479 rule 17..16777216/0(match): block in on re0: 109.203.120.115.54579 > w.x.y.z.445: Flags [S], seq
    424673279, win 512, length 0
    13:55:31.353017 rule 17..16777216/0(match): block in on re0: 31.3.237.245.51122 > w.x.y.z.445: Flags [S], seq 51
    8389759, win 512, length 0[/noparse]
  • To review the log file: # tcpdump -tttt -nr /var/log/pflog | less

    To enable logging you need this in /etc/rc.conf:
    Code:
    pflog_enable="YES"
    See rc.conf(5).
  • The rules only specify IPv4 traffic through the inet keyword.
  • Not for security through obscurity, but only to prevent clogging the /var/log/auth.log with unsuccessful ssh connection attempts another port than the default port 22 is being used.
  • The rules are logically ordered by direction (in/out) and protocol (TCP, UDP and ICMP).
  • The quick keyword is used to defeat pf's last matching rule wins strategy.
  • Because pf keeps state by default, the keep state option is not needed anymore.

The pf.conf file:

Code:
# ----------------------- simple server pf.conf ----------------------
# For FreeBSD 9.1
# j65nko 2011, 2012, 2013
#
# If you adapt this ruleset for a resolving caching name server please
# make sure you don't allow the whole world to use your name server
# Creating an open resolving name server can allow the bad guys to use your nameserver
# in an DNS amplification attack

ext_if="re0"
icmp_types="echoreq"

# Custom port for ssh
SSH_CUSTOM = xxxx

scrub in on $ext_if all fragment reassemble

set skip on lo0
#set skip on lo1

antispoof for $ext_if

# --- EXTERNAL INTERFACE
# --- INCOMING -------------------------------------------------------------------

# --- TCP
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port http
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port https
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port $SSH_CUSTOM

# --- for authoritative DNS server
#pass in  quick on $ext_if inet proto udp from any to $ext_if  port domain

# --- UDP
# --- for authoritative DNS server
#pass in  quick on $ext_if inet proto udp from any to $ext_if  port domain

# --- ICMP
pass in  quick on $ext_if inet proto icmp from any to $ext_if icmp-type $icmp_types

# --- EXTERNAL INTERFACE
# --- OUTGOING --------------------------------------------------------------------

anchor TMP

# --- TCP
pass  out quick log on $ext_if inet proto tcp from $ext_if to any port smtp
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port domain
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port http
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port https
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port whois
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port $SSH_CUSTOM

# --- UDP
pass  out quick on $ext_if inet proto udp from $ext_if to any port domain
pass  out quick on $ext_if inet proto udp from $ext_if to any port ntp

# --- ICMP
pass  out quick on $ext_if inet proto icmp  from $ext_if to any

# ------------------------------------------------------
# --- DEFAULT POLICY
# ------------------------------------------------------
block log all

# ----- end of pf.conf

A test load of the rules with # pfctl -vvnf /etc/pf.conf:
Code:
ext_if = "re0"
icmp_types = "echoreq"
SSH_CUSTOM = "xxxx"
set skip on { lo0 }
@0 scrub in on re0 all fragment reassemble
@0 block drop in on ! re0 inet from w.x.y.z/27 to any
@1 block drop in inet from w.x.y.z to any
@2 block drop in on re0 inet6 from fe80::21d:92ff:fe63:4195 to any
@3 pass in quick on re0 inet proto tcp from any to w.x.y.z port = http flags S/SA keep state
@4 pass in quick on re0 inet proto tcp from any to w.x.y.z port = https flags S/SA keep state
@5 pass in quick on re0 inet proto tcp from any to w.x.y.z port = xxxx flags S/SA keep state
@6 pass in quick on re0 inet proto icmp from any to w.x.y.z icmp-type echoreq keep state
@7 anchor "TMP" all
@8 pass out log quick on re0 inet proto tcp from w.x.y.z to any port = smtp flags S/SA keep state
@9 pass out quick on re0 inet proto tcp from w.x.y.z to any port = domain flags S/SA keep state
@10 pass out quick on re0 inet proto tcp from w.x.y.z to any port = http flags S/SA keep state
@11 pass out quick on re0 inet proto tcp from w.x.y.z to any port = https flags S/SA keep state
@12 pass out quick on re0 inet proto tcp from w.x.y.z to any port = nicname flags S/SA keep state
@13 pass out quick on re0 inet proto tcp from w.x.y.z to any port = xxxx flags S/SA keep state
@14 pass out quick on re0 inet proto udp from w.x.y.z to any port = domain keep state
@15 pass out quick on re0 inet proto udp from w.x.y.z to any port = ntp keep state
@16 pass out quick on re0 inet proto icmp from w.x.y.z to any keep state
@17 block drop log all
 
Last edited:
Thanks for this.

Question: how to make FTP work in this as well, I implemented a bit and am now stuck with FTP.

Help will be appreciated!
 
Back
Top