initial
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Sat, 19 Feb 2022 08:28:52 +0000 (19:28 +1100)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Sat, 19 Feb 2022 08:28:52 +0000 (19:28 +1100)
rwhod-sniffer.lsp [new file with mode: 0755]

diff --git a/rwhod-sniffer.lsp b/rwhod-sniffer.lsp
new file mode 100755 (executable)
index 0000000..f39e841
--- /dev/null
@@ -0,0 +1,147 @@
+#!/usr/bin/newlisp
+#
+# Use  pcap to sniff out rwhod broadcasts on an        interface, and
+# store        select ones at  /var/spool/rwho/rwho.$HOST
+
+(define (die)
+  (write-line 2 (join (map string (args)) " "))
+  (exit 1))
+
+;(signal 2 'die) ;; THIS DOESN'T WORK??
+
+(constant
+ 'IFACE "hemmanet"
+ 'HOSTS '( "mini" "borta" )
+ )
+
+(setf ERRBUF (dup "\0" 356))
+
+(constant
+ 'PCAPLIB "/usr/lib/x86_64-linux-gnu/libpcap.so"
+ 'PCAP_CHAR_ENC_LOCAL 0
+ 'PCAP_CHAR_ENC_UTF_8 1
+ )
+(import PCAPLIB "pcap_init" "int" "int" "char*")
+(import PCAPLIB "pcap_open_live" "void*" "char*" "int" "int" "int" "char*")
+(import PCAPLIB "pcap_loop" "int" "void*" "int" "void*" "void*")
+
+;; syntax helper
+(define (estruct NAME)
+  (apply struct (cons NAME (map string (flat (args))))))
+
+;; /usr/include/linux/time.h
+(struct 'timeval
+        "long" ;; seconds
+        "long" ;; microseconds */
+        )
+(struct 'bpf_u_int32 "unsigned int")
+
+;; /usr/include/pcap/pcap.h
+(struct 'pcap_pkthdr
+        "timeval"       ;; time stamp
+        "bpf_u_int32"  ;; length of portion present
+        "bpf_u_int32"  ;; length of this packet
+        )
+
+(define (pcap_handling RECEIVER (LIMIT 10) (SNAP 500))
+  (letn ((RECEIVER_FN RECEIVER)
+         (CALLBACK (callback RECEIVER_FN
+                              "void"  ;; no return value
+                              "void*" ;; userdata
+                              "void*" ;; struct pcap_pkthdr*
+                              "void*" ;; unsigned char*
+                              )))
+
+    (when (!= (setf RET (pcap_init PCAP_CHAR_ENC_LOCAL ERRBUF)))
+      (die "pcap_init" RET ERRBUF))
+
+    (when (= (setf HANDLE (pcap_open_live IFACE SNAP 0 0 ERRBUF)))
+      (die "pcap_open_live" ERRBUF))
+
+    (when (!= (setf RET (pcap_loop HANDLE LIMIT CALLBACK 0)))
+      (die "pcap_loop" RET))
+  ))
+
+(estruct 'macaddr (dup 'byte 6))
+(estruct 'ethertype (dup 'byte 2))
+(struct 'ether_head
+         "macaddr" ;; destination mac
+         "macaddr" ;; source mac
+         "ethertype" ;; ether type 
+         )
+
+(estruct 'ipv4addr (dup 'byte 4))
+(struct 'byte2 "byte" "byte")
+(struct 'uint16 "unsigned short int") ;
+(define (ntohs S) (unpack ">u" (address S)))
+(struct 'ipv4_head
+        "byte2" ;; Version[4] IHL[4] DSCP[6] ECV[2]
+        "uint16" ;; Length[16] (in network byte order!)
+        "uint16" ;; Identification
+        "uint16" ;; Flags[3] Fragment-offset[13]
+        "byte"   ;; TTL
+        "byte"   ;; protocol
+        "uint16" ;; header-checksum
+        "ipv4addr" ;; source IP
+        "ipv4addr" ;; destinetion IP
+        )
+
+(struct 'udp_head_real
+        "uint16" ;; source port (network order)
+        "uint16" ;; destination port (network order)
+        "uint16" ;; payload length (network order)
+        "uint16" ;; checksum (network order)
+        )
+(constant 'udp_head ">uuuu"); loading data into host order
+
+(estruct 'wd_hostname (dup 'char 32))
+(struct 'wd_loadav "int" "int" "int")
+(struct 'rwhod
+        "char"        ;;    wd_vers;
+        "char"        ;;    wd_type;
+        "char" "char" ;;    wd_fill[2];
+        "int"         ;; wd_sendtime;
+        "int"         ;; wd_recvtime;
+        "wd_hostname" ;; char[32];
+        "wd_loadav"   ;; "int" "int" "int" [3];
+        "int"         ;;     wd_boottime;
+        ;; struct  whoent {
+        ;;        struct  outmp we_utmp;
+        ;;        int     we_idle;
+        ;; } wd_we[1024 / sizeof (struct whoent)];
+        )
+
+(unless (directory? "/var/spool/rwho")
+  (make-dir "/var/spool/rwho"))
+
+;; Save rwhod report
+(define (receive_rwhod BYTES LEN)
+  (let ((HOST ((unpack "s32" (+ BYTES 12)) 0))
+        (DATA (get-string BYTES LEN)))
+    (when (member HOST HOSTS)
+      (write-file (format "/var/spool/rwho/whod.%s" HOST) DATA))))
+
+(define (receive_udp BYTES LEN)
+  (let ((HDR (unpack udp_head BYTES)))
+    (when (= '(513 513) (0 2 HDR))
+      (receive_rwhod (+ BYTES 8) (- LEN 8)))
+    ))
+
+(define (receive_ipv4 BYTES LEN REAL)
+  (letn ((HDR (unpack ipv4_head BYTES))
+         (SZ (* 4 (& (HDR 0 0) 0xf))))
+    (when (and (= LEN REAL) (= (HDR 5) 17))
+      (receive_udp (+ BYTES SZ) (- LEN SZ))
+      )))
+
+(define (receive_packet USERDATA PKTHDR BYTES)
+  (let ((HDR (unpack pcap_pkthdr PKTHDR))
+        (MAC (unpack ether_head BYTES)))
+    (when (and (> (HDR 1 0) 34) (= (dup 255 6) (MAC 0)) (= '(8 0) (MAC 2)))
+      (receive_ipv4 (+ BYTES 14) (- (HDR 1 0) 14) (- (HDR 2 0) 14)))
+    ))
+
+;;; Main program
+(pcap_handling 'receive_packet)
+
+(exit 0)