tufted.fnl (1495B)
1 (local tftp (require :tftp)) 2 (local { : realpath} (require :posix.stdlib)) 3 (local { : view } (require :fennel)) 4 5 (local options 6 (match arg 7 ["-a" ip-address dir] 8 { :allow ip-address :base-directory (realpath dir)} 9 10 [dir] 11 { :allow nil :base-directory (realpath dir)} 12 13 [] 14 (error "missing command line parameters") 15 )) 16 17 (print (.. "TFTP serving from " options.base-directory)) 18 19 ;; this is a copy of anoia append-path 20 (fn merge-pathname [dirname filename] 21 (let [base (or (string.match dirname "(.*)/$") dirname) 22 result []] 23 (each [component (string.gmatch filename "([^/]+)")] 24 (if (and (= component "..") (> (# result) 0)) 25 (table.remove result) 26 (= component "..") 27 (error "path traversal attempt") 28 true 29 (table.insert result component))) 30 (.. base "/" (table.concat result "/")))) 31 32 (-> 33 (tftp:listen 34 (fn [file host port] 35 (if (or (not options.allow) (= host options.allow)) 36 (let [pathname (merge-pathname options.base-directory file) 37 f (io.open pathname "rb") 38 size (f:seek "end")] 39 (f:seek "set" 0) 40 (var eof? false) 41 (values 42 (fn handler [reqlen] 43 (let [bytes (f:read reqlen)] 44 (if bytes 45 (values true bytes) 46 (values false nil)))) 47 size)) 48 (error "host not allowed"))) 49 nil 50 ["*"] 51 69) 52 53 (os.exit))