treewide: replace jow@openwrt.org with jo@mein.io
[openwrt/openwrt.git] / package / network / utils / iwcap / src / iwcap.c
1 /*
2 * iwcap.c - A simply radiotap capture utility outputting pcap dumps
3 *
4 * Copyright 2012 Jo-Philipp Wich <jo@mein.io>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <syslog.h>
28 #include <errno.h>
29 #include <byteswap.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <sys/ioctl.h>
33 #include <sys/socket.h>
34 #include <net/ethernet.h>
35 #include <net/if.h>
36 #include <netinet/in.h>
37 #include <linux/if_packet.h>
38
39 #define ARPHRD_IEEE80211_RADIOTAP 803
40
41 #define DLT_IEEE802_11_RADIO 127
42 #define LEN_IEEE802_11_HDR 32
43
44 #define FRAMETYPE_MASK 0xFC
45 #define FRAMETYPE_BEACON 0x80
46 #define FRAMETYPE_DATA 0x08
47
48 #if __BYTE_ORDER == __BIG_ENDIAN
49 #define le16(x) __bswap_16(x)
50 #else
51 #define le16(x) (x)
52 #endif
53
54 uint8_t run_dump = 0;
55 uint8_t run_stop = 0;
56 uint8_t run_daemon = 0;
57
58 uint32_t frames_captured = 0;
59 uint32_t frames_filtered = 0;
60
61 int capture_sock = -1;
62 const char *ifname = NULL;
63
64
65 struct ringbuf {
66 uint32_t len; /* number of slots */
67 uint32_t fill; /* last used slot */
68 uint32_t slen; /* slot size */
69 void *buf; /* ring memory */
70 };
71
72 struct ringbuf_entry {
73 uint32_t len; /* used slot memory */
74 uint32_t olen; /* original data size */
75 uint32_t sec; /* epoch of slot creation */
76 uint32_t usec; /* epoch microseconds */
77 };
78
79 typedef struct pcap_hdr_s {
80 uint32_t magic_number; /* magic number */
81 uint16_t version_major; /* major version number */
82 uint16_t version_minor; /* minor version number */
83 int32_t thiszone; /* GMT to local correction */
84 uint32_t sigfigs; /* accuracy of timestamps */
85 uint32_t snaplen; /* max length of captured packets, in octets */
86 uint32_t network; /* data link type */
87 } pcap_hdr_t;
88
89 typedef struct pcaprec_hdr_s {
90 uint32_t ts_sec; /* timestamp seconds */
91 uint32_t ts_usec; /* timestamp microseconds */
92 uint32_t incl_len; /* number of octets of packet saved in file */
93 uint32_t orig_len; /* actual length of packet */
94 } pcaprec_hdr_t;
95
96 typedef struct ieee80211_radiotap_header {
97 u_int8_t it_version; /* set to 0 */
98 u_int8_t it_pad;
99 u_int16_t it_len; /* entire length */
100 u_int32_t it_present; /* fields present */
101 } __attribute__((__packed__)) radiotap_hdr_t;
102
103
104 int check_type(void)
105 {
106 struct ifreq ifr;
107
108 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
109
110 if (ioctl(capture_sock, SIOCGIFHWADDR, &ifr) < 0)
111 return -1;
112
113 return (ifr.ifr_hwaddr.sa_family == ARPHRD_IEEE80211_RADIOTAP);
114 }
115
116 int set_promisc(int on)
117 {
118 struct ifreq ifr;
119
120 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
121
122 if (ioctl(capture_sock, SIOCGIFFLAGS, &ifr) < 0)
123 return -1;
124
125 if (on && !(ifr.ifr_flags & IFF_PROMISC))
126 {
127 ifr.ifr_flags |= IFF_PROMISC;
128
129 if (ioctl(capture_sock, SIOCSIFFLAGS, &ifr))
130 return -1;
131
132 return 1;
133 }
134 else if (!on && (ifr.ifr_flags & IFF_PROMISC))
135 {
136 ifr.ifr_flags &= ~IFF_PROMISC;
137
138 if (ioctl(capture_sock, SIOCSIFFLAGS, &ifr))
139 return -1;
140
141 return 1;
142 }
143
144 return 0;
145 }
146
147
148 void sig_dump(int sig)
149 {
150 run_dump = 1;
151 }
152
153 void sig_teardown(int sig)
154 {
155 run_stop = 1;
156 }
157
158
159 void write_pcap_header(FILE *o)
160 {
161 pcap_hdr_t ghdr = {
162 .magic_number = 0xa1b2c3d4,
163 .version_major = 2,
164 .version_minor = 4,
165 .thiszone = 0,
166 .sigfigs = 0,
167 .snaplen = 0xFFFF,
168 .network = DLT_IEEE802_11_RADIO
169 };
170
171 fwrite(&ghdr, 1, sizeof(ghdr), o);
172 }
173
174 void write_pcap_frame(FILE *o, uint32_t *sec, uint32_t *usec,
175 uint16_t len, uint16_t olen)
176 {
177 struct timeval tv;
178 pcaprec_hdr_t fhdr;
179
180 if (!sec || !usec)
181 {
182 gettimeofday(&tv, NULL);
183 }
184 else
185 {
186 tv.tv_sec = *sec;
187 tv.tv_usec = *usec;
188 }
189
190 fhdr.ts_sec = tv.tv_sec;
191 fhdr.ts_usec = tv.tv_usec;
192 fhdr.incl_len = len;
193 fhdr.orig_len = olen;
194
195 fwrite(&fhdr, 1, sizeof(fhdr), o);
196 }
197
198
199 struct ringbuf * ringbuf_init(uint32_t num_item, uint16_t len_item)
200 {
201 static struct ringbuf r;
202
203 if (len_item <= 0)
204 return NULL;
205
206 r.buf = malloc(num_item * (len_item + sizeof(struct ringbuf_entry)));
207
208 if (r.buf)
209 {
210 r.len = num_item;
211 r.fill = 0;
212 r.slen = (len_item + sizeof(struct ringbuf_entry));
213
214 memset(r.buf, 0, num_item * len_item);
215
216 return &r;
217 }
218
219 return NULL;
220 }
221
222 struct ringbuf_entry * ringbuf_add(struct ringbuf *r)
223 {
224 struct timeval t;
225 struct ringbuf_entry *e;
226
227 gettimeofday(&t, NULL);
228
229 e = r->buf + (r->fill++ * r->slen);
230 r->fill %= r->len;
231
232 memset(e, 0, r->slen);
233
234 e->sec = t.tv_sec;
235 e->usec = t.tv_usec;
236
237 return e;
238 }
239
240 struct ringbuf_entry * ringbuf_get(struct ringbuf *r, int i)
241 {
242 struct ringbuf_entry *e = r->buf + (((r->fill + i) % r->len) * r->slen);
243
244 if (e->len > 0)
245 return e;
246
247 return NULL;
248 }
249
250 void ringbuf_free(struct ringbuf *r)
251 {
252 free(r->buf);
253 memset(r, 0, sizeof(*r));
254 }
255
256
257 void msg(const char *fmt, ...)
258 {
259 va_list ap;
260 va_start(ap, fmt);
261
262 if (run_daemon)
263 vsyslog(LOG_INFO | LOG_USER, fmt, ap);
264 else
265 vfprintf(stderr, fmt, ap);
266
267 va_end(ap);
268 }
269
270
271 int main(int argc, char **argv)
272 {
273 int i, n;
274 struct ringbuf *ring;
275 struct ringbuf_entry *e;
276 struct sockaddr_ll local = {
277 .sll_family = AF_PACKET,
278 .sll_protocol = htons(ETH_P_ALL)
279 };
280
281 radiotap_hdr_t *rhdr;
282
283 uint8_t frametype;
284 uint8_t pktbuf[0xFFFF];
285 ssize_t pktlen;
286
287 FILE *o;
288
289 int opt;
290
291 uint8_t promisc = 0;
292 uint8_t streaming = 0;
293 uint8_t foreground = 0;
294 uint8_t filter_data = 0;
295 uint8_t filter_beacon = 0;
296 uint8_t header_written = 0;
297
298 uint32_t ringsz = 1024 * 1024; /* 1 Mbyte ring buffer */
299 uint16_t pktcap = 256; /* truncate frames after 265KB */
300
301 const char *output = NULL;
302
303
304 while ((opt = getopt(argc, argv, "i:r:c:o:sfhBD")) != -1)
305 {
306 switch (opt)
307 {
308 case 'i':
309 ifname = optarg;
310 if (!(local.sll_ifindex = if_nametoindex(ifname)))
311 {
312 msg("Unknown interface '%s'\n", ifname);
313 return 2;
314 }
315 break;
316
317 case 'r':
318 ringsz = atoi(optarg);
319 if (ringsz < (3 * pktcap))
320 {
321 msg("Ring size of %d bytes is too short, "
322 "must be at least %d bytes\n", ringsz, 3 * pktcap);
323 return 3;
324 }
325 break;
326
327 case 'c':
328 pktcap = atoi(optarg);
329 if (pktcap <= (sizeof(radiotap_hdr_t) + LEN_IEEE802_11_HDR))
330 {
331 msg("Packet truncate after %d bytes is too short, "
332 "must be at least %d bytes\n",
333 pktcap, sizeof(radiotap_hdr_t) + LEN_IEEE802_11_HDR);
334 return 4;
335 }
336 break;
337
338 case 's':
339 streaming = 1;
340 break;
341
342 case 'o':
343 output = optarg;
344 break;
345
346 case 'B':
347 filter_beacon = 1;
348 break;
349
350 case 'D':
351 filter_data = 1;
352 break;
353
354 case 'f':
355 foreground = 1;
356 break;
357
358 case 'h':
359 msg(
360 "Usage:\n"
361 " %s -i {iface} -s [-b] [-d]\n"
362 " %s -i {iface} -o {file} [-r len] [-c len] [-B] [-D] [-f]\n"
363 "\n"
364 " -i iface\n"
365 " Specify interface to use, must be in monitor mode and\n"
366 " produce IEEE 802.11 Radiotap headers.\n\n"
367 " -s\n"
368 " Stream to stdout instead of Dumping to file on USR1.\n\n"
369 " -o file\n"
370 " Write current ringbuffer contents to given output file\n"
371 " on receipt of SIGUSR1.\n\n"
372 " -r len\n"
373 " Specify the amount of bytes to use for the ringbuffer.\n"
374 " The default length is %d bytes.\n\n"
375 " -c len\n"
376 " Truncate captured packets after given amount of bytes.\n"
377 " The default size limit is %d bytes.\n\n"
378 " -B\n"
379 " Don't store beacon frames in ring, default is keep.\n\n"
380 " -D\n"
381 " Don't store data frames in ring, default is keep.\n\n"
382 " -f\n"
383 " Do not daemonize but keep running in foreground.\n\n"
384 " -h\n"
385 " Display this help.\n\n",
386 argv[0], argv[0], ringsz, pktcap);
387
388 return 1;
389 }
390 }
391
392 if (!streaming && !output)
393 {
394 msg("No output file specified\n");
395 return 1;
396 }
397
398 if (streaming && output)
399 {
400 msg("The -s and -o options are exclusive\n");
401 return 1;
402 }
403
404 if (streaming && isatty(1))
405 {
406 msg("Refusing to stream into a terminal\n");
407 return 1;
408 }
409
410 if (!local.sll_ifindex)
411 {
412 msg("No interface specified\n");
413 return 2;
414 }
415
416 if (!check_type())
417 {
418 msg("Bad interface: not ARPHRD_IEEE80211_RADIOTAP\n");
419 return 2;
420 }
421
422 if ((capture_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
423 {
424 msg("Unable to create raw socket: %s\n",
425 strerror(errno));
426 return 6;
427 }
428
429 if (bind(capture_sock, (struct sockaddr *)&local, sizeof(local)) == -1)
430 {
431 msg("Unable to bind to interface: %s\n",
432 strerror(errno));
433 return 7;
434 }
435
436 if (!streaming)
437 {
438 if (!foreground)
439 {
440 switch (fork())
441 {
442 case -1:
443 msg("Unable to fork: %s\n", strerror(errno));
444 return 8;
445
446 case 0:
447 umask(0077);
448 chdir("/");
449 freopen("/dev/null", "r", stdin);
450 freopen("/dev/null", "w", stdout);
451 freopen("/dev/null", "w", stderr);
452 run_daemon = 1;
453 break;
454
455 default:
456 msg("Daemon launched ...\n");
457 return 0;
458 }
459 }
460
461 msg("Monitoring interface %s ...\n", ifname);
462
463 if (!(ring = ringbuf_init(ringsz / pktcap, pktcap)))
464 {
465 msg("Unable to allocate ring buffer: %s\n",
466 strerror(errno));
467 return 5;
468 }
469
470 msg(" * Using %d bytes ringbuffer with %d slots\n", ringsz, ring->len);
471 msg(" * Truncating frames at %d bytes\n", pktcap);
472 msg(" * Dumping data to file %s\n", output);
473
474 signal(SIGUSR1, sig_dump);
475 }
476 else
477 {
478 msg("Monitoring interface %s ...\n", ifname);
479 msg(" * Streaming data to stdout\n");
480 }
481
482 msg(" * Beacon frames are %sfiltered\n", filter_beacon ? "" : "not ");
483 msg(" * Data frames are %sfiltered\n", filter_data ? "" : "not ");
484
485 signal(SIGINT, sig_teardown);
486 signal(SIGTERM, sig_teardown);
487
488 promisc = set_promisc(1);
489
490 /* capture loop */
491 while (1)
492 {
493 if (run_stop)
494 {
495 msg("Shutting down ...\n");
496
497 if (promisc)
498 set_promisc(0);
499
500 if (ring)
501 ringbuf_free(ring);
502
503 return 0;
504 }
505 else if (run_dump)
506 {
507 msg("Dumping ring to %s ...\n", output);
508
509 if (!(o = fopen(output, "w")))
510 {
511 msg("Unable to open %s: %s\n",
512 output, strerror(errno));
513 }
514 else
515 {
516 write_pcap_header(o);
517
518 /* sig_dump packet buffer */
519 for (i = 0, n = 0; i < ring->len; i++)
520 {
521 if (!(e = ringbuf_get(ring, i)))
522 continue;
523
524 write_pcap_frame(o, &(e->sec), &(e->usec), e->len, e->olen);
525 fwrite((void *)e + sizeof(*e), 1, e->len, o);
526 n++;
527 }
528
529 fclose(o);
530
531 msg(" * %d frames captured\n", frames_captured);
532 msg(" * %d frames filtered\n", frames_filtered);
533 msg(" * %d frames dumped\n", n);
534 }
535
536 run_dump = 0;
537 }
538
539 pktlen = recvfrom(capture_sock, pktbuf, sizeof(pktbuf), 0, NULL, 0);
540 frames_captured++;
541
542 /* check received frametype, if we should filter it, rewind the ring */
543 rhdr = (radiotap_hdr_t *)pktbuf;
544
545 if (pktlen <= sizeof(radiotap_hdr_t) || le16(rhdr->it_len) >= pktlen)
546 {
547 frames_filtered++;
548 continue;
549 }
550
551 frametype = *(uint8_t *)(pktbuf + le16(rhdr->it_len));
552
553 if ((filter_data && (frametype & FRAMETYPE_MASK) == FRAMETYPE_DATA) ||
554 (filter_beacon && (frametype & FRAMETYPE_MASK) == FRAMETYPE_BEACON))
555 {
556 frames_filtered++;
557 continue;
558 }
559
560 if (streaming)
561 {
562 if (!header_written)
563 {
564 write_pcap_header(stdout);
565 header_written = 1;
566 }
567
568 write_pcap_frame(stdout, NULL, NULL, pktlen, pktlen);
569 fwrite(pktbuf, 1, pktlen, stdout);
570 fflush(stdout);
571 }
572 else
573 {
574 e = ringbuf_add(ring);
575 e->olen = pktlen;
576 e->len = (pktlen > pktcap) ? pktcap : pktlen;
577
578 memcpy((void *)e + sizeof(*e), pktbuf, e->len);
579 }
580 }
581
582 return 0;
583 }