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