{ secret, inputs', pkgs, ... }: { networking.notnft.rules = let notnft = (inputs'.notnft.lib.${pkgs.stdenv.system}); logRule = with notnft.dsl; with payload; prefix: [ (log { prefix = "${prefix} dropped: "; flags = (f: [ f.all ]); } ) ]; traceChain = with notnft.dsl; with payload; add chain [ (is.eq th.dport 53) (mangle meta.nftrace 1) ] [ (is.eq th.dport 53) (mangle meta.nftrace 1) ] [ (is.eq th.dport 22) (mangle meta.nftrace 1) ] [ (is.eq th.sport 22) (mangle meta.nftrace 1) ] [ (is.eq meta.oifname "mvm0") (mangle meta.nftrace 1) ] [ (is.eq meta.iifname "mvm0") (mangle meta.nftrace 1) ]; in # pkgs.writeText "nftables.json" (builtins.toJSON (with notnft.dsl; with payload; ruleset with notnft.dsl; with payload; ruleset { filter = add table { family = f: f.inet; } { trace = traceChain; ### lo input-lo = add chain [ (is.ne ip.saddr (set [ "127.0.0.1" "127.0.0.53" ])) drop ] [ (is.ne ip.daddr (set [ "127.0.0.1" "127.0.0.53" ])) drop ] [ accept ]; output-lo = add chain [ accept ]; ### ### mvm input-mvm = add chain [ (is.eq ip.protocol (f: f.icmp)) accept ]; output-mvm = add chain [ (is.eq ip.protocol (f: f.icmp)) (is.eq ip.saddr "10.80.1.1") (is.eq ip.daddr "10.80.1.2") accept ] [ (is.eq ip.protocol (f: f.icmp)) (is.eq ip.saddr "10.80.1.2") (is.eq ip.daddr "10.80.1.1") accept ] [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport 22) (is.eq ip.saddr "10.80.1.1") (is.eq ip.daddr "10.80.1.2") accept ] [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport 80) (is.eq ip.saddr "10.80.1.1") (is.eq ip.daddr "10.80.1.2") accept ]; ### ### wlan0 input-wlan0 = add chain [ drop ]; output-wlan0 = add chain [ (is.ne ip.daddr (secret.network.ips.blowhole.ip or "")) (is.eq ip.protocol (f: with f; set [ tcp udp ])) (is.eq th.dport 53) drop ] [ accept ]; ### ### wlan0 input-eth0 = add chain [ drop ]; output-eth0 = add chain [ (is.ne ip.daddr (secret.network.ips.blowhole.ip or "")) (is.eq ip.protocol (f: with f; set [ tcp udp ])) (is.eq th.dport 53) drop ] [ accept ]; ### ### wg0 input-wg0 = add chain # 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-wg0 = add chain # TCP, UDP 53 to blowhole [ (is.eq ip.protocol (f: with f; set [ udp tcp ])) (is.eq th.dport 53) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.blowhole.ip or "")) 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 (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.blowhole.ip or "")) accept ] # TCP 22 toothpick [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport (set [ 22 ])) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.toothpick or "")) accept ] # TCP 22 altra [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport (set [ 22 ])) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.altra.ip or "")) accept ] # ICMP to blowhole, toothpick, altra [ (is.eq ip.protocol (f: f.icmp)) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (set [ (secret.network.ips.toothpick or "") (secret.network.ips.altra.ip or "") (secret.network.ips.blowhole.ip or "") ])) accept ] [ (is.eq ip.protocol (f: f.tcp)) (is.eq th.dport 8883) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.altra.ip or "")) accept ] # 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 ] ; ### 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 "eth0") (jump "input-eth0") ] [ (is.eq meta.iifname "mvm0") (jump "input-mvm") ] [ (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 "eth0") (jump "output-eth0") ] [ (is.eq meta.oifname "lo") (jump "output-lo") ] [ (is.eq meta.oifname "mvm0") (jump "output-mvm") ] [ (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 "wg0") (vmap ct.state { established = accept; related = accept; }) ] # accept TCP, UDP 53 from 10.80.1.2 to blowhole [ (is.eq meta.iifname "mvm0") (is.eq meta.oifname "wg0") (is.eq ip.protocol (f: with f; set [ tcp udp ])) (is.eq th.dport 53) (is.eq ip.saddr "10.80.1.2") (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; } ; postrouting = add chain { type = f: f.nat; hook = f: f.postrouting; prio = -199; policy = f: f.accept; } # masquarade from 10.80.1.2 heading to wg0 [ (is.eq meta.iifname "mvm0") (is.eq meta.oifname "wg0") (is.eq ip.saddr (set [ "10.80.1.2" ])) masquerade ]; }; bridge-t = add table { family = f: f.bridge; } { trace = traceChain; input-body = add chain; input = add chain { type = f: f.filter; hook = f: f.input; prio = -300; policy = f: f.drop; } [ (jump "trace") ] [ (vmap ct.state { established = accept; related = accept; invalid = drop; }) ] [ (is.eq meta.protocol (f: f.arp)) accept ] [ (jump "input-body") ] (logRule "Bridge input"); output-body = add chain; output = add chain { type = f: f.filter; hook = f: f.output; prio = -300; policy = f: f.drop; } [ (jump "trace") ] [ (is.eq ether.type (f: f.arp)) accept ] [ (jump "output-body") ] (logRule "Bridge output"); forward-body = add chain; forward = add chain { type = f: f.filter; hook = f: f.forward; prio = -300; policy = f: f.drop; } [ (jump "trace") ] [ (jump "forward-body") ] (logRule "Bridge forward"); prerouting = add chain { type = f: f.filter; hook = f: f.prerouting; prio = -300; policy = f: f.accept; } ; postrouting = add chain { type = f: f.filter; hook = f: f.postrouting; prio = -300; policy = f: f.accept; } ; }; }; }