liminix

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

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 }