liminix

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

ifwatch.fnl (2054B)


      1 (local { : system : join } (require :anoia))
      2 (local svc (require :anoia.svc))
      3 (local ll (require :lualinux))
      4 
      5 ;; ifwatch.fnl  wan:/nix/store/eee/.outputs/ifname wan:/nix/store/ffff/.outputs/ifname lan:/nix/store/abc123/.outputs/ifname
      6 
      7 (fn parse-options [cmdline]
      8   (let [interfaces {}]
      9     (each [_ s (ipairs cmdline)]
     10       (let [(zone service) (string.match s "(.-):(.+)")]
     11         (tset interfaces (svc.open service) zone)))
     12     interfaces))
     13 
     14 (local POLLIN 1)
     15 (local POLLHUP 16)
     16 
     17 (fn zone-contents [interfaces]
     18   (accumulate [zones {}
     19                intf zone (pairs interfaces)]
     20     (let [ifs (or (. zones zone) [])]
     21       (table.insert ifs  (intf:output "ifname"))
     22       (tset zones zone ifs)
     23       zones)))
     24 
     25 (fn wait-for-change [interfaces]
     26   (let [pollfds (icollect [k _ (pairs interfaces)]
     27                   (bor (lshift (k:fileno) 32)
     28                        (lshift (bor POLLIN POLLHUP) 16)))]
     29     (ll.poll pollfds)))
     30 
     31 (fn fail [msg]
     32   (io.stderr:write (.. "ERROR: " msg "\n")))
     33 
     34 (macro with-popen [[handle command mode] & body]
     35   `(let [,handle (assert (io.popen ,command ,mode))
     36          val# (do ,(unpack body))]
     37     (case (: ,handle :close)
     38       ok# val#
     39       (nil :exit code#) (fail (.. ,command " exited "  code#))
     40       (nil :signal sig#) (fail (.. ,command " killed by " sig#)))))
     41 
     42 (fn update-zone-str [zone ifnames]
     43   (if (> (# ifnames) 0)
     44       (..
     45        "flush set ip table-ip " zone " ; add element ip table-ip " zone " { " (table.concat ifnames ", ") " };\n"
     46        "flush set ip6 table-ip6 " zone " ; add element ip6 table-ip6 " zone " { " (table.concat ifnames ", ") " };\n"
     47        )
     48       (..
     49        "flush set ip table-ip " zone "; \n"
     50        "flush set ip6 table-ip6 " zone "; \n"
     51        )))
     52 
     53 (fn run []
     54   (while true
     55     (let [interfaces (parse-options arg)]
     56       (with-popen [nft "nft -f -" :w]
     57         (each [zone ifnames (pairs (zone-contents interfaces))]
     58           (nft:write (update-zone-str zone ifnames))))
     59       (wait-for-change interfaces)
     60       (each [k _ (pairs interfaces)]
     61         (k:close)))))
     62 
     63 { :  run }