network: firewall integration with NFT sets
authorTopi Miettinen <toiwoton@gmail.com>
Wed, 9 Aug 2023 20:07:21 +0000 (23:07 +0300)
committerTopi Miettinen <toiwoton@gmail.com>
Sat, 26 Aug 2023 18:37:09 +0000 (21:37 +0300)
commitfc289dd0ad4c223c0fa02dc7e91f7244143fa918
treeaea1eecc488e369f6bc3c24adae606bae27053ed
parent274ffe1abbdeb4647ee98448b4ec88069ab3f4aa
network: firewall integration with NFT sets

New directive `NFTSet=` provides a method for integrating network configuration
into firewall rules with NFT sets. The benefit of using this setting is that
static network configuration or dynamically obtained network addresses can be
used in firewall rules with the indirection of NFT set types. For example,
access could be granted for hosts in the local subnetwork only. Firewall rules
using IP address of an interface are also instantly updated when the network
configuration changes, for example via DHCP.

This option expects a whitespace separated list of NFT set definitions. Each
definition consists of a colon-separated tuple of source type (one of
"address", "prefix", or "ifindex"), NFT address family (one of "arp", "bridge",
"inet", "ip", "ip6", or "netdev"), table name and set name. The names of tables
and sets must conform to lexical restrictions of NFT table names. The type of
the element used in the NFT filter must match the type implied by the
directive ("address", "prefix" or "ifindex") and address type (IPv4 or IPv6)
as shown type implied by the directive ("address", "prefix" or "ifindex") and
address type (IPv4 or IPv6) must also match the set definition.

When an interface is configured with IP addresses, the addresses, subnetwork
masks or interface index will be appended to the NFT sets. The information will
be removed when the interface is deconfigured. systemd-networkd only inserts
elements to (or removes from) the sets, so the related NFT rules, tables and
sets must be prepared elsewhere in advance. Failures to manage the sets will be
ignored.

/etc/systemd/network/eth.network
```
[DHCPv4]
...
NFTSet=prefix:netdev:filter:eth_ipv4_prefix
```

Example NFT rules:
```
table netdev filter {
        set eth_ipv4_prefix {
                type ipv4_addr
                flags interval
        }
        chain eth_ingress {
                type filter hook ingress device "eth0" priority filter; policy drop;
                ip saddr != @eth_ipv4_prefix drop
                accept
        }
}
```
```
$ sudo nft list set netdev filter eth_ipv4_prefix
table netdev filter {
        set eth_ipv4_prefix {
                type ipv4_addr
                flags interval
                elements = { 10.0.0.0/24 }
        }
}
```
12 files changed:
man/systemd.network.xml
src/basic/parse-util.c
src/basic/parse-util.h
src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/shared/firewall-util-nft.c
src/shared/firewall-util.h
src/test/meson.build
src/test/test-nft-set.c [new file with mode: 0644]