A firewall filters network traffic, which is transmitted in packets.
The network packet filter is configured with rules.
The basics of these filter rules are explained here.

Contents

iptables

Load iptables rules on boot

On Debian, iptables-restore is called on boot by installing the following package:

apt install iptables-persistent

IPv4 rules

We set the default policy of the INPUT chain to DROP and
specify some rules, which are applied from top to bottom:

  1. Incoming packets on the loopback interface lo are accepted.
  2. ESTABLISHED connections or RELATED packets are accepted.
  3. ICMP traffic (e.g. incoming ping requests) is allowed.
  4. The number of SSH connection attempts from each source IP address is limited
    to 8 in 60 seconds. This slows down brute-force password attacks significantly.
  5. A web server needs incoming packets on port 80 (http) and port 443 (https)
    to be accepted.
/etc/iptables/rules.v4
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

-A INPUT -i lo -j ACCEPT

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

-A INPUT -p icmp -j ACCEPT

-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 8 --rttl --name SSH -j DROP
-A INPUT -p tcp --dport 22 -j ACCEPT

-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

COMMIT

Load the IPv4 rules from file:

iptables-restore < /etc/iptables/rules.v4

Verify the loaded IPv4 rules:

iptables -L
Network Address Translation (NAT)

The PREROUTING chain is used for port forwarding.

The rule in the POSTROUTING chain translates the source address of outgoing packets.
The reply will be forwarded by translating the destination address of incoming packets.
This is what ordinary IPv4 routers do.

Rules for the nat table are part of the iptables rules:

/etc/iptables/rules.v4
*filter
#...
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.0.100:80
-A POSTROUTING -s 192.168.0.0/255.255.255.0 -o ppp0 -j MASQUERADE
COMMIT

Forwarding of IPv4 packets needs to be enabled in the kernel.
An interface for modifying kernel parameters is the proc file system.

echo 1 > /proc/sys/net/ipv4/ip_forward

A simplified command line tool for the proc file system is sysctl.
To make the change persistent over reboots, edit the following file:

/etc/sysctl.conf
#...

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

#...

IPv6 rules

For IPv6, the following rules need to be added:

/etc/iptables/rules.v6
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

-A INPUT -i lo -j ACCEPT

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

-A INPUT -p icmpv6 -j ACCEPT

-A INPUT -p udp -s fe80::/10 --dport 546 -j ACCEPT

-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 8 --rttl --name SSH -j DROP
-A INPUT -p tcp --dport 22 -j ACCEPT

-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

COMMIT

Load the IPv6 rules from file:

ip6tables-restore < /etc/iptables/rules.v6

Verify the loaded IPv6 rules:

ip6tables -L

nftables

nftables is the successor of {ip,ip6,arp,eb}tables.
There is only one ruleset needed to cover IPv4 and IPv6.

The table ip contains chains with rules for IPv4.
The contained chain input filters incoming packets.
All accepted IPv4 packets are marked with 0x34414343 ("4ACC"):

  1. All ICMP packets are accepted.
  2. For new SSH connections, rules are created that limit the rate
    to 12 connections per minute for each source IP address.
    This slows down brute-force password attacks significantly.

The table ip6 contains chains with rules for IPv6.
The contained chain input filters incoming packets.
All accepted IPv6 packets are marked with 0x36414343 ("6ACC"):

  1. All ICMPv6 packets are accepted. This is mandatory for IPv6.
  2. All DHCPv6 packets are accepted from link-local IPv6 addresses.
    This is mandatory for IPv6.
  3. For new SSH connections, rules are created that limit the rate
    to 12 connections per minute for each source IP address.
    This slows down brute-force password attacks significantly.

The table inet contains chains with rules for IPv4 and IPv6.
The contained chain input accepts the following incoming packets:

  1. All packets on the loopback interface (lo) are accepted.
  2. Packets from established connections or related packets are accepted.
  3. Packets marked with 0x34414343 (from table ip) are accepted.
  4. Packets marked with 0x36414343 (from table ip6) are accepted.
  5. For a web server, packets on port 80 (http) are accepted.
  6. Packets on port 443 (https) are accepted.
/etc/nftables.conf
#!/usr/sbin/nft -f

flush ruleset

table ip filter {
    set ipv4_ssh_meter {
        type ipv4_addr
        flags dynamic,timeout
        timeout 10m
    }
    chain input {
        type filter hook input priority -10;
        meta l4proto icmp counter meta mark set 0x34414343 accept
        tcp dport 22 ct state new update @ipv4_ssh_meter { ip saddr limit rate 12/minute } counter meta mark set 0x34414343 accept
    }
}

table ip6 filter {
    set ipv6_ssh_meter {
        type ipv6_addr
        flags dynamic,timeout
        timeout 10m
    }
    chain input {
        type filter hook input priority -10;
        meta l4proto ipv6-icmp counter meta mark set 0x36414343 accept
        ip6 saddr fe80::/10 udp dport 546 counter meta mark set 0x36414343 accept
        tcp dport 22 ct state new update @ipv6_ssh_meter { ip6 saddr limit rate 12/minute } counter meta mark set 0x36414343 accept
    }
}

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        iifname "lo" counter accept
        ct state established,related counter accept
        meta mark 0x34414343 counter accept
        meta mark 0x36414343 counter accept
        tcp dport 80 counter accept
        tcp dport 443 counter accept
    }
}

Load the ruleset from file:

nft -f /etc/nftables.conf

Verify the loaded ruleset:

nft list ruleset

Load nftables ruleset on boot

systemctl enable nftables.service