{ secret, inputs', pkgs, lib, ... }: { systemd.services.notnft-reload-podman = let reloadPodman = pkgs.writeShellScript "notnft-reload-podman.sh" '' if systemctl status podman ; then ${lib.getExe' pkgs.podman "podman"} network reload -a fi ''; in { after = ["notnftables.service"]; wantedBy = ["notnftables.service"]; bindsTo = ["notnftables.service"]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStart = reloadPodman; ExecStop = reloadPodman; }; }; networking.notnft = let notnft = inputs'.notnft.lib.${pkgs.stdenv.system}; ips = { blowhole = secret.network.ips.blowhole.ip or ""; omen = secret.network.ips.omen.vpn or ""; altra = secret.network.ips.altra.ip or ""; gooseberry = secret.network.ips.gooseberry.wg or ""; toothpick = secret.network.ips.toothpick or ""; heater = secret.network.ips.heater or ""; }; in { enable = true; firewall.interfaces = with notnft.dsl; with payload; { "wlan0".rules = { input = [ [(is.eq ip.protocol (f: f.tcp)) (is.eq th.dport "8080") accept] [(is.eq ip.protocol (f: f.udp)) (is.eq th.dport "20111") accept] [(is.eq ip.protocol (f: f.tcp)) (is.eq th.dport "27036") accept] [(is.eq ip.protocol (f: f.udp)) (is.eq th.dport (set [27031 27032 27033 27034 27035 27036])) accept] ]; output = [ [(is.ne ip.daddr ips.blowhole) (is.eq ip.protocol (f: with f; set [tcp udp])) (is.eq th.dport 53) drop] [accept] ]; }; "lo".rules = { input = [ [accept] ]; output = [ [accept] ]; }; "eth0".rules = { output = [ [(is.ne ip.daddr ips.blowhole) (is.eq ip.protocol (f: with f; set [tcp udp])) (is.eq th.dport 53) drop] [accept] ]; }; "wg0".rules = { input = [ # accept syncthing sharing [(is.eq ip.protocol (f: f.udp)) (is.eq th.sport "22000") (is.eq th.dport "22000") accept] [(is.eq ip.protocol (f: f.tcp)) (is.eq th.dport "22000") accept] [(is.eq ip.protocol (f: f.icmp)) accept] ]; output = [ # TCP, UDP 53 to blowhole [(is.eq ip.protocol (f: with f; set [udp tcp])) (is.eq th.dport 53) (is.eq ip.saddr ips.omen) (is.eq ip.daddr ips.blowhole) accept] # TCP 22, 80, 4646, 8200, 8500, 2049 to blowhole [(is.eq ip.protocol (f: with f; set [tcp])) (is.eq th.dport (set [22 80 4646 8200 8500 2049])) (is.eq ip.saddr ips.omen) (is.eq ip.daddr ips.blowhole) accept] # NFS services to blowhole [(is.eq ip.protocol (f: with f; set [tcp udp])) (is.eq th.dport (set [111 2049 4000 4002 20048])) (is.eq ip.saddr ips.omen) (is.eq ip.daddr ips.blowhole) accept] # TCP 22, 4646, 8200 toothpick [(is.eq ip.protocol (f: with f; set [tcp])) (is.eq th.dport (set [22 4646 8200])) (is.eq ip.saddr ips.omen) (is.eq ip.daddr ips.toothpick) accept] # TCP 22 altra heater gooseberry [(is.eq ip.protocol (f: with f; set [tcp])) (is.eq th.dport (set [22])) (is.eq ip.saddr ips.omen) (is.eq ip.daddr (set [ips.altra ips.gooseberry ips.heater])) accept] # ARMA heater [(is.eq ip.protocol (f: with f; set [udp])) (is.eq th.dport (set [2302 2303 2304])) (is.eq ip.saddr ips.omen) (is.eq ip.daddr ips.heater) accept] # ICMP to blowhole, toothpick, altra [(is.eq ip.protocol (f: f.icmp)) (is.eq ip.saddr ips.omen) (is.eq ip.daddr (set [ips.toothpick ips.altra ips.blowhole])) accept] # [(is.eq ip.protocol (f: f.udp)) (is.eq th.sport "22000") (is.eq th.dport "22000") accept] [(is.eq ip.protocol (f: f.tcp)) (is.eq th.dport "22000") accept] ]; }; }; rules = let logRule = with notnft.dsl; with payload; prefix: [ (log { prefix = "${prefix} dropped: "; flags = f: [f.all]; }) ]; traceChain = with notnft.dsl; with payload; add chain [(mangle meta.nftrace 1)]; in with notnft.dsl; with payload; ruleset { filter = add table {family = f: f.inet;} { trace = traceChain; input = add chain { type = f: f.filter; hook = f: f.input; prio = -300; policy = f: f.drop; } # accept related, established and drop invalid [ (vmap ct.state { established = accept; related = accept; invalid = drop; }) ] # # accept icmp between the same IP # [ (is.eq ip.protocol (f: f.icmp)) (is.eq ip.daddr ip.saddr) accept ] [(jump "trace")] [(is.eq meta.iifname "wlan0") (jump "input-wlan0")] [(is.eq meta.iifname (set ["eth0" "eth1"])) (jump "input-eth0")] [(is.eq meta.iifname "lo") (jump "input-lo")] [(is.eq meta.iifname "wg0") (jump "input-wg0")] [(is.eq ip.protocol (f: f.icmp)) accept] (logRule "Input"); output = add chain { type = f: f.filter; hook = f: f.output; prio = -300; policy = f: f.drop; } [(jump "trace")] [(is.eq meta.oifname "wlan0") (jump "output-wlan0")] [(is.eq meta.oifname (set ["eth0" "eth1"])) (jump "output-eth0")] [(is.eq meta.oifname "lo") (jump "output-lo")] [(is.eq meta.oifname "wg0") (jump "output-wg0")] (logRule "Output"); forward = add chain { type = f: f.filter; hook = f: f.forward; prio = -300; policy = f: f.drop; } [(jump "trace")] # accept masquaraded packets incoming from wg0 [ (is.eq meta.iifname (set ["wg0" "wlan0" "eth0"])) (vmap ct.state { established = accept; related = accept; }) ] [(is.eq meta.iifname "podman0") (is.eq meta.oifname "wg0") (is.eq ip.protocol (f: with f; set [tcp udp])) (is.eq th.dport 53) (is.eq ip.daddr (secret.network.ips.blowhole.ip or "")) accept] (logRule "Forward"); prerouting = add chain { type = f: f.nat; hook = f: f.prerouting; prio = -199; policy = f: f.accept; } # [(jump "trace")] ; postrouting = add chain { type = f: f.nat; hook = f: f.postrouting; prio = -199; policy = f: f.accept; } # [(jump "trace")] ; }; bridge-t = add table {family = f: f.bridge;} { trace = traceChain; input = add chain { type = f: f.filter; hook = f: f.input; prio = f: f.filter; policy = f: f.drop; } [(jump "trace")] [ (vmap ct.state { established = accept; related = accept; invalid = drop; }) ] [(is.eq meta.protocol (f: f.arp)) accept] (logRule "Bridge input"); output = add chain { type = f: f.filter; hook = f: f.output; prio = f: f.out; policy = f: f.drop; } [(is.eq ether.type (f: f.arp)) accept] (logRule "Bridge output"); forward = add chain { type = f: f.filter; hook = f: f.forward; prio = f: f.filter; policy = f: f.drop; } (logRule "Bridge forward"); prerouting = add chain { type = f: f.filter; hook = f: f.prerouting; prio = f: f.dstnat; policy = f: f.accept; }; postrouting = add chain { type = f: f.filter; hook = f: f.postrouting; prio = f: f.srcnat; policy = f: f.accept; }; }; }; }; }