| NPF.CONF(5) | File Formats Manual | NPF.CONF(5) | 
npf.conf —
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 website for comprehensive and in-depth information.
There are multiple structural elements that
    npf.conf may contain, such as:
$) sign, which
  is used for both definition and referencing of a variable. Variables are
  defined by assigning a value to them as follows:
$var1 = 10.0.0.1A 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.
<’ and
  ‘>’. The following is an example of
  table definition:
table <blocklist> type
  ipsetCurrently, tables support three data storage types:
    ipset, lpm, or
    const. The contents of the table may be pre-loaded
    from the specified file. The const tables are
    immutable (no insertions or deletions after loading) and therefore must
    always be loaded from a file.
The specified file should contain a list of IP addresses and/or
    networks in the form of 10.1.1.1 or
    10.0.0.0/24.
Tables of type ipset and
    const can only contain IP addresses (without masks).
    The lpm tables can contain networks and they will
    perform the longest prefix match on lookup.
It is legal to pass an extracted list from an interface in keywords where NPF would expect instead a direct reference to said interface. In this case, NPF infers a direct reference to the interface, and does not consider the list.
There are two types of IP address lists. With a static list, NPF will capture the interface addresses on configuration load, whereas with a dynamic list NPF will capture the runtime list of addresses, reflecting any changes to the interface, including the attach and detach. Note that with a dynamic list, bringing the interface down has no effect, all addresses will remain present.
Three functions exist, to extract addresses from an interface with a chosen list type and IP address type:
inet4(interface)inet6(interface)ifaddrs(interface)family
      keyword of a filtering rule can be used in combination to explicitly
      select an IP address type. This function can also be used with
      map to specify the translation address, see
    below.Example of configuration:
$var1 = inet4(wm0)
$var2 = ifaddrs(wm0)
group default {
	block in on wm0 all               # rule 1
	block in on $var1 all             # rule 2
	block in on inet4(wm0) all        # rule 3
	pass in on inet6(wm0) from $var2  # rule 4
	pass in on wm0 from ifaddrs(wm0)  # rule 5
}
In the above example, $var1 is the static
    list of IPv4 addresses configured on wm0, and $var2
    is the dynamic list of all the IPv4 and IPv6 addresses configured on wm0.
    The first three rules are equivalent, because with the
    block ...
    on
    <interface>
    syntax, NPF expects a direct reference to an interface, and therefore does
    not consider the extraction functions. The fourth and fifth rules are
    equivalent, for the same reason.
default group. The
  default group must always be defined.
Example of configuration:
group "my-name" in on wm0 {
	# List of rules, for packets received on wm0
}
group default {
	# List of rules, for the other packets
}
pass or
  block a packet depending on packet header information,
  transit direction and the interface it arrived on, either immediately upon
  match or using the last match.
If a packet matches a rule which has the
    final option set, this rule is considered the last
    matching rule, and evaluation of subsequent rules is skipped. Otherwise, the
    last matching rule is used.
The proto keyword can be used to filter
    packets by layer 4 protocol (TCP, UDP, ICMP or other). Its parameter should
    be a protocol number or its symbolic name, as specified in the
    /etc/protocols file. This keyword can additionally
    have protocol-specific options, such as flags.
The flags keyword can be used to match the
    packets against specific TCP flags, according to the following syntax:
proto tcp
  flags
  match[/mask]Where match is the set of TCP flags to be
    matched, out of the mask set, both sets being
    represented as a string combination of:
    ‘S’ (SYN),
    ‘A’ (ACK),
    ‘F’ (FIN), and
    ‘R’ (RST). The flags that are not
    present in mask are ignored.
To notify the sender of a blocking decision, three
    return options can be used in conjunction with a
    block rule:
returnreturn-rst or
      return-icmp, depending on whether the packet being
      blocked is TCP or UDP.return-rstreturn-icmpThe from and to
    keywords are provided to filter by source or destination IP addresses. They
    can be used in conjunction with the port keyword.
    Negation (the exclamation mark) can be used in front of the address filter
    criteria.
Further packet specification at present is limited to TCP and UDP understanding source and destination ports, and ICMP and IPv6-ICMP understanding icmp-type.
A rule can also instruct NPF to create an entry in the state table when passing the packet or to apply a procedure to the packet (e.g. "log").
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"
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.
Depending on the settings (see the section on
    state.key in the
    npf-params(7) manual), the
    connection identifier (keys) may also include the interface ID, making the
    states per-interface.
Stateful packet inspection is enabled using the
    stateful or stateful-all
    keywords. The former matches the interface after the state lookup, while the
    latter avoids matching the interface (assuming the
    state.key.interface parameter is disabled), i.e.
    making the state global, and must be used with caution. 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 aforementioned flags keyword.
