.\" $OpenBSD: pf.conf.5,v 1.29 2002/01/09 11:30:53 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 .Xr pf 4 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 ] [ route ] [ af ] [ "proto" ( proto-name | proto-number | "{" proto-list "}" ) ] hosts [ flags ] ( [ icmp-type ] | [ ipv6-icmp-type ] ) [ "keep state" ] [ "modulate state" ] [ "no-df" ] [ "min-ttl" number ] [ "allow-opts" ] [ "label" string ] . action = "pass" | "block" [ return ] | "scrub" . return = "return-rst" | "return-icmp" [ "(" ( icmp-code-name | icmp-code-number ) ")" ] | "return-icmp6" [ "(" ( icmp-code-name | icmp-code-number ) ")" ] . af = "inet" | "inet6" . proto-list = ( proto-name | proto-number ) [ "," proto-list ] . hosts = "all" | "from" ( "any" | host | "{" host-list "}" ) [ port ] "to" ( "any" | host | "{" host-list "}" ) [ port ] . host = [ "!" ] address [ "/" mask-bits ] . host-list = host [ "," host-list ] . port = "port" ( unary-op | binary-op | "{" port-list "}" ) . port-list = ( unary-op | binary-op ) [ "," port-list ] . unary-op = ( "=" | "!=" | "<" | "<=" | ">" | ">=" ) ( port-name | port-number ) . binary-op = port-number ( "<>" | "><" ) port-number . flags = "flags" ( flag-set | flag-set "/" flag-set | "/" flag-set ) . flag-set = [ "F" ] [ "S" ] [ "R" ] [ "P" ] [ "A" ] [ "U" ] . icmp-type = "icmp-type" ( icmp-type-code | "{" icmp-list "}" ) . ipv6-icmp-type = "ipv6-icmp-type" ( icmp-type-code | "{" icmp-list "}" ) . icmp-type-code = ( icmp-type-name | icmp-type-number ) [ "code" ( icmp-code-name | icmp-code-number ) ] . icmp-list = icmp-type-code [ "," icmp-list ] . route = "fastroute" | "route-to" interface-name[":"address] | "dup-to" interface-name[":"address] .Ed .Sh FILTER RULES Filter rules are typically manipulated using .Xr pfctl 8 . 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 .Em pass . .Pp To block everything by default and only pass packets that match explicit rules, one uses .Bd -literal .Cm block in all .Cm block out all .Ed .Pp as the first two rules. .Sh ACTIONS .Bl -tag -width Fl .It Em pass The packet is passed. .It Em block The packet is blocked. Optionally, the filter can return a TCP RST or ICMP UNREACHABLE packet to the sender, where applicable. .It Em scrub The packet is run through normalization/defragmentation. Scrub rules are not considered last matching rules. IPv6 packets are not defragmented. .El .Sh LOGGING .Bl -tag -width Fl .It Em log In addition to the action specified, a log message is generated. .It Em log-all Used with .Sq keep state or .Sq modulate state rules. Not only the packet that creates state is logged, but all packets of the connection. .El .Pp The logged packets are sent to the .Em pflog0 interface. This interface is monitored by the .Xr pflogd 8 logging daemon which dumps the logged packets to the file .Em /var/log/pflog in .Xr tcpdump 8 binary format. The log files can be read using tcpdump: .Bd -literal .Cm # tcpdump -n -e -ttt -r /var/log/pflog .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 ROUTING If a packet matches a rule with a route option set, the packet filter will route the packet according to the type of route option. .Ss fastroute The .Em fastroute option does a normal route lookup to find the next hop for the packet. .Ss route-to The .Em route-to option routes the packet to the specified interface with an optional address for the next hop. .Ss dup-to The .Em dup-to option creates a duplicate of the packet and routes it like .Em route-to. The original packet gets routed as it normally would. .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. Certain parameters can be expressed as lists, in which case .Em pfctl generates all needed rule combinations. .Ss in or out The rule applies to incoming or outgoing packets. Either .Em in or .Em out must be specified. To cover both directions, two rules are needed. .Ss on The rule applies only to packets coming in on or going out through this particular interface. .Ss The rule applies only to packets of this address family. Supported values are inet and inet6. .Ss proto The rule applies only to packets of this protocol. Common protocols used here are tcp, udp, icmp and ipv6-icmp. .Ss from port to port The rule applies only to packets with the specified source and destination addresses/ports. .Pp Addresses can be specified in CIDR notation (matching netblocks), as symbolic host names or interface names. Host name resolution and interface to address translation are done at rule set load-time. When the address of an interface (or host name) changes (by DHCP or PPP, for instance), the rule set must be reloaded for the change to be reflected in the kernel. See .Xr dhclient-script 8 or .Xr ppp 8 for information on how to automate this task. .Pp 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 Em port 2000 >< 2004 means .Sq all ports > 2000 and < 2004 , hence ports 2001, 2002 and 2003. .It Em 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 proto tcp from any port <= 1024 to any pass in proto tcp from any to any port = 25 pass in proto tcp from 10.0.0.0/8 port > 1024 to ! 10.1.2.3 port != 22 .Ed .Ss flags | / | / The rule only applies to TCP packets that have the flags set out of set . Flags not specified in are ignored. Possible flags are F (FIN), S (SYN), R (RST), P (PUSH), A (ACK) and U (URG). .Bl -tag -width Fl .It Em flags S/S Flag SYN is set. The other flags are ignored. .It Em 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 Em 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. .It Em flags /SFRA If the first set is not specified, it defaults to none. All of SYN, FIN, RST and ACK must be unset. .El .Ss icmp-type code and ipv6-icmp-type code The rule only applies to ICMP or ICMPv6 packets with the specified type and code. This parameter is only valid for rules that cover protocols icmp or ipv6-icmp. The protocol and the icmp type indicator (icmp-type or ipv6-icmp-type) must match. .Ss allow-opts By default, packets which contain IP options are blocked. When .Em allow-opts is specified for a .Em pass rule, packets that pass the filter based on that rule (last matching) do so even if they contain IP options. For packets that match state, the rule that initially created the state is used. The implicit .Em pass rule that is used when a packet doesn't match any rules does not allow IP options. .Ss label Adds a label (name) to the rule, which can be used to identify the rule. For instance, .Em pfctl -s labels shows per-rule statistics for rules that have labels. .Sh MACROS .Em pfctl supports macro definition and expansion like: .Bd -literal ext_if = "kue0" pass out on $ext_if from any to any keep state pass in on $ext_if from any to any port = 25 keep state .Ed .Pp Macro names must start with a letter and may contain letters, digits and underscores. Macros are not expanded recursively. .Sh STATEFUL INSPECTION .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, one 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 timed 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 one has 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 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. One can also be less restrictive, and allow state creation from intermediate .Pq non-SYN packets. This will cause .Em pf to synchronize to existing connections, for instance if one flushes 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 one keeps 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 inet 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 implicitly create state for connections. .Sh STATE MODULATION Much of the security derived from TCP is attributable to how well the initial sequence numbers (ISNs) are chosen. Some popular stack implementations choose .Cm very poor ISNs thus are normally susceptible to ISN prediction exploits. By applying a "modulate state" rule to a TCP connection, .Em pf will create a high quality random sequence number for each connection endpoint. .Pp The "modulate state" directive implicitly keeps state on the rule and is only applicable to TCP connections. .Pp For instance: .Bd -literal block out all block in all pass out proto tcp from any to any modulate state pass in proto tcp from any to any port = 25 flags S/SA modulate state .Ed .Pp Caveat: If .Em pf picks up an already established connection (the firewall was rebooted, the state table was flushed, ...) it will not randomize the sequence number and it will fall back to operating as if "keep state" was specified for that connection. .Pp Caveat: If the state table is flushed or the firewall is rebooted, currently established modulated connections can not be continued or picked up again by the firewall. The sequence numbers will be out of sync without the modulator. .Sh NORMALIZATION Packet normalization is invoked via the .Pa scrub directive. Normalization is used to sanitize packet content in such a way that there are no ambiguities in packet interpretation on the receiving side. .Pp The normalizer does full IP fragment reassembly to prevent attacks that confuse intrusion detection systems by sending overlapping IP fragments. .Ss no-df Clears the .Pa dont-fragment bit from a matching ip packet. .Ss min-ttl Enforces a minimum ttl for matching ip packets. .Sh EXAMPLES .Bd -literal # The external interface is kue0 (157.161.48.183, the only routable address) # and the private network is 10.0.0.0/8, for which we are doing NAT. # use a macro for the interface name, so it can be changed easily ext_if = "kue0" # normalize all incoming traffic scrub in on $ext_if all # block and log everything by default block out log on $ext_if all block in log on $ext_if all block return-rst out log on $ext_if proto tcp all block return-rst in log on $ext_if proto tcp all block return-icmp out log on $ext_if proto udp all block return-icmp in log on $ext_if proto udp all # block and log outgoing packets that don't have our 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 $ext_if from ! 157.161.48.183 to any # silently drop broadcasts (cable modem noise) block in quick on $ext_if 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 $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 # 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 $ext_if inet proto icmp all icmp-type 8 code 0 keep state pass in on $ext_if inet proto icmp all icmp-type 8 code 0 keep state # UDP # pass out all UDP connections and keep state pass out on $ext_if proto udp all keep state # pass in certain UDP connections and keep state (DNS) pass in on $ext_if proto udp from any to any port = domain keep state # TCP # pass out all TCP connections and modulate state pass out on $ext_if proto tcp all modulate state # pass in certain TCP connections and keep state (SSH, SMTP, DNS, IDENT) pass in on $ext_if proto tcp from any to any port { ssh, smtp, domain, \\ auth } keep state # pass in data mode connections for ftp-proxy running on this host. # (see ftp-proxy(8) for details) pass in on $ext_if proto tcp from any to 157.161.48.183 port >= 41952 \\ 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 , .Xr pflogd 8 .Sh HISTORY The .Nm file format appeared in .Ox 3.0 .