liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }