pass EDITOR through sudo
[rrq/newlisp-ftw.git] / rwhod-sniffer.lsp
1 #!/usr/bin/newlisp
2 #
3 # Use  pcap to sniff out rwhod broadcasts on an interface, and
4 # store select ones at  /var/spool/rwho/rwho.$HOST
5
6 (define (die)
7   (write-line 2 (join (map string (args)) " "))
8   (exit 1))
9
10 ;(signal 2 'die) ;; THIS DOESN'T WORK??
11
12 (constant
13  'IFACE "hemmanet"
14  'HOSTS '( "mini" "borta" )
15  )
16
17 (setf ERRBUF (dup "\0" 356))
18
19 (constant
20  'PCAPLIB "/usr/lib/x86_64-linux-gnu/libpcap.so"
21  'PCAP_CHAR_ENC_LOCAL 0
22  'PCAP_CHAR_ENC_UTF_8 1
23  )
24 (import PCAPLIB "pcap_init" "int" "int" "char*")
25 (import PCAPLIB "pcap_open_live" "void*" "char*" "int" "int" "int" "char*")
26 (import PCAPLIB "pcap_loop" "int" "void*" "int" "void*" "void*")
27
28 ;; syntax helper
29 (define (estruct NAME)
30   (apply struct (cons NAME (map string (flat (args))))))
31
32 ;; /usr/include/linux/time.h
33 (struct 'timeval
34         "long" ;; seconds
35         "long" ;; microseconds */
36         )
37 (struct 'bpf_u_int32 "unsigned int")
38
39 ;; /usr/include/pcap/pcap.h
40 (struct 'pcap_pkthdr
41         "timeval"       ;; time stamp
42         "bpf_u_int32"  ;; length of portion present
43         "bpf_u_int32"  ;; length of this packet
44         )
45
46 (define (pcap_handling RECEIVER (LIMIT 10) (SNAP 500))
47   (letn ((RECEIVER_FN RECEIVER)
48          (CALLBACK (callback RECEIVER_FN
49                               "void"  ;; no return value
50                               "void*" ;; userdata
51                               "void*" ;; struct pcap_pkthdr*
52                               "void*" ;; unsigned char*
53                               )))
54
55     (when (!= (setf RET (pcap_init PCAP_CHAR_ENC_LOCAL ERRBUF)))
56       (die "pcap_init" RET ERRBUF))
57
58     (when (= (setf HANDLE (pcap_open_live IFACE SNAP 0 0 ERRBUF)))
59       (die "pcap_open_live" ERRBUF))
60
61     (when (!= (setf RET (pcap_loop HANDLE LIMIT CALLBACK 0)))
62       (die "pcap_loop" RET))
63   ))
64
65 (estruct 'macaddr (dup 'byte 6))
66 (estruct 'ethertype (dup 'byte 2))
67 (struct 'ether_head
68          "macaddr" ;; destination mac
69          "macaddr" ;; source mac
70          "ethertype" ;; ether type 
71          )
72
73 (estruct 'ipv4addr (dup 'byte 4))
74 (struct 'byte2 "byte" "byte")
75 (struct 'uint16 "unsigned short int") ;
76 (define (ntohs S) (unpack ">u" (address S)))
77 (struct 'ipv4_head
78         "byte2" ;; Version[4] IHL[4] DSCP[6] ECV[2]
79         "uint16" ;; Length[16] (in network byte order!)
80         "uint16" ;; Identification
81         "uint16" ;; Flags[3] Fragment-offset[13]
82         "byte"   ;; TTL
83         "byte"   ;; protocol
84         "uint16" ;; header-checksum
85         "ipv4addr" ;; source IP
86         "ipv4addr" ;; destinetion IP
87         )
88
89 (struct 'udp_head_real
90         "uint16" ;; source port (network order)
91         "uint16" ;; destination port (network order)
92         "uint16" ;; payload length (network order)
93         "uint16" ;; checksum (network order)
94         )
95 (constant 'udp_head ">uuuu"); loading data into host order
96
97 (estruct 'wd_hostname (dup 'char 32))
98 (struct 'wd_loadav "int" "int" "int")
99 (struct 'rwhod
100         "char"        ;;    wd_vers;
101         "char"        ;;    wd_type;
102         "char" "char" ;;    wd_fill[2];
103         "int"         ;; wd_sendtime;
104         "int"         ;; wd_recvtime;
105         "wd_hostname" ;; char[32];
106         "wd_loadav"   ;; "int" "int" "int" [3];
107         "int"         ;;     wd_boottime;
108         ;; struct  whoent {
109         ;;        struct  outmp we_utmp;
110         ;;        int     we_idle;
111         ;; } wd_we[1024 / sizeof (struct whoent)];
112         )
113
114 (unless (directory? "/var/spool/rwho")
115   (make-dir "/var/spool/rwho"))
116
117 ;; Save rwhod report
118 (define (receive_rwhod BYTES LEN)
119   (let ((HOST ((unpack "s32" (+ BYTES 12)) 0))
120         (DATA (get-string BYTES LEN)))
121     (when (member HOST HOSTS)
122       (write-file (format "/var/spool/rwho/whod.%s" HOST) DATA))))
123
124 (define (receive_udp BYTES LEN)
125   (let ((HDR (unpack udp_head BYTES)))
126     (when (= '(513 513) (0 2 HDR))
127       (receive_rwhod (+ BYTES 8) (- LEN 8)))
128     ))
129
130 (define (receive_ipv4 BYTES LEN REAL)
131   (letn ((HDR (unpack ipv4_head BYTES))
132          (SZ (* 4 (& (HDR 0 0) 0xf))))
133     (when (and (= LEN REAL) (= (HDR 5) 17))
134       (receive_udp (+ BYTES SZ) (- LEN SZ))
135       )))
136
137 (define (receive_packet USERDATA PKTHDR BYTES)
138   (let ((HDR (unpack pcap_pkthdr PKTHDR))
139         (MAC (unpack ether_head BYTES)))
140     (when (and (> (HDR 1 0) 34) (= (dup 255 6) (MAC 0)) (= '(8 0) (MAC 2)))
141       (receive_ipv4 (+ BYTES 14) (- (HDR 1 0) 14) (- (HDR 2 0) 14)))
142     ))
143
144 ;;; Main program
145 (pcap_handling 'receive_packet)
146
147 (exit 0)