3 # Use pcap to sniff out rwhod broadcasts on an interface, and
4 # store select ones at /var/spool/rwho/rwho.$HOST
7 (write-line 2 (join (map string (args)) " "))
10 ;(signal 2 'die) ;; THIS DOESN'T WORK??
14 'HOSTS '( "mini" "borta" )
17 (setf ERRBUF (dup "\0" 356))
20 'PCAPLIB "/usr/lib/x86_64-linux-gnu/libpcap.so"
21 'PCAP_CHAR_ENC_LOCAL 0
22 'PCAP_CHAR_ENC_UTF_8 1
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*")
29 (define (estruct NAME)
30 (apply struct (cons NAME (map string (flat (args))))))
32 ;; /usr/include/linux/time.h
35 "long" ;; microseconds */
37 (struct 'bpf_u_int32 "unsigned int")
39 ;; /usr/include/pcap/pcap.h
41 "timeval" ;; time stamp
42 "bpf_u_int32" ;; length of portion present
43 "bpf_u_int32" ;; length of this packet
46 (define (pcap_handling RECEIVER (LIMIT 10) (SNAP 500))
47 (letn ((RECEIVER_FN RECEIVER)
48 (CALLBACK (callback RECEIVER_FN
49 "void" ;; no return value
51 "void*" ;; struct pcap_pkthdr*
52 "void*" ;; unsigned char*
55 (when (!= (setf RET (pcap_init PCAP_CHAR_ENC_LOCAL ERRBUF)))
56 (die "pcap_init" RET ERRBUF))
58 (when (= (setf HANDLE (pcap_open_live IFACE SNAP 0 0 ERRBUF)))
59 (die "pcap_open_live" ERRBUF))
61 (when (!= (setf RET (pcap_loop HANDLE LIMIT CALLBACK 0)))
62 (die "pcap_loop" RET))
65 (estruct 'macaddr (dup 'byte 6))
66 (estruct 'ethertype (dup 'byte 2))
68 "macaddr" ;; destination mac
69 "macaddr" ;; source mac
70 "ethertype" ;; ether type
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)))
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]
84 "uint16" ;; header-checksum
85 "ipv4addr" ;; source IP
86 "ipv4addr" ;; destinetion IP
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)
95 (constant 'udp_head ">uuuu"); loading data into host order
97 (estruct 'wd_hostname (dup 'char 32))
98 (struct 'wd_loadav "int" "int" "int")
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;
109 ;; struct outmp we_utmp;
111 ;; } wd_we[1024 / sizeof (struct whoent)];
114 (unless (directory? "/var/spool/rwho")
115 (make-dir "/var/spool/rwho"))
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))))
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)))
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))
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)))
145 (pcap_handling 'receive_packet)