service.nix (3363B)
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 46 rules = map (x: '' 47 {{; 48 local s = "${x}"; 49 local n = output(s, "ifname"); 50 local bw = output(s, "bandwidth"); 51 if n and bw then 52 return "meta l4proto icmpv6 iifname ".. n .. " limit rate over " .. (math.floor (tonumber(bw) / 8 / 20)) .. " bytes/second drop" 53 else 54 return "# " .. (n or "not n") .. " " .. (bw or "not bw") 55 end 56 }} 57 '') (concatLists (builtins.attrValues zones)); 58 in 59 { 60 type = "filter"; 61 family = "ip6"; 62 hook = "input"; 63 priority = "-1"; 64 policy = "accept"; 65 inherit rules; 66 }; 67 68 rateHook4 = 69 let 70 rules = map (x: '' 71 {{; 72 local s = "${x}"; 73 local n = output(s, "ifname"); 74 local bw = output(s, "bandwidth"); 75 if n and bw then 76 return "meta l4proto icmp iifname ".. n .. " limit rate over " .. (math.floor (tonumber(bw) / 8 / 20)) .. " bytes/second drop" 77 else 78 return "# " .. (n or "not n") .. " " .. (bw or "not bw") 79 end 80 }} 81 '') (concatLists (builtins.attrValues zones)); 82 in 83 { 84 type = "filter"; 85 family = "ip"; 86 hook = "input"; 87 priority = "-1"; 88 policy = "accept"; 89 inherit rules; 90 }; 91 92 sets = (mapAttrs' (n: _: mkSet "ip" n) zones) // (mapAttrs' (n: _: mkSet "ip6" n) zones); 93 allRules = { 94 icmp6-ratehook = rateHook6; 95 icmp4-ratehook = rateHook4; 96 } 97 // (lib.recursiveUpdate (lib.recursiveUpdate sets rules) extraRules); 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 = concatLists ( 123 mapAttrsToList (_zone: services: map (s: outputRef s "ifname") services) zones 124 ); 125 126 inherit service; 127 }