service.nix (3540B)
1 { 2 liminix, 3 lib, 4 firewallgen, 5 nftables, 6 svc, 7 lua, 8 output-template, 9 }: 10 { 11 rules, 12 extraRules, 13 zones, 14 }: 15 let 16 inherit (liminix.services) longrun; 17 inherit (lib.attrsets) mapAttrs' nameValuePair mapAttrsToList; 18 inherit (lib.strings) concatStringsSep; 19 inherit (builtins) concatLists toJSON attrValues; 20 inherit (liminix) outputRef; 21 mkSet = 22 family: name: 23 nameValuePair "${name}-set-${family}" { 24 kind = "set"; 25 inherit name family; 26 type = "ifname"; 27 extraText = '' 28 {{; 29 local services = { ${concatStringsSep ", " (map toJSON zones.${name})} } 30 local ifnames = {} 31 for _, v in ipairs(services) do 32 local o = output(v, "ifname") 33 if o then table.insert(ifnames, o) end 34 end 35 if (#ifnames > 0) then 36 return "elements = { " .. table.concat(ifnames, ", ") .. " }\n" 37 else 38 return "" 39 end 40 }} 41 ''; 42 }; 43 44 rateHook6 = 45 let rules = 46 map 47 (x: '' 48 {{; 49 local s = "${x}"; 50 local n = output(s, "ifname"); 51 local bw = output(s, "bandwidth"); 52 if n and bw then 53 return "meta l4proto icmpv6 iifname ".. n .. " limit rate over " .. (math.floor (tonumber(bw) / 8 / 20)) .. " bytes/second drop" 54 else 55 return "# " .. (n or "not n") .. " " .. (bw or "not bw") 56 end 57 }} 58 '') 59 (concatLists (builtins.attrValues zones)); 60 in { 61 type = "filter"; family = "ip6"; 62 hook = "input"; priority = "-1"; policy = "accept"; 63 inherit rules; 64 }; 65 66 rateHook4 = 67 let rules = 68 map 69 (x: '' 70 {{; 71 local s = "${x}"; 72 local n = output(s, "ifname"); 73 local bw = output(s, "bandwidth"); 74 if n and bw then 75 return "meta l4proto icmp iifname ".. n .. " limit rate over " .. (math.floor (tonumber(bw) / 8 / 20)) .. " bytes/second drop" 76 else 77 return "# " .. (n or "not n") .. " " .. (bw or "not bw") 78 end 79 }} 80 '') 81 (concatLists (builtins.attrValues zones)); 82 in { 83 type = "filter"; family = "ip"; 84 hook = "input"; priority = "-1"; policy = "accept"; 85 inherit rules; 86 }; 87 88 sets = (mapAttrs' (n: _: mkSet "ip" n) zones) // 89 (mapAttrs' (n: _: mkSet "ip6" n) zones); 90 allRules = 91 { 92 icmp6-ratehook = rateHook6; 93 icmp4-ratehook = rateHook4; 94 } // 95 (lib.recursiveUpdate 96 extraRules 97 (lib.recursiveUpdate sets rules)); 98 script = firewallgen "firewall1.nft" allRules; 99 name = "firewall"; 100 service = longrun { 101 inherit name; 102 run = '' 103 PATH=${nftables}/bin:${lua}/bin:$PATH 104 reload() { 105 echo reloading firewall 106 ${output-template}/bin/output-template '{{' '}}' < ${script} > /run/${name}/fw.nft; 107 nft -f /run/${name}/fw.nft ; 108 } 109 trap reload SIGUSR1 110 mkdir -p /run/${name}; in_outputs ${name} 111 reload 112 while :; do 113 # signals sent to ash won't interrupt sleep, but will interrupt wait 114 sleep 86400 & wait 115 done 116 ''; 117 finish = "${nftables}/bin/nft flush ruleset"; 118 }; 119 in 120 svc.secrets.subscriber.build { 121 action = "usr1"; 122 watch = 123 concatLists 124 (mapAttrsToList (_zone : services : map (s: outputRef s "ifname") services) zones); 125 126 inherit service; 127 }