Skip to content

nftables - Firewall

Basics

Using nftables as the successor to iptables makes life much more convenient. So I switched to nftables at my projects. For debian (bookworm) it's necessary to enable the nftables service:

systemctl enable nftables.service

Default configuration file for nftables is located at: /etc/nftables.conf. I don't want to make big modifications at preinstalled files, so I just add an include statement for customized rules:

include "/etc/custom/nftables.rules" 

Basic commands for nftables

List loaded ruleset
nft list ruleset
List set WHITELIST of table CUSTOM
nft list set inet CUSTOM WHITELIST

Basic ruleset for a server providing http/https services

#!/usr/sbin/nft -f

table inet CUSTOM {
    # empty set WHITELIST - will be filled dynamically by scripts
    set WHITELIST {
        type ipv4_addr
    }
    chain INPUT {
        type filter hook input priority 0; policy drop;

        # allow established/related connections
        ct state {established, related} accept

        # early drop of invalid connections
        ct state invalid drop

        # allow from loopback
        iifname lo accept

        # allow icmp (ipv4) - only from IP set WHITELIST
        ip protocol icmp ip saddr @WHITELIST accept

        # allow only ssh connections from IP set WHITELIST
        tcp dport {22} ip saddr @WHITELIST accept

        # allow web services
        tcp dport {80, 443} accept

        # allow internal container interface
        iifname "lxcbr0" ip daddr 10.0.3.1 accept

        # everything else drop
        drop
    }

    chain OUTPUT {
        type filter hook output priority 0; policy accept;
    }

    chain FORWARD {
        type filter hook forward priority 0; policy drop;
        oifname "lxcbr0" accept
        iifname "lxcbr0" accept
    }
}

Updating nftables set

The following bash script updates the set WHITELIST with a dynamic IP address. The script should be executed periodically by a cron job. The variables ips and host have to be modified.

#!/bin/bash
# Update ipset to let my dynamic IP in
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# nftables table and set
ipset=WHITELIST
table=CUSTOM

# dynamical IP for resolving via DNS
host=myurl.example.com

#IP for whitelisting
ips="127.0.0.1 127.0.0.2"

# hostname for logging
me=$(basename "$0")

ip=$(dig +short $host | tail -1)
if [ -z "${ip}" ]; then
    logger -t "${me}" "IP for ${host} not found"
    exit 1
fi

ips="${ips} ${ip}"

ret=`nft get element inet ${table} ${ipset} { ${ip} } > /dev/null 2>&1; echo $?`

if [[ ${ret} == "1" ]] then
    nft flush set inet ${table} ${ipset}
    logger -t "${me}"  "Adding IP ${ip} to set ${ipset}."
    for i in ${ips}
    do
        logger -t "${me}"  "Adding IP ${i} to set ${ipset}."
        nft add element inet ${table} ${ipset} { ${i} }
    done
fi

exit 0