Solved pf syntax clarification and feedback

Hello all,

I have been trying to writes my pf(4) firewall rule from various online articles and the help from the forum. I finally reached the end of my pf rule writing.

I would however really appreciate a little bit more help in the following area:

Why can I not ssh to the box anymore using my rules?

Is the single line
Code:
block drop in log on $ExtIf
the same as this 2 lines:
Code:
block in all
block log all

Is using
Code:
scrub in all no-df max-mss 1440
better that using
Code:
scrub  log on $ExtIf all reassemble tcp fragment reassemble

And finally, where in my config file do I need to place this?
Code:
antispoof quick for ($ExtIf) inet
I don't have IPv6 setup on my vps, so should I be blocking IPv6 traffic:
Code:
block out quick inet6 all
block in quick inet6 all

I would also welcome any feedback on this piece of work.
Bellow id my /etc/pf.conf file
Code:
################ FreeBSD pf.conf ##########################
# Required order: options, normalization, queueing, translation, filtering.
# Note: translation rules are first match while filter rules are last match.
#
#  Command                          Purpose
#  pfctl -e                         Enable PF
#  pfctl -d                         Disable PF
#  pfctl -f /etc/pf.conf            Tell pf to re-read the pf.conf file after I make a change
#  pfctl -F all -f /etc/pf.conf     Flush all rules (nat, filter, state, table, etc.)
#                                   and reload from the file /etc/pf.conf
#  pfctl -s [ rules | nat | state ] Report on the filter rules, nat rules, or state table
#  pfctl -vnf /etc/pf.conf          Check /etc/pf.conf for errors, but do not load ruleset
#  pfctl -t <TABLENAME> -T show     see what ip addresses are in the abusive hosts tables
#  pfctl -vvs rules | grep @        List out the pf rules in order with rule numbers
#  pfctl -sa                        List out all the pf rules and other options in my rules
#  tcpdump -n -e -ttt -i pflog0     Watch the pf logs in real time
#  tcpdump -n -e -ttt -r pflog0     Cat the pf log file


################ Change History ##########################
# * 2015-07-24  This file was created
# *


################ Macros ###################################
### Interfaces ###
ExtIf ="xn0"
JailIf ="lo1"

### Hosts ###
# OpenSMTPD = "10.10.10.4"
WebProxy  = "10.8.20.11"

### Queues, States and Types ###
IcmpPing ="icmp-type 8 code 0"
SshQueue ="(ssh_bulk, ssh_login)"
SynState ="flags S/SA synproxy state"
#TcpState ="flags S/SA synproxy state"
TcpState ="flags S/SA modulate state"
UdpState ="keep state"

### Stateful Tracking Options (STO) ###
OpenSTO ="(max 90000, source-track rule, max-src-conn 1000, max-src-nodes 256)"
SmtpSTO ="(max   200, source-track rule, max-src-conn   10, max-src-nodes 256, max-src-conn-rate 200/30)"
SshSTO  ="(max   100, source-track rule, max-src-conn   10, max-src-nodes 100, max-src-conn-rate 100/30,  overload <BLOCKTEMP> flush global)"
WebSTO  ="(max  4096, source-track rule, max-src-conn   64, max-src-nodes 512, max-src-conn-rate 500/100, overload <BLOCKTEMP> flush global)"

### Tables ###
#table <spamd-white>
#table <BLACKLIST> persist persist "/var/db/pf/blacklist/blacklist.zone"
table <TRUSTED> persist file "/etc/pf-files/trusted.pftable"
table <BLOCKEDZONE> persist file "/etc/pf-files/deniedzones.pftable"
table <BLOCKTEMP> counters file "/etc/pf-files/fail2ban.pftable"
table <BLOCKNETS> {224.0.0.22, 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \
                    169.254.0.0/16, 192.0.2.0/24, \
                    192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, \
                    169.254.0.0/16, 0.0.0.0/8, 240.0.0.0/4, 255.255.255.255/32}

