odhcp6-script.fnl (2938B)
1 (local { : split : merge : hash : base64url } (require :anoia)) 2 (local { : mktree : rmtree } (require :anoia.fs)) 3 4 (local state-directory (assert (os.getenv "SERVICE_STATE"))) 5 (mktree state-directory) 6 7 (fn write-value [name value] 8 (let [path (.. state-directory "/" name)] 9 (with-open [fout (io.open path :w)] 10 (when value (fout:write value))))) 11 12 (fn write-value-from-env [name] 13 (write-value name (os.getenv (string.upper name)))) 14 15 (fn parse-address [str] 16 (fn parse-extra [s] 17 (let [out {}] 18 (each [name val (string.gmatch s ",(.-)=([^,]+)")] 19 (tset out name val)) 20 out)) 21 (let [(address len preferred valid extra) 22 (string.match str "(.-)/(%d+),(%d+),(%d+)(.*)$")] 23 (merge {: address : len : preferred : valid} (parse-extra extra)))) 24 25 (fn write-addresses [prefix addresses] 26 (each [_ a (ipairs (split " " addresses))] 27 (let [address (parse-address a) 28 suffix (base64url (string.pack "n" (hash a))) 29 ;; keydir should be a function of all the address 30 ;; attributes: we want it to change whenever anything changes 31 ;; so that clients can see which addresses are new without 32 ;; deep table comparisons 33 keydir (.. 34 prefix 35 (-> address.address 36 (: :gsub "::$" "") 37 (: :gsub ":" "-")) 38 "_" 39 suffix)] 40 (mktree (.. state-directory "/" keydir)) 41 (each [k v (pairs address)] 42 (write-value (.. keydir "/" k) v))))) 43 44 ;; we remove state before updating to ensure that consumers don't get 45 ;; a half-updated snapshot 46 (os.remove (.. state-directory "/state")) 47 48 ;; remove parsed addresses/prefixes from any previous run 49 (rmtree (.. state-directory "/prefix")) 50 (rmtree (.. state-directory "/address")) 51 52 (let [wanted 53 [ 54 :addresses 55 :aftr 56 :cer 57 :domains 58 :lw406 59 :mape 60 :mapt 61 :ntp_fqdn 62 :ntp_ip 63 :option_1 64 :option_2 65 :option_3 66 :option_4 67 :option_5 68 :passthru 69 :prefixes 70 :ra_addresses 71 :ra_dns 72 :ra_domains 73 :ra_hoplimit 74 :ra_mtu 75 :ra_reachable 76 :ra_retransmit 77 :ra_routes 78 :rdnss 79 :server 80 :sip_domain 81 :sip_ip 82 :sntp_ip 83 :sntp_fqdn 84 ]] 85 (each [_ n (ipairs wanted)] 86 (write-value-from-env n)) 87 88 (match (os.getenv :ADDRESSES) s (write-addresses "address/" s)) 89 (match (os.getenv :PREFIXES) s (write-addresses "prefix/" s))) 90 91 (let [[ifname state] arg 92 ready (match state 93 "started" false 94 "unbound" false 95 "stopped" false 96 _ true)] 97 (write-value ".lock" (tostring (os.time))) 98 (write-value "ifname" ifname) 99 (write-value "state" state) 100 (os.remove (.. state-directory "/.lock")) 101 (when ready 102 (with-open [fd (io.open "/proc/self/fd/10" :w)] (fd:write "\n"))))