v1.5 branch refresh based upon upstream master @ c8677ca89e53e3be7988d54280fce166cc894a7e
[librecmc/librecmc.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_dump)
494                 {
495                         msg("Dumping ring to %s ...\n", output);
496
497                         if (!(o = fopen(output, "w")))
498                         {
499                                 msg("Unable to open %s: %s\n",
500                                         output, strerror(errno));
501                         }
502                         else
503                         {
504                                 write_pcap_header(o);
505
506                                 /* sig_dump packet buffer */
507                                 for (i = 0, n = 0; i < ring->len; i++)
508                                 {
509                                         if (!(e = ringbuf_get(ring, i)))
510                                                 continue;
511
512                                         write_pcap_frame(o, &(e->sec), &(e->usec), e->len, e->olen);
513                                         fwrite((void *)e + sizeof(*e), 1, e->len, o);
514                                         n++;
515                                 }
516
517                                 fclose(o);
518
519                                 msg(" * %d frames captured\n", frames_captured);
520                                 msg(" * %d frames filtered\n", frames_filtered);
521                                 msg(" * %d frames dumped\n", n);
522                         }
523
524                         run_dump = 0;
525                 }
526                 if (run_stop)
527                 {
528                         msg("Shutting down ...\n");
529
530                         if (promisc)
531                                 set_promisc(0);
532
533                         if (ring)
534                                 ringbuf_free(ring);
535
536                         return 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 }