################ Options ######################################################
### Misc Options
set skip on lo
set debug urgent
set block-policy drop
set loginterface $ExtIf
set state-policy if-bound
set fingerprints "/etc/pf.os"
set ruleset-optimization none

### Timeout Options
set optimization normal
set timeout { tcp.closing 60, tcp.established 7200}

################ Queueing ####################################################
# no quality of service (QOS) since QoS controls is monitored and rate shaped by the VPS data centre.

################ Normalization ###############################################
# set-tos 0x1c is Maximize-Reliability + Minimize-Delay + Maximize-Throughput
#scrub out log on $ExtIf all random-id min-ttl 15 set-tos 0x1c fragment reassemble
scrub     log on $ExtIf all reassemble tcp fragment reassemble

################ Translation #################################################
### NAT and Redirection rules are first match

# NAT all jail traffic
nat on $ExtIf from $JailIf:network  to any -> ($ExtIf)
#nat on $ExtIf from $IntIf:network   to any -> ($ExtIf)
# Hiawatha web server
rdr on $ExtIf inet proto tcp from  !($ExtIf) to ($ExtIf) port https -> $WebProxy
rdr on $ExtIf inet proto tcp from  !($ExtIf) to ($ExtIf) port http  -> $WebProxy

# OpenSMTPD with Spamd
#rdr on $ExtIf inet proto tcp from !<spamd-white> to ($ExtIf) port smtp -> 10.10.10.200 port spamd
#rdr on $ExtIf inet proto tcp from  <spamd-white> to ($ExtIf) port smtp -> 10.10.10.250
# Openssh
rdr on $ExtIf inet proto tcp from <TRUSTED> to ($ExtIf) port ssh -> lo0

# Unbound DNS for LAN machines
#rdr on $IntIf inet proto udp from $IntIf:network to $IntIf port domain -> lo0
# Ntpd time server for the LAN
#rdr on $IntIf inet proto udp from $IntIf:network to $IntIf port ntp -> lo0

# Anchors
#nat-anchor "openvpn"
#rdr-anchor "openvpn"

# DENY rogue redirection
no rdr

################ Filtering ###################################################
# Rules are best (closest) match. Rules are optimized so external
# interface parsing is first followed by the internal interface.

### $ExtIf block abusive hosts in temp and blacklist tables
#block in quick on $ExtIf from                     <BLACKLIST> to any
block drop in log quick from { <BLOCKNETS> urpf-failed no-route } to any
block out quick on $ExtIf from any to { <BLOCKNETS> no-route }
block drop in log quick on $ExtIf proto udp from <BLOCKTEMP> to any
block drop in log quick on $ExtIf proto tcp from <BLOCKTEMP> to any port != ssh
block drop in log quick on $ExtIf proto tcp from <BLOCKEDZONE> to any port { 22 80 443 }

### $ExtIf default block with drop
block drop in log on $ExtIf

### $ExtIf inbound
pass in log on $ExtIf inet proto tcp  from !($ExtIf)      to $WebProxy port https $TcpState $WebSTO
pass in log on $ExtIf inet proto tcp  from !($ExtIf)      to $WebProxy port www   $TcpState $WebSTO
pass in log on $ExtIf inet proto tcp  from  <TRUSTED>     to lo0 port ssh   $TcpState $SshSTO

### $ExtIf outbound
pass out log on $ExtIf inet proto tcp  from ($ExtIf) to !($ExtIf) $TcpState $OpenSTO
pass out log on $ExtIf inet proto udp  from ($ExtIf) to !($ExtIf) $UdpState $OpenSTO
pass out log on $ExtIf inet proto icmp from ($ExtIf) to !($ExtIf) $UdpState $OpenSTO
Thank you
 
Last edited by a moderator:
Is the single line block drop in log on $ExtIf the same as this 2 lines:
Code:
block in all
block log all
No. The second statement is the same as
Code:
block log in
block log out
If there's no direction (in or out) the rule applies to both, the statement "all" is short for "from any to any" and there's no interface so it applies to all interfaces. Your initial statement blocks incoming traffic on $Extif only.

