NAME
npf.conf —
NPF packet filter
configuration file
DESCRIPTION
npf.conf is the default configuration file for the NPF packet
filter.
This manual page serves as a reference for editing
npf.conf.
Please refer to the official NPF documentation for comprehensive and in-depth
information.
There are multiple structural elements
npf.conf may contain:
variable and
table definitions (with or
without content), abstraction
groups, packet filtering
rules,
map rules for address translation
and
procedure definitions to call on filtered packets. The
minimal
npf.conf must contain a mandatory
default group.
SYNTAX
Variables
Variables are specified using the dollar ($) sign, which is used both in
definitions and uses of a variable. Variables are defined by assigning a value
to them as follows:
A variable may also be defined as a set:
$var2 = { 10.0.0.1, 10.0.0.2 }
Common variable definitions are for IP addresses, networks, ports, and
interfaces.
Tables
Tables are specified using a name between angle brackets < and >. The
following is an example of table definition:
table <black> type hash dynamic
Currently, tables support three storage types: "hash",
"tree", or "cdb". They can also be "dynamic" or
static i.e. loaded from the specified file.
The file should contain a list of IP addresses and/or networks in the form of:
Tables of type "hash" and "cdb" can only contain IP
addresses. Also, the latter can only be static.
Interfaces
Interfaces can be specified as the values of the variables:
$pub_if_list = { inet4(wm0), inet4(wm1) }
In the context of filtering, an interface provides a list of its all IP
addresses, including IPv4 and IPv6. Specific interface addresses can be
selected by the family, e.g.:
$pub_if4 = inet4(wm0)
$pub_if46 = { inet4(wm0), inet6(wm0) }
In the above examples, NPF will statically capture the interface addresses on
configuration load.
The following can be used for dynamic handling of the interface addresses:
In this case, the expression will represent the runtime list of addresses,
reflecting any changes to the interface, including the attach and detach.
Marking the interface as ``down'' has no effect, i.e. all addresses will
remain present.
The dynamic address list represents both the IPv4 and IPv6 addresses, therefore
the
family keyword can be used in combination to make the
filtering more narrow.
Groups
Groups may have the following options: name, interface, and direction. They are
defined in the following form:
group "my-name" in on wm0 {
# List of rules
}
Rules
With a rule statement NPF is instructed to
pass or
block a packet depending on packet header information,
transit direction and interface it arrives on, either immediately upon match
(keyword
final) or using the last match. The rule can also
instruct NPF to create an entry in the state table when passing the packet, to
notify the sender when blocking it, and to apply a procedure to the packet
(e.g. "log") in either case.
A "fully-featured" rule would for example be:
pass stateful in final family inet4 proto tcp flags S/SA \
from $source port $sport to $dest port $dport apply "someproc"
Any protocol in
/etc/protocols can be specified. Further
packet specification at present is limited to protocol TCP understanding
flags, TCP and UDP understanding source and destination ports, and ICMP and
IPv6-ICMP understanding icmp-type.
Alternatively, NPF supports
pcap-filter(7) syntax, for
example:
block out final pcap-filter "tcp and dst 10.1.1.252"
Fragments are not selectable since NPF always reassembles packets before further
processing.
Stateful
Stateful packet inspection is enabled using
stateful or
stateful-ends keywords. The former creates a state which is
uniquely identified by a 5-tuple (source and destination IP addresses, port
numbers and an interface identifier). The latter excludes the interface
identifier and must be used with precaution. In both cases, a full TCP state
tracking is performed for TCP connections and a limited tracking for
message-based protocols (UDP and ICMP).
By default, a stateful rule implies SYN-only flag check ("flags
S/SAFR") for the TCP packets. It is not advisable to change this
behavior; however, it can be overridden with the
flags
keyword.
Map
Network Address Translation (NAT) is expressed in a form of segment mapping. The
translation may be dynamic (stateful) or static (stateless). The following
mapping types are available:
- ->
- outbound NAT (translation of the source)
- <-
- inbound NAT (translation of the destination)
- <->
- bi-directional NAT (combination of inbound and outbound
NAT)
The following would translate the source to the IP address specified by the
$pub_ip for the packets on the interface $ext_if.
map $ext_if dynamic 10.1.1.0/24 -> $pub_ip
Translations are implicitly filtered by limiting the operation to the network
segments specified, that is, translation would be performed only on packets
originating from 10.1.1.0/24 network. Explicit filter criteria can be
specified using "pass <criteria>" as an additional option of
the mapping.
Procedures
A rule procedure is defined as a collection of extension calls (it may have
none). Every extension call has a name and a list of options in the form of
key-value pairs. Depending on the call, the key might represent the argument
and the value might be optional. For example:
procedure "someproc" {
log: npflog0
normalize: "random-id", "min-ttl" 64, "max-mss" 1432
}
In this case, the procedure calls the logging and normalisation modules. The
logging facility requires the npf_ext_log kernel module which would normally
get auto-loaded by NPF. The specified npflog interface would also be
auto-created once the configuration is loaded. The log packets can be written
to a file using the
npfd(8)
daemon.
Traffic normalisation has a set of different mechanisms. In the example above,
the normalisation procedure has arguments which apply the following
mechanisms: IPv4 ID randomisation, Don't Fragment (DF) flag cleansing, minimum
TTL enforcement and TCP MSS "clamping".
Misc
Text after a hash (‘#’) character is considered a comment. The
backslash (‘\’) character at the end of a line marks a
continuation line, i.e., the next line is considered an extension of the
present line.
GRAMMAR
The following is a non-formal BNF-like definition of the grammar. The definition
is simplified and is intended to be human readable, therefore it does not
strictly represent the formal grammar.
; Syntax of a single line. Lines can be separated by LF (\n) or
; a semicolon. Comments start with a hash (#) character.
syntax = var-def | set-param | alg | table-def |
map | group | rproc | comment
; Variable definition. Names can be alpha-numeric, including "_" character.
var-name = "$" . string
interface = interface-name | var-name
var-def = var "=" ( var-value | "{" value *[ "," value ] "}" )
; Parameter setting.
set-param = "set" param-value
; Application level gateway. The name should be in the double quotes.
alg = "alg" alg-name
; Table definition. Table ID shall be numeric. Path is in the double quotes.
table-id = <table-name>
table-def = "table" table-id "type" ( "hash" | "tree" | "cdb" )
( "dynamic" | "file" path )
; Mapping for address translation.
map = "map" interface
( "static" [ "algo" algorithm ] | "dynamic" )
[ map-flags ] [ proto ]
net-seg ( "->" | "<-" | "<->" ) net-seg
[ "pass" [ proto ] filt-opts ]
map-flags = "no-ports"
; Rule procedure definition. The name should be in the double quotes.
;
; Each call can have its own options in a form of key-value pairs.
; Both key and values may be strings (either in double quotes or not)
; and numbers, depending on the extension.
proc = "procedure" proc-name "{" *( proc-call [ new-line ] ) "}"
proc-opts = key " " val [ "," proc-opts ]
proc-call = call-name ":" proc-opts new-line
; Group definition and the rule list.
group = "group" ( "default" | group-opts ) "{" rule-list "}"
group-opts = name-string [ "in" | "out" ] [ "on" interface ]
rule-list = [ rule new-line ] rule-list
npf-filter = [ "family" family-opt ] [ proto ] ( "all" | filt-opts )
static-rule = ( "block" [ block-opts ] | "pass" )
[ "stateful" | "stateful-ends" ]
[ "in" | out" ] [ "final" ] [ "on" interface ]
( npf-filter | "pcap-filter" pcap-filter-expr )
[ "apply" proc-name ]
dynamic-ruleset = "ruleset" group-opts
rule = static-rule | dynamic-ruleset
proto = "proto" protocol [ proto-opts ]
block-opts = "return-rst" | "return-icmp" | "return"
family-opt = "inet4" | "inet6"
proto-opts = "flags" tcp-flags [ "/" tcp-flag-mask ] |
"icmp-type" type [ "code" icmp-code ]
addr-mask = addr [ "/" mask ]
filt-opts = "from" filt-addr [ port-opts ] "to" filt-addr [ port-opts ]
filt-addr = [ "!" ] [ interface | var-name |
addr-mask | table-id | "any" ]
filt-port = "port" ( port-num | port-from "-" port-to | var-name )
FILES
- /dev/npf
- control device
- /etc/npf.conf
- default configuration file
- /usr/share/examples/npf
- directory containing further examples
EXAMPLES
$ext_if = { inet4(wm0) }
$int_if = { inet4(wm1) }
table <blacklist> type hash file "/etc/npf_blacklist"
table <limited> type tree dynamic
$services_tcp = { http, https, smtp, domain, 6000, 9022 }
$services_udp = { domain, ntp, 6000 }
$localnet = { 10.1.1.0/24 }
alg "icmp"
# Note: if $ext_if has multiple IP address (e.g. IPv6 as well),
# then the translation address has to be specified explicitly.
map $ext_if dynamic 10.1.1.0/24 -> $ext_if
map $ext_if dynamic proto tcp 10.1.1.2 port 22 <- $ext_if port 9022
procedure "log" {
# The logging facility can be used together with npfd(8).
log: npflog0
}
group "external" on $ext_if {
pass stateful out final all
block in final from <blacklist>
pass stateful in final family inet4 proto tcp to $ext_if port ssh apply "log"
pass stateful in final proto tcp to $ext_if port $services_tcp
pass stateful in final proto udp to $ext_if port $services_udp
pass stateful in final proto tcp to $ext_if port 49151-65535 # Passive FTP
pass stateful in final proto udp to $ext_if port 33434-33600 # Traceroute
}
group "internal" on $int_if {
block in all
block in final from <limited>
# Ingress filtering as per BCP 38 / RFC 2827.
pass in final from $localnet
pass out final all
}
group default {
pass final on lo0 all
block all
}
SEE ALSO
bpf(4),
npf(7),
pcap-filter(7),
npfctl(8),
npfd(8)
HISTORY
NPF first appeared in
NetBSD 6.0.
AUTHORS
NPF was designed and implemented by
Mindaugas
Rasiukevicius.