Rules

Rules can either be:

  • shared config snippets defined at rules
  • concrete snippet generated within chains at tables.<table>.<chain>.rules.<rule>

There are a number of rules auto-included when the default profile is enabled.

Default shared rules

These shared rules are added by default under rules

# included from ./default-rules.nix
{
  accept-to-local = {
    n = 1;
    main = "iifname lo";
    comment = "accept all to host";
    counter = false;
    verdict = "accept";
  };
  icmp-default = {
    n = 10;
    main = "meta l4proto { icmp, ipv6-icmp }";
    comment = "accept ICMPv4 + ICMPv6 (ARP / ping)";
    counter = true;
    verdict = "accept";
  };
  ct-related-accept = {
    n = 20;
    main = "ct state { established, related }";
    comment = "accept established/related packets";
    counter = true;
    verdict = "accept";
  };
  ct-dnat-trace = {
    n = 25;
    main = "ct status dnat";
    comment = "accept incoming DNAT";
    # trace = true;
    verdict = "counter accept";
  };
  ct-drop-invalid = {
    n = 30;
    main = "ct state invalid";
    comment = "drop invalid packets";
    counter = true;
    verdict = "drop";
  };
  arp-reply = {
    n = 33;
    main = "arp operation reply";
    comment = "accept ARP reply";
    verdict = "accept";
  };
  ipv6-accept-link-local-dhcp = {
    n = 40;
    main = "ip6 daddr fe80::/64 udp dport dhcpv6-client";
    counter = true;
    verdict = "accept";
    comment = "accept all DHCPv6 packets received at a link-local address";
  };
}

And can be used with

networking.nftables.gen.tables.filter.input.rules = {
  accept-to-local = {};
  icmp-default = {};
  ct-related-accept = {};
  ct-dnat-trace = {};
  ct-drop-invalid = {};
  ipv6-accept-link-local-dhcp = {};
}

Rules are enabled by default when defined, but can be disabled by setting enable = false.

Overriding rules

You can use override shared rules simply by setting a value

networking.nftables.gen = {
  rules.allow-ssh = {
    tcpDport = [22];
    comment = "allow SSH inbound";
  };
  tables.filter.input.rules.allow-ssh.iifname = ["vpn"];
};

We can inspect the final rule generated in the repl

nix-repl> nixosConfigurations.<host>.config.networking.nftables.gen.tables.filter.input.rules.allow-ssh.__final
"iifname vpn tcp dport 22  comment \"allow SSH inbound\""