Code:
block out quick inet6 all
block in quick inet6 all
These two can be replaced with a single line:
Code:
block quick inet6
Again, there's no direction so it applies to both. And in this case you don't have to add "all", it's implied.
 
Your no rdr line is basically a no-nop, it does nothing if it actually passes the rule syntax check, does it? If it does pass the syntax check it won't stop any unwanted traffic nor does it actually affect rules placed before or after it because any other rdr that has more qualifiers in it will be more specific and overrides your no rdr rule.
 
Thank you you for clarifying these points guys, Its really appreciated. The no rdr does indeed pass syntax check but I have now removed it as you suggested..
Could you see why I am no longer able to ssh to the box?
should the line
Code:
pass in log on $ExtIf inet proto tcp from <TRUSTED> to lo0 port ssh $TcpState $SshSTO
be changed for
Code:
pass in log on $ExtIf inet proto tcp from <TRUSTED> to $ExtIf port ssh $TcpState $SshSTO
instead?
 
Last edited by a moderator:
Did you solve your SSH problem ?

I would test the second rule with the "quick" and without:
-> $TcpState
-> $SshSTO
-> inet

Something like:

Code:
pass in quick log on $ExtIf proto tcp from <TRUSTED> to $ExtIf port ssh
 
The quick keyword "short-circuits" the rules, if the rule matches it will stop processing the other rules. Remember that PF doesn't stop if a rule matches, it will process all the rules.
 
A tcpdump(1) on your pflog0 interface is the best option to troubleshoot your ruleset.

It'll show what your firewall is doing with packets.

Code:
tcpdump -n -e -ttt -i pflog0

There are many good guides about pf setup.

Although based on OpenBSD, this one helped me a lot when I was starting (The original page is down from where I am, so I'm posting the Google cache link)

A Newbie's Guide to Setting up PF on OpenBSD 4.x

Another helpful pf knowledge base: Peter's Firewalling with PF
 
I've also often used # pfctl -sr -v to see which rules are actually creating states (the States: counters). That will very quickly show if a rule is evaluated but is not the last rule matching the traffic if the states counter stays at zero for the rule.
 
Hi guys,

I am still stuck.
Tried both...
Code:
pass in quick log on $ExtIf proto tcp from <TRUSTED> to $ExtIf port ssh
and
Code:
pass in quick log on $ExtIf proto tcp from any to $ExtIf port ssh
And I still cannot ssh to my machine :(
Code:
ssh: connect to host 206.35.6.9 port 22: Connection timed out
 
Remove this line:
Code:
rdr on $ExtIf inet proto tcp from <TRUSTED> to ($ExtIf) port ssh -> lo0
It's not needed and may be the cause of the problem. Just make sure sshd(8) is listening on the external address.
 
Just last question on this thread please.
Where do I put the line bellow? Do I need i?
Code:
antispoof quick for ($ExtIf) inet
 
Just last question on this thread please.
Where do I put the line bellow? Do I need i?
Code:
antispoof quick for ($ExtIf) inet

It is useful if you don't trust your users or the WAN network where your firewall connects directly to. It will expand to a set of block rules as described in the pf.conf(5) manual page:

Code:
"Spoofing" is the faking of IP addresses, typically for malicious pur-
poses. The antispoof directive expands to a set of filter rules which
will block all traffic with a source IP from the network(s) directly con-
nected to the specified interface(s) from entering the system through any
other interface.

For example, the line

antispoof for lo0

expands to

block drop in on ! lo0 inet from 127.0.0.1/8 to any
block drop in on ! lo0 inet6 from ::1 to any

The best place for the rule is at the beginning of the ruleset where you already have rules for blocking unwanted traffic.
 
Will it be ok in that block?
Code:
### $ExtIf default block with drop
block drop in log on $ExtIf
antispoof quick log for $ExtIf inet
antispoof log quick for $ExtIf label "Spoofed"
block quick inet6
 
Back
Top