From 4a555dc180b97f3e5606054a3b107b91fc830e04 Mon Sep 17 00:00:00 2001 From: TudbuT Date: Fri, 22 Nov 2024 14:06:33 +0100 Subject: [PATCH] add tnoe, begin home node rewrite --- pi/homemgmt.spl | 55 +++++++++++ tnoe/tnoegatherer.spl | 21 +++++ tnoe/tnoemgmt.spl | 194 ++++++++++++++++++++++++++++++++++++++ tnoe/tnoescan-masscan.spl | 107 +++++++++++++++++++++ tnoe/tnoescan.spl | 32 +++++++ 5 files changed, 409 insertions(+) create mode 100644 pi/homemgmt.spl create mode 100644 tnoe/tnoegatherer.spl create mode 100644 tnoe/tnoemgmt.spl create mode 100644 tnoe/tnoescan-masscan.spl create mode 100644 tnoe/tnoescan.spl diff --git a/pi/homemgmt.spl b/pi/homemgmt.spl new file mode 100644 index 0000000..37c0567 --- /dev/null +++ b/pi/homemgmt.spl @@ -0,0 +1,55 @@ +"#time.spl" import + +"home node management" =program-name + +def remote, revpfwkey + +"revpfw.spl" import +"network.spl" import + +"tudbut.de" =remote +"REVPFWKEY" env:get =revpfwkey + +func panic-handler { | + +} + +func main { exitcode | with args ; + "management system starting up." println + "init revpfw subsystem" println + &revpfw-watcher fork + 1000 time:sleep; + "init ircbot subsystem" println + &ircbot-watcher fork + 1000 time:sleep; + "init network monitor subsystem" println + &network-monitor fork + 1000 time:sleep; +} + +func watcher { | with statevar update delay ; + while { statevar call =>? [ ^ok &pop ] } { + def sa time:unixms =sa + update call + delay (time:unixms sa -) - dup 0 lt if { pop 0 } time:sleep; + } + :sjson<0> panic +} + +func revpfw-watcher { | + [ ^ok ^down ] =revpfw-state + &revpfw-state &revpfw-update watcher<1000> +} + +func ircbot-watcher { | + "ircbot -> service disabled" println + 1 stop + + [ ^ok ^down ] =ircbot-state + &ircbot-state &ircbot-update watcher<1000> +} + +func network-monitor { | + [ ^ok ^up ] =network-state + &network-state &network-update watcher<30000> +} diff --git a/tnoe/tnoegatherer.spl b/tnoe/tnoegatherer.spl new file mode 100644 index 0000000..32f48f2 --- /dev/null +++ b/tnoe/tnoegatherer.spl @@ -0,0 +1,21 @@ +"#httpserver/base.spl" import + +func main { exitcode | with args ; + def server + net:http:Server:new<"::0" 4000> =server + "Started listening on ::0:4000" println + "ip a:" println + + [ "ip" "a" ] command-wait; + + while { 1 } { + server:accept + dup :read + dup :path println + dup :body _str println + :write-ok:write-str-body<"">:finish; + + } + + 0 +} diff --git a/tnoe/tnoemgmt.spl b/tnoe/tnoemgmt.spl new file mode 100644 index 0000000..3a8a9f5 --- /dev/null +++ b/tnoe/tnoemgmt.spl @@ -0,0 +1,194 @@ + +"#stream.spl" import +"#time.spl" import +"#json.spl" import + +def state, network, connections + +[ ^bring-up ] =state +"johlg" =network +6 =connections + +include json:_StringyJSON in array + +func panic-handler { | + catch IO { + "status" StreamTypes:file:create<1> + dup :write-exact<[ ^dead [ ^panic ] ] :sjson<0> "\n" concat :to-bytes> + :close; + } { with e ; + "fuck."; + } +} + +func main { exitcode | with args ; + start-timer =>? ^ok not if { + "error " print :sjson<0> print " in state: " state:sjson<0> concat println + "error in timers" panic + } + 0 +} + +func start-timer { result | + def sa time:unixms =sa + 1 while { } { + 1000 time:unixms sa - - dup 0 lt if { pop 0 } time:sleep; + time:unixms =sa + + def v + timer-run + dup :sjson<0> + dup println + =v + catch IO { + "status" StreamTypes:file:create<1> + dup :write-exact + :close; + } { + [ ^err "no fs access" "status" ] 3 stop + } + dup => [ ^reboot &=v ] if { + "" println + "reboot requested because " v concat "." concat println + catch IO { + "deny-reboot" read-file "no" eq not if { + "reboot denied because deny-reboot is set. need manual help" + pop [ ^err "reboot denied" ] 3 stop + } + } { pop } + catch IO { + "deny-reboot" StreamTypes:file:create<1> + dup :write-exact<"yes" :to-bytes> + :close; + } { + [ ^err "no fs access" "deny-reboot" ] 3 stop + } + while { 1 } { + fork<| + "status" StreamTypes:file:create<1> + dup :write-exact<[ ^dead v ] :sjson<0> "\n" concat :to-bytes> + :close; + catch { + [ "sudo" "reboot" ] command-wait; + } { pop } + > + 5000 time:sleep; + } + } + =>? [ ^ok &pop ] + } +} + +func timer-run { result | + def wait-time + + device-present not if { + [ ^reboot "device not present" ] + 2 stop + } + + state => [ ^fix-device ] if { + fix-device + 2 stop + } + + state => [ ^bring-up ] if { + switch-networks =>? [ ^err "nmcli failed" ] if { + [ ^fix-device ] =state + [ ^ok state ] 3 stop + } dup => [ ^ok &pop ] if { + 3 stop + } + } + + is-network-up not if { + [ ^bring-up ] =state + [ ^ok state ] 2 stop + } + + state => [ ^waiting &=wait-time ] if { + wait-time 0 eq if { + [ ^bring-up ] =state + [ ^ok state ] 3 stop + } + [ ^waiting wait-time 1 - ] =state + [ ^ok state ] 2 stop + } + + state => [ ^connecting &=wait-time ] if { + is-network-up if { + [ ^waiting 60 20 * ] =state + catch IO { + "deny-reboot" StreamTypes:file:create<1> + dup :write-exact<"no" :to-bytes> + :close; + } { + [ ^err "no fs access" "deny-reboot" ] 4 stop + } + [ ^ok ^connected ] 3 stop + } + wait-time 0 eq if { + [ ^bring-up ] =state + [ ^ok state ] 3 stop + } + [ ^connecting wait-time -- ] =state + [ ^ok state ] 2 stop + } + + [ ^err "unknown state" state ] +} + +func switch-networks { result | + [ ^connecting 10 ] =state + + def b + random-byte =>? [ ^ok &=b ] not if { 2 stop } + + b connections % =b + + def conn, hostname + network b _str concat =conn + conn "-hostname" concat read-file :replace<"\n" ""> =hostname + + "connecting to " conn concat " with hostname " concat hostname concat println + + [ "sudo" "hostnamectl" "set-hostname" hostname ] command-wait + [ "sudo" "nmcli" "c" "up" conn ] command-wait or + if { + [ ^err "nmcli failed" ] 2 stop + } + + [ ^ok ^connected ] +} + +func device-present { bool | + [ "lsusb" ] StreamTypes:cmd:create + dup :read-to-end<1024>:to-str + dup :contains<"0bda:c811"> swap:contains<"0bda:1a2b"> or swap + :close +} + +func fix-device { result | + [ ^bring-up ] =state + [ "sudo" "usb_modeswitch" "-v" "0bda" "-p" "1a2b" "-K" ] command-wait; + [ ^ok ^fixing-device ] +} + +func is-network-up { | + def done 0 =done + fork<| 1000 time:sleep; done not if { "ping unsuccessful" println [ "killall" "ping" ] command-wait; } > + [ "ping" "-c" "1" "1.1.1.1" ] command-wait 0 _int eq + 1 =done +} + +func random-byte { [result,byte] | + catch IO { + def b + "/dev/urandom" StreamTypes:file:create<0> + dup :read-one =b + :close; + [ ^ok b ] + } { with err ; + [ ^err err ] + } +} diff --git a/tnoe/tnoescan-masscan.spl b/tnoe/tnoescan-masscan.spl new file mode 100644 index 0000000..0682dce --- /dev/null +++ b/tnoe/tnoescan-masscan.spl @@ -0,0 +1,107 @@ +"#time.spl" import +"#stream.spl" import +"#json.spl" import + +include json:_StringyJSON in array +include json:_StringyJSON in str + +func main { exitcode | with args ; + "scanning network " print args:2 println + def nmap + [ "sudo" "masscan" "--rate" "1000" "--ping" "--wait" "2" args:2 ] StreamTypes:cmd:create =nmap + nmap:read-to-end<1024> _str =nmap + + nmap:split<"\n">:iter =nmap + def records, line + [ ] =records + while { nmap:next dup =line } { + line:readf1<"Discovered open port 0/icmp on {} {}"> => &=line if { + line awrap records swap aadd =records + 2 stop + } + } pop + + "IPs: " println + records:foreach<| ("IP: " print) :sjson println> + + "waiting..." println + 3000 time:sleep; + + "grabbing MACs+Hostnames" println + def i 0 =i + def newrecords + [ ] =newrecords + def running [ 0 0 0 0 0 ] =running + while { i records:len lt } { + "task " print i println + while { running:contains<0> not } { + 500 time:sleep; + } + running:find<0 awrap> i fork<| with id i ; + + 1 id running:set; + + def done [ ] =done + def nmap, out, line, ip, hostname + [ "sudo" "nmap" "-T4" "-sn" records:get ] StreamTypes:cmd:create =nmap + nmap:read-to-end<1024> _str =out + [ "sudo" "nmap" "-sn" "-Pn" records:get ] StreamTypes:cmd:create =nmap + out nmap:read-to-end<1024> _str concat =nmap + + func submit { | with mac ; + 0 done:foreach<| ip eq if { pop 1 }> not if { + done ip awrap aadd =done + newrecords [ ip hostname mac ] awrap aadd =newrecords + } + null =ip + } + + nmap:split<"\n">:iter =nmap + while { nmap:next dup =line } { + line:readf<"Nmap scan report for {} ({})"> => &=line if { + ip null eq not if { + "?" submit + } + line:0 =hostname + line:1 =ip + 2 stop + } + line:readf1<"Nmap scan report for {}"> => &=ip if { + "?" =hostname + 2 stop + } + line:readf1<"MAC Address: {} ({})"> => &=line if { + line submit + 2 stop + } + } pop + + ip null eq not hostname "?" eq not and if { + "?" submit + } + + 0 id running:set; + + > pop pop + + 100 time:sleep; + + i ++ =i + } + while { running:contains<1> } { + 500 time:sleep; + } + + newrecords:foreach<| ("Record: " print) :sjson println> + + "Success rate: " print newrecords:len _float records:len _float / 100 _float * print "%" println + + 0 +} + +func min { min(a,b) | with a b ; + a + a b gt if { + pop b + } +} diff --git a/tnoe/tnoescan.spl b/tnoe/tnoescan.spl new file mode 100644 index 0000000..d8f9666 --- /dev/null +++ b/tnoe/tnoescan.spl @@ -0,0 +1,32 @@ +"#stream.spl" import +"#json.spl" import + +include json:_StringyJSON in array + +func main { exitcode | with args ; + "scanning network " print args:2 println + def nmap + [ "sudo" "nmap" "-T5" "-sn" args:2 ] StreamTypes:cmd:create =nmap + nmap:read-to-end<1024> _str =nmap + + nmap:split<"\n">:iter =nmap + def records, hostname, ip, line + [ ] =records + while { nmap:next dup =line } { + line:readf<"Nmap scan report for {} ({})"> => [ &=hostname &=ip ] if { + 2 stop + } pop + line:readf1<"Nmap scan report for {}"> => &=ip if { + "?" =hostname + 2 stop + } pop + line:readf1<"MAC Address: {} ({})"> => &=line if { + records [ ip hostname line ] awrap aadd =records + 2 stop + } pop + } pop + + records:foreach<| :sjson println> + + 0 +}