1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
|
.\" $OpenBSD: pf.conf.5,v 1.5 2001/07/16 15:41:59 dhartmei Exp $
.\"
.\" Copyright (c) 2001, Daniel Hartmeier
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\"
.\" - Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" - Redistributions in binary form must reproduce the above
.\" copyright notice, this list of conditions and the following
.\" disclaimer in the documentation and/or other materials provided
.\" with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd July 8, 2001
.Dt PF.CONF 5
.Os
.Sh NAME
.Nm pf.conf
.Nd filter rule configuration file for packet filtering
.Sh DESCRIPTION
The packet filter drops, passes and modifies packets according to the
rules defined in this file.
For each packet inspected by the filter, the set of rules is evaluated
from top to bottom, and the last matching rule decides what action is
performed.
.Sh GRAMMAR
Syntax for filter rules in BNF:
.Bd -literal
rule = action ( "in" | "out" )
[ "log" | "log-all" ] [ "quick" ]
[ "on" interface-name ]
[ "proto" ( proto-name | proto-number ) ]
hosts
[ flags ] [ icmp-type ] [ "keep-state" ] .
action = "pass" | "block" [ return ] | "scrub" .
return = "return-rst" |
"return-icmp" [ "(" ( icmp-code-name | icmp-code-number ) ")" ]
.
hosts = "all" |
"from" ( "any" | host ) [ port ] "to" ( "any" | host ) [ port ]
.
host = [ "!" ] address [ "/" mask-bits ] .
port = "port" ( unary-op | binary-op ) .
unary-op = ( "=" | "!=" | "<" | "<=" | ">" | ">=" )
( port-name | port-number ) .
binary-op = port-number ( "<>" | "><" ) port-number .
flags = "flags" flag-set [ "/" flag-set ] .
flag-set = [ "F" ] [ "S" ] [ "R" ] [ "P" ] [ "A" ] [ "U" ] .
icmp-type = "icmp-type" ( icmp-type-name | icmp-type-number )
[ "code" ( icmp-code-name | icmp-code-number ) ] .
.Ed
.Sh FILTER RULES
Filter rules are loaded from a text file into the kernel using
.Pp
.Cm pfctl -R file
.Pp
which replaces the active rule set with the new one.
The active rule set can be displayed using
.Pp
.Cm pfctl -s r
.Pp
For each packet processed by the packet filter, the filter rules are
evaluated in sequential order, from first to last.
Each rule either matches the packet or doesn't.
The last matching rule decides what action is taken.
.Pp
If no rule matches the packet, the default action is pass.
If you rather want to block everything by default and only pass packets
that match explicit rules, you can achieve this by adding
.Bd -literal
block in all
block out all
.Ed
.Pp
as your first two rules.
.Sh ACTIONS
.Bl -tag -width Fl
.It Li pass
The packet is passed.
.It Li block
The packet is blocked.
Optionally, the filter can return a TCP RST or ICMP UNREACHABLE packet
to the sender, where applicable.
.It Li scrub
The packet is run through normalization/defragmentation.
Scrub rules are not considered last matching rules.
.El
.Sh LOGGING
.Bl -tag -width Fl
.It Li log
In addition to the action specified, a log message is generated.
.It Li log-all
Used with
.Sq keep state
rules.
Not only the packet that creates state is logged, but all packets of
the connection.
.El
.Pp
The log messages can be viewed with tcpdump:
.Bd -literal
ifconfig pflog0 up
tcpdump -n -i pflog0
.Ed
.Sh QUICK
If a packet matches a rule which has the
.Sq quick
option set, this rule
is considered the last matching rule, and evaluation of subsequent rules
is skipped.
.Sh PARAMETERS
The rule parameters specify for what packets a rule applies.
A packet always comes in on or goes out through one interface.
Most parameters are optional.
If a parameter is specified, the rule only applies to packets with
matching attributes.
.Ss in/out
The rule applies to incoming or outgoing packets.
Either in or out must be specified.
To cover both directions, two rules are needed.
.Ss on <interface>
The rule applies only to packets coming in on or going out through this
particular interface.
.Ss proto <protocol>
The rule applies only to packets of this protocol.
Common protocols used here are tcp, udp and icmp.
.Ss from <source> port <source> to <dest> port <dest>
The rule applies only to packets with the specified source and destination
addresses/ports.
Addresses can be specified in CIDR notation (matching netblocks) and ports
can be specified using these operators
.Bd -literal
= (equal), != (unequal), < (lesser), <= (lesser or equal), > (greater),
>= (greater or equal), >< (range) and <> (except range).
.Ed
.Pp
>< and <> are binary operators (they take two arguments), and the range
doesn't include the limits, for instance:
.Bl -tag -width Fl
.It Li port 2000 >< 2004
means
.Sq all ports > 2000 and < 2004 ,
hence ports 2001, 2002 and 2003.
.It Li port 2000 <> 2004
means
.Sq all ports < 2000 or > 2004 ,
hence ports 1-1999 and 2005-65535.
.El
.Pp
The host and port specifications are optional, as the following examples
show:
.Bd -literal
pass in all
pass in from any to any
pass in from any port <= 1024 to any
pass in from any to any port = 25
pass in from 10.0.0.0/8 port > 1024 to ! 10.1.2.3 port != 22
.Ed
.Ss flags <a>[/<b>]
The rule only applies to TCP packets that have the flags <a> set
out of set <b>.
Flags not specified in <b> are ignored.
.Bl -tag -width Fl
.It Li flags S/S
Flag SYN is set.
The other flags are ignored.
.It Li flags S/SA
Of SYN and ACK, exactly SYN is set.
SYN, SYN+PSH, SYN+RST match, but SYN+ACK, ACK and ACK+RST don't.
This is more restrictive than the previous example.
.It Li flags S
If the second set is not specified, it defaults to FSRPAU.
Hence, only packets with SYN set and all other flags unset match this
rule. This is more restrictive than the previous example.
.El
.Ss icmp-type <type> code <code>
The rule only applies to ICMP packets with the specified type and code.
This parameter is only valid for rules that cover protocol icmp.
.Sh KEEP STATE
.Em pf
is a stateful packet filter, which means it can track the state of
a connection.
Instead of passing all traffic to port 25, for instance, you can pass
only the initial packet and keep state.
.Pp
If a packet matches a pass ... keep-state rule, the filter creates
a state for this connection and automatically lets pass all following
packets of that connection.
.Pp
Before any rules are evaluated, the filter checks whether the packet
matches any state.
If it does, the packet is passed without evaluation of any rules.
.Pp
States are removed after the connection is closed or has times out.
.Pp
This has several advantages.
Comparing a packet to a state involves checking its sequence numbers.
If the sequence numbers are outside the narrow windows of expected
values, the packet is dropped.
This prevents spoofing attacks, where the attacker sends packets with
a fake source address/port but doesn't know the connection's sequence
numbers.
.Pp
Also, looking up states is usually faster than evaluating rules.
If you have 50 rules, all of them are evaluated sequentially in O(n).
Even with 50'000 states, only 16 comparisons are needed to match a
state, since states are stored in a binary search tree that allows
searches in O(log2 n).
.Pp
It also makes writing rule sets easier, once you embrace the concept.
You only filter the initial packets and keep state.
All other packets are handled by states.
For instance:
.Bd -literal
block out all
block in all
pass out proto tcp from any to any flags S/SA keep state
pass in proto tcp from any to any port = 25 flags S/SA keep state
.Ed
.Pp
This rule set blocks everything by default.
Only outgoing connections and incoming connection to port 25 are allowed.
The inital packet of each connection has the SYN flag set, will be passed
and creates state.
All further packets of these connections are passed if they match a state.
.Pp
Specifying flags S/SA restricts state creation to the initial SYN
packet of the TCP handshake.
You can also be less restrictive, and allow state creation from
intermediate
.Pq non-SYN
packets.
This will cause pf to synchronize to existing connections, for instance
if you flush the state table.
.Pp
For UDP, which is stateless by nature, keep state will create state
as well.
UDP packets are matched to states using only host addresses and ports.
.Pp
ICMP messages fall in two categories: ICMP error messages, which always
refer to a TCP or UDP packet, are matched against the refered to connection.
If you keep state on a TCP connection, and an ICMP source quench message
refering to this TCP connection arrives, it will be matched to the right
state and get passed.
.Pp
For ICMP queries, keep state creates an ICMP state, and
.Em pf
knows how to match ICMP replies to states.
For example
.Bd -literal
pass out proto icmp all icmp-type echoreq keep state
.Ed
.Pp
lets echo requests
.Pq pings
out, creates state, and matches incoming echo replies correctly to states.
.Pp
Note: nat/rdr rules
.Po
see
.Xr nat.conf 5
.Pc
implicitely create state for connections.
.Sh EXAMPLES
.Bd -literal
# My external interface is kue0 (157.161.48.183, my only routable address)
# and the private network is 10.0.0.0/8, for which i'm doing NAT.
# block and log everything by default
#
block out log on kue0 all
block in log on kue0 all
block return-rst out log on kue0 proto tcp all
block return-rst in log on kue0 proto tcp all
block return-icmp out log on kue0 proto udp all
block return-icmp in log on kue0 proto udp all
# block and log outgoing packets that don't have my address as source,
# they are either spoofed or something is misconfigured (NAT disabled,
# for instance), we want to be nice and don't send out garbage.
#
block out log quick on kue0 from ! 157.161.48.183 to any
# silently drop broadcasts (cable modem noise)
#
block in quick on kue0 from any to 255.255.255.255
# block and log incoming packets from reserved address space and invalid
# addresses, they are either spoofed or misconfigured, we can't reply to
# them anyway (hence, no return-rst).
#
block in log quick on kue0 from 10.0.0.0/8 to any
block in log quick on kue0 from 172.16.0.0/12 to any
block in log quick on kue0 from 192.168.0.0/16 to any
block in log quick on kue0 from 255.255.255.255/32 to any
# -----------------------------------------------------------------------
# ICMP
# -----------------------------------------------------------------------
# pass out/in certain ICMP queries and keep state (ping)
#
# state matching is done on host addresses and ICMP id (not type/code),
# so replies (like 0/0 for 8/0) will match queries
#
# ICMP error messages (which always refer to a TCP/UDP packet) are
# handled by the TCP/UDP states
#
pass out on kue0 proto icmp all icmp-type 8 code 0 keep state
pass in on kue0 proto icmp all icmp-type 8 code 0 keep state
# -----------------------------------------------------------------------
# UDP
# -----------------------------------------------------------------------
# pass out all UDP connections and keep state
#
pass out on kue0 proto udp all keep state
# pass in certain UDP connections and keep state (DNS)
#
pass in on kue0 proto udp from any to any port = domain keep state
# -----------------------------------------------------------------------
# TCP
# -----------------------------------------------------------------------
# pass out all TCP connections and keep state
#
pass out on kue0 proto tcp all keep state
# pass in certain TCP connections and keep state (SSH, SMTP, DNS, IDENT)
#
pass in on kue0 proto tcp from any to any port = ssh keep state
pass in on kue0 proto tcp from any to any port = smtp keep state
pass in on kue0 proto tcp from any to any port = domain keep state
pass in on kue0 proto tcp from any to any port = auth keep state
.Ed
.Sh FILES
.Bl -tag -width "/etc/pf.conf" -compact
.It Pa /etc/pf.conf
.It Pa /etc/services
.El
.Sh SEE ALSO
.Xr pf 4 ,
.Xr nat.conf 5 ,
.Xr services 5 ,
.Xr pfctl 8
.Pp
.Pa http://www.obfuscation.org/ipf/
has an extensive filter rule tutorial which for the most part applies to
.Em pf
as well.
.Sh HISTORY
The
.Nm
file format appeared in
.Ox 3.0 .
|