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