I would appreciate any donations. Wishlist or send e-mail type donations to maekawa AT daemon-systems.org.

Thank you.

NPF.CONF(5)                   File Formats Manual                  NPF.CONF(5)

     npf.conf - NPF packet filter configuration file

     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

     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.

     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:

     $var1 =

     A variable may also be defined as a set:

     $var2 = {, }

     Common variable definitions are for IP addresses, networks, ports, and

     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 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

     $pub_if = ifaddrs(wm0)

     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 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

     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"

     Fragments are not selectable since NPF always reassembles packets before
     further processing.

     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.

     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 -> $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 network.  Explicit filter
     criteria can be specified using "pass <criteria>" as an additional option
     of the mapping.

     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.
     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".

     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.

     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 full syntax, which is more flexible.

     ; 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" ) [ proto ]
                       net-seg ( "->" | "<-" | "<->" ) net-seg
                       [ "pass" [ proto ] filt-opts ]

     ; 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 )

     /dev/npf                 control device
     /etc/npf.conf            default configuration file
     /usr/share/examples/npf  directory containing further 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 = { }

     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 -> $ext_if
     map $ext_if dynamic proto tcp port 22 <- $ext_if port 9022

     procedure "log" {
             # Note: npf_ext_log kernel module should be loaded, if not built-in.
             # Also, the interface created, e.g.: ifconfig npflog0 create
             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

     bpf(4), npf(7), pcap-filter(7), npfctl(8)

     NPF first appeared in NetBSD 6.0.

     NPF was designed and implemented by Mindaugas Rasiukevicius.

NetBSD 8.0                     January 19, 2017                     NetBSD 8.0