dynamic (stateful) or
  static (stateless). The following mapping types are
  available:
The following would translate the source (10.1.1.0/24) to the IP
    address specified by $pub_ip for the packets on the
    interface $ext_if.
map $ext_if dynamic 10.1.1.0/24 ->
  $pub_ipTranslations are implicitly filtered by limiting the operation to
    the network segments specified, that is, translation would be performed only
    on packets originating from the 10.1.1.0/24 network. Explicit filter
    criteria can be specified using pass
    criteria ... as an additional option of the
  mapping.
The dynamic NAT implies network address and port translation (NAPT). The port translation can be controlled explicitly. For example, the following provides “port forwarding”, redirecting the public port 9022 to the port 22 of an internal host:
map $ext_if dynamic proto tcp
  10.1.1.2 port 22 <- $ext_if port 9022In the regular dynamic NAT case, it is also possible to disable
    port translation using the no-ports flag.
The translation address can also be dynamic, based on the interface. The following would select the IPv4 address(es) currently assigned to the interface:
map $ext_if dynamic 10.1.1.0/24 ->
  ifaddrs($ext_if)If the dynamic NAT is configured with multiple translation
    addresses, then a custom selection algorithm can be chosen using the
    algo keyword. The currently available algorithms for
    the dynamic translation are:
ip-hashround-robinnetmapThe static NAT can also have different address translation
    algorithms, chosen using the algo keyword. The
    currently available algorithms are:
If no algorithm is specified, then 1:1 address mapping is assumed. Currently, the static NAT algorithms do not perform port translation.
NPF supports the following ALGs:
icmpThe ALGs are built-in. If NPF is used as kernel module, then they
    come as kernel modules too. In such case, the ALG kernel modules can be
    autoloaded through the configuration, using the alg
    keyword.
For example:
alg "icmp"Alternatively, the ALG kernel modules can be loaded manually, using modload(8).
log:
    interfacenormalize:
    option1[,
    option2 ...]The available normalization options are:
"max-mss"
    value"min-ttl"
    value"no-df""random-id"For example:
procedure "someproc" {
	log: npflog0
	normalize: "random-id", "min-ttl" 64, "max-mss" 1432
}
In this case, the procedure calls the logging and normalization modules.
set state.tcp.timeout.time_wait 0 # destroy the state immediately
See npf-params(7) for the list of parameters and their details.
# 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 | proc | 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 double quotes.
alg		= "alg" alg-name
alg-name	= "icmp"
# Table definition.  Table ID shall be numeric.  Path is in the
# double quotes.
table-id	= <table-name>
table-def	= "table" table-id "type" ( "ipset" | "lpm" | "const" )
		  [ "file" path ]
# Mapping for address translation.
map		= map-common | map-ruleset
map-common	= "map" interface
		  ( "static" [ "algo" map-algo ] | "dynamic" )
		  [ map-flags ] [ proto ]
		  map-seg ( "->" | "<-" | "<->" ) map-seg
		  [ "pass" [ proto ] filt-opts ]
map-ruleset	= "map" "ruleset" group-opts
map-algo	= "ip-hash" | "round-robin" | "netmap" | "npt66"
map-flags	= "no-ports"
map-seg		= ( addr-mask | interface ) [ port-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-all" ]
		  [ "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
tcp-flag-mask	= tcp-flags
tcp-flags	= [ "S" ] [ "A" ] [ "F" ] [ "R" ]
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 ]
proto		= "proto" protocol [ proto-opts ]
filt-opts	= "from" filt-addr [ port-opts ] "to" filt-addr [ port-opts ]
filt-addr	= [ "!" ] [ interface | addr-mask | table-id | "any" ]
port-opts	= "port" ( port-num | port-from "-" port-to | var-name )
addr-mask	= addr [ "/" mask ]
$ext_if = { inet4(wm0) }
$int_if = { inet4(wm1) }
table <blocklist> type ipset file "/etc/npf_blocklist"
table <limited> type lpm
$services_tcp = { http, https, smtp, domain, 6000, 9022 }
$services_udp = { domain, ntp, 6000 }
$localnet = { 10.1.1.0/24 }
alg "icmp"
# These NAT rules will dynamically select the interface address(es).
map $ext_if dynamic 10.1.1.0/24 -> ifaddrs($ext_if)
map $ext_if dynamic proto tcp 10.1.1.2 port 22 <- ifaddrs($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 <blocklist>
	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
}
| May 19, 2020 | NetBSD 9.4 |