Simple ruleset for a home router

From nftables wiki
Jump to navigation Jump to search

The following example rulesets have been tested with Linux kernel 4.19 and nftables 1.0.0.

Before you configure your ruleset policy, do not forget to:

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

to enable IPv4 forwarding in your router or enable it through /etc/sysctl.conf for persistency

Simple router using ppp interface

This example shows the configuration of an IPv4-only home router using a ppp interface to go out to the Internet.

flush ruleset

define DEV_PRIVATE = eth1
define DEV_WORLD = ppp0
define NET_PRIVATE = 192.168.0.0/16

table ip global {

    chain inbound_world {
        # accepting ping (icmp-echo-request) for diagnostic purposes.
        # However, it also lets probes discover this host is alive.
        # This sample accepts them within a certain rate limit:
        #
        # icmp type echo-request limit rate 5/second accept

        # allow SSH connections from some well-known internet host
        ip saddr 81.209.165.42 tcp dport ssh accept
    }

    chain inbound_private {
        # accepting ping (icmp-echo-request) for diagnostic purposes.
        icmp type echo-request limit rate 5/second accept

        # allow DHCP, DNS and SSH from the private network
        ip protocol . th dport vmap { tcp . 22 : accept, udp . 53 : accept, tcp . 53 : accept, udp . 67 : accept}
    }

    chain inbound {
        type filter hook input priority 0; policy drop;

        # Allow traffic from established and related packets, drop invalid
        ct state vmap { established : accept, related : accept, invalid : drop }

        # allow loopback traffic, anything else jump to chain for further evaluation
        iifname vmap { lo : accept, $DEV_WORLD : jump inbound_world, $DEV_PRIVATE : jump inbound_private }

        # the rest is dropped by the above policy
    }

    chain forward {
        type filter hook forward priority 0; policy drop;

        # Allow traffic from established and related packets, drop invalid
        ct state vmap { established : accept, related : accept, invalid : drop }

        # connections from the internal net to the internet or to other
        # internal nets are allowed
        iifname $DEV_PRIVATE accept

        # the rest is dropped by the above policy
    }

    chain postrouting {
        type nat hook postrouting priority 100; policy accept;

        # masquerade private IP addresses
        ip saddr $NET_PRIVATE oifname $DEV_WORLD masquerade
    }
}

Router with LAN and WLAN segments using VLAN interface to the Internet

A similar example with a Wireless LAN network segment and using a VLAN device to go out to the Internet

flush ruleset

define DEV_LAN = eth1
define DEV_WLAN = wlan0
define DEV_WORLD = eth0.20
# LAN is 192.168.2.0/24 and WLAN is 192.168.3.0/24, hence 192.168.2.0/23 contains both network segments
define NET_PRIVATE = 192.168.2.0/23

table ip global {
    chain inbound_world {
        # accepting ping (icmp-echo-request) for diagnostic purposes.
        # However, it also lets probes discover this host is alive.
        # This sample accepts them within a certain rate limit:
        #
        # icmp type echo-request limit rate 5/second accept

        # allow SSH connections from some well-known internet host
        ip saddr 81.209.165.42 tcp dport 22 accept
    }

    chain inbound_private_lan {
        # accepting ping (icmp-echo-request) for diagnostic purposes.
        icmp type echo-request limit rate 5/second accept

        # allow DHCP, DNS and SSH from the wired private network
        ip protocol . th dport vmap { tcp . 22 : accept, udp . 53 : accept, tcp . 53 : accept, udp . 67 : accept}
    }

    chain inbound_private_wlan {
        # accepting ping (icmp-echo-request) for diagnostic purposes.
        icmp type echo-request limit rate 5/second accept

        # allow DHCP and DNS from the private wireless network
        ip protocol . th dport vmap { udp . 53 : accept, tcp . 53 : accept, udp . 67 : accept}
    }

    chain inbound {
        type filter hook input priority 0; policy drop;

        # Allow traffic from established and related packets, drop invalid
        ct state vmap { established : accept, related : accept, invalid : drop }

        # allow loopback traffic, anything else jump to chain for further evaluation
        iifname vmap { lo : accept, $DEV_WORLD : jump inbound_world, $DEV_LAN : jump inbound_private_lan, $DEV_WLAN : jump inbound_private_wlan }

        # the rest is dropped by the above policy
    }

    chain forward {
        type filter hook forward priority 0; policy drop;

        # Allow traffic from established and related packets, drop invalid
        ct state vmap { established : accept, related : accept, invalid : drop }

        # connections from the internal net to the internet: wlan to lan and lan to wlan not allowed
        meta iifname . meta oifname { $DEV_LAN . $DEV_WORLD, $DEV_WLAN . $DEV_WORLD, $DEV_WORLD . $DEV_LAN, $DEV_WORLD . $DEV_WLAN } accept

        # the rest is dropped by the above policy
    }

    chain postrouting {
        type nat hook postrouting priority 100; policy accept;

        # masquerade private IP addresses
        ip saddr $NET_PRIVATE counter oifname $DEV_WORLD counter masquerade
    }
}