make depend
[darkstat] / cap.c
1 /* darkstat 3
2 * copyright (c) 2001-2011 Emil Mikulic.
3 *
4 * cap.c: capture packets, and hand them off to decode and acct.
5 *
6 * You may use, modify and redistribute this file under the terms of the
7 * GNU General Public License version 2. (see COPYING.GPL)
8 */
9
10 #include "acct.h"
11 #include "cdefs.h"
12 #include "cap.h"
13 #include "config.h"
14 #include "conv.h"
15 #include "decode.h"
16 #include "err.h"
17 #include "hosts_db.h"
18 #include "localip.h"
19 #include "now.h"
20 #include "opt.h"
21 #include "queue.h"
22 #include "str.h"
23
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/wait.h>
28 #ifdef HAVE_SYS_FILIO_H
29 # include <sys/filio.h> /* Solaris' FIONBIO hides here */
30 #endif
31 #include <assert.h>
32 #include <pcap.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 char *title_interfaces = NULL; /* for html.c */
39
40 /* The cap process life-cycle:
41 * - cap_add_ifname() one or more times
42 * - cap_add_filter() zero or more times
43 * - cap_start() once to start listening
44 * Once per main loop:
45 * - cap_fd_set() to update the select() set
46 * - cap_poll() to read from ready pcap fds
47 * Shutdown:
48 * - cap_stop()
49 */
50
51 struct strnode {
52 STAILQ_ENTRY(strnode) entries;
53 const char *str;
54 };
55
56 struct cap_iface {
57 STAILQ_ENTRY(cap_iface) entries;
58
59 const char *name;
60 const char *filter;
61 pcap_t *pcap;
62 int fd;
63 const struct linkhdr *linkhdr;
64 struct local_ips local_ips;
65 };
66
67 static STAILQ_HEAD(cli_ifnames_head, strnode) cli_ifnames =
68 STAILQ_HEAD_INITIALIZER(cli_ifnames);
69
70 static STAILQ_HEAD(cli_filters_head, strnode) cli_filters =
71 STAILQ_HEAD_INITIALIZER(cli_filters);
72
73 static STAILQ_HEAD(cap_ifs_head, cap_iface) cap_ifs =
74 STAILQ_HEAD_INITIALIZER(cap_ifs);
75
76 /* The read timeout passed to pcap_open_live() */
77 #define CAP_TIMEOUT_MSEC 500
78
79 void cap_add_ifname(const char *ifname) {
80 struct strnode *n = xmalloc(sizeof(*n));
81 n->str = ifname;
82 STAILQ_INSERT_TAIL(&cli_ifnames, n, entries);
83 }
84
85 void cap_add_filter(const char *filter) {
86 struct strnode *n = xmalloc(sizeof(*n));
87 n->str = filter;
88 STAILQ_INSERT_TAIL(&cli_filters, n, entries);
89 }
90
91 static void cap_set_filter(pcap_t *pcap, const char *filter) {
92 struct bpf_program prog;
93 char *tmp_filter;
94
95 if (filter == NULL)
96 return;
97
98 tmp_filter = xstrdup(filter);
99 if (pcap_compile(
100 pcap,
101 &prog,
102 tmp_filter,
103 1, /* optimize */
104 0) /* netmask */
105 == -1)
106 errx(1, "pcap_compile(): %s", pcap_geterr(pcap));
107
108 if (pcap_setfilter(pcap, &prog) == -1)
109 errx(1, "pcap_setfilter(): %s", pcap_geterr(pcap));
110
111 pcap_freecode(&prog);
112 free(tmp_filter);
113 }
114
115 static void cap_start_one(struct cap_iface *iface, const int promisc) {
116 char errbuf[PCAP_ERRBUF_SIZE], *tmp_device;
117 int linktype, snaplen, waited;
118
119 /* pcap wants a non-const interface name string */
120 tmp_device = xstrdup(iface->name);
121 if (iface->filter)
122 verbosef("capturing on interface '%s' with filter '%s'",
123 tmp_device, iface->filter);
124 else
125 verbosef("capturing on interface '%s' with no filter", tmp_device);
126
127 /* Open packet capture descriptor. */
128 waited = 0;
129 for (;;) {
130 errbuf[0] = '\0'; /* zero length string */
131 iface->pcap = pcap_open_live(
132 tmp_device,
133 1, /* snaplen, irrelevant at this point */
134 0, /* promisc, also irrelevant */
135 CAP_TIMEOUT_MSEC,
136 errbuf);
137 if (iface->pcap != NULL)
138 break; /* success! */
139
140 if ((opt_wait_secs != -1) && strstr(errbuf, "device is not up")) {
141 if ((opt_wait_secs > 0) && (waited >= opt_wait_secs))
142 errx(1, "waited %d secs, giving up: pcap_open_live(): %s",
143 waited, errbuf);
144
145 verbosef("waited %d secs, interface is not up", waited);
146 sleep(1);
147 waited++;
148 }
149 else errx(1, "pcap_open_live(): %s", errbuf);
150 }
151
152 /* Work out the linktype and what snaplen we need. */
153 linktype = pcap_datalink(iface->pcap);
154 verbosef("linktype is %d", linktype);
155 if ((linktype == DLT_EN10MB) && opt_want_macs)
156 hosts_db_show_macs = 1;
157 iface->linkhdr = getlinkhdr(linktype);
158 if (iface->linkhdr == NULL)
159 errx(1, "unknown linktype %d", linktype);
160 if (iface->linkhdr->decoder == NULL)
161 errx(1, "no decoder for linktype %d", linktype);
162 snaplen = getsnaplen(iface->linkhdr);
163 if (opt_want_pppoe) {
164 snaplen += PPPOE_HDR_LEN;
165 if (linktype != DLT_EN10MB)
166 errx(1, "can't do PPPoE decoding on a non-Ethernet linktype");
167 }
168 verbosef("calculated snaplen minimum %d", snaplen);
169 #ifdef linux
170 /* FIXME: actually due to libpcap moving to mmap (!!!)
171 * work out which version and fix the way we do capture
172 * on linux:
173 */
174
175 /* Ubuntu 9.04 has a problem where requesting snaplen <= 60 will
176 * give us 42 bytes, and we need at least 54 for TCP headers.
177 *
178 * Hack to set minimum snaplen to tcpdump's default:
179 */
180 snaplen = MAX(snaplen, 96);
181 #endif
182 if (opt_want_snaplen > -1)
183 snaplen = opt_want_snaplen;
184 verbosef("using snaplen %d", snaplen);
185
186 /* Close and re-open pcap to use the new snaplen. */
187 pcap_close(iface->pcap);
188 errbuf[0] = '\0'; /* zero length string */
189 iface->pcap = pcap_open_live(
190 tmp_device,
191 snaplen,
192 promisc,
193 CAP_TIMEOUT_MSEC,
194 errbuf);
195
196 if (iface->pcap == NULL)
197 errx(1, "pcap_open_live(): %s", errbuf);
198
199 if (errbuf[0] != '\0') /* not zero length anymore -> warning */
200 warnx("pcap_open_live() warning: %s", errbuf);
201
202 free(tmp_device);
203
204 if (promisc)
205 verbosef("capturing in promiscuous mode");
206 else
207 verbosef("capturing in non-promiscuous mode");
208
209 cap_set_filter(iface->pcap, iface->filter);
210 iface->fd = pcap_fileno(iface->pcap);
211
212 /* set non-blocking */
213 #ifdef linux
214 if (pcap_setnonblock(iface->pcap, 1, errbuf) == -1)
215 errx(1, "pcap_setnonblock(): %s", errbuf);
216 #else
217 {
218 int one = 1;
219 if (ioctl(iface->fd, FIONBIO, &one) == -1)
220 err(1, "ioctl(iface->fd, FIONBIO)");
221 }
222 #endif
223
224 #ifdef BIOCSETWF
225 {
226 /* Deny all writes to the socket */
227 struct bpf_insn bpf_wfilter[] = { BPF_STMT(BPF_RET+BPF_K, 0) };
228 int wf_len = sizeof(bpf_wfilter) / sizeof(struct bpf_insn);
229 struct bpf_program pr;
230
231 pr.bf_len = wf_len;
232 pr.bf_insns = bpf_wfilter;
233
234 if (ioctl(iface->fd, BIOCSETWF, &pr) == -1)
235 err(1, "ioctl(iface->fd, BIOCSETFW)");
236 verbosef("filtered out BPF writes");
237 }
238 #endif
239
240 #ifdef BIOCLOCK
241 /* set "locked" flag (no reset) */
242 if (ioctl(iface->fd, BIOCLOCK) == -1)
243 err(1, "ioctl(iface->fd, BIOCLOCK)");
244 verbosef("locked down BPF for security");
245 #endif
246 }
247
248 void cap_start(const int promisc) {
249 struct str *ifs = str_make();
250
251 assert(STAILQ_EMPTY(&cap_ifs));
252 if (STAILQ_EMPTY(&cli_ifnames))
253 errx(1, "no interfaces specified");
254
255 /* For each ifname */
256 while (!STAILQ_EMPTY(&cli_ifnames)) {
257 struct strnode *ifname, *filter = NULL;
258 struct cap_iface *iface = xmalloc(sizeof(*iface));
259
260 ifname = STAILQ_FIRST(&cli_ifnames);
261 STAILQ_REMOVE_HEAD(&cli_ifnames, entries);
262
263 if (!STAILQ_EMPTY(&cli_filters)) {
264 filter = STAILQ_FIRST(&cli_filters);
265 STAILQ_REMOVE_HEAD(&cli_filters, entries);
266 }
267
268 iface->name = ifname->str;
269 iface->filter = (filter == NULL) ? NULL : filter->str;
270 iface->pcap = NULL;
271 iface->fd = -1;
272 iface->linkhdr = NULL;
273 localip_init(&iface->local_ips);
274 STAILQ_INSERT_TAIL(&cap_ifs, iface, entries);
275 cap_start_one(iface, promisc);
276
277 free(ifname);
278 if (filter) free(filter);
279
280 if (str_len(ifs) == 0)
281 str_append(ifs, iface->name);
282 else
283 str_appendf(ifs, ", %s", iface->name);
284 }
285 verbosef("all capture interfaces prepared");
286
287 /* Deallocate extra filters, if any. */
288 while (!STAILQ_EMPTY(&cli_filters)) {
289 struct strnode *filter = STAILQ_FIRST(&cli_filters);
290
291 verbosef("ignoring extraneous filter '%s'", filter->str);
292 STAILQ_REMOVE_HEAD(&cli_filters, entries);
293 free(filter);
294 }
295
296 str_appendn(ifs, "", 1); /* NUL terminate */
297 {
298 size_t _;
299 str_extract(ifs, &_, &title_interfaces);
300 }
301 }
302
303 #ifdef linux
304 # define _unused_on_linux_ _unused_
305 # define _unused_otherwise_
306 #else
307 # define _unused_on_linux_
308 # define _unused_otherwise_ _unused_
309 #endif
310
311 /*
312 * Set pcap_fd in the given fd_set.
313 */
314 void cap_fd_set(fd_set *read_set _unused_on_linux_,
315 int *max_fd _unused_on_linux_,
316 struct timeval *timeout _unused_otherwise_,
317 int *need_timeout) {
318 assert(*need_timeout == 0); /* we're first to get a shot at the fd_set */
319
320 #ifdef linux
321 /*
322 * Linux's BPF is immediate, so don't select() as it will lead to horrible
323 * performance. Instead, use a timeout for buffering.
324 */
325 *need_timeout = 1;
326 timeout->tv_sec = 0;
327 timeout->tv_usec = CAP_TIMEOUT_MSEC * 1000;
328 #else
329 {
330 struct cap_iface *iface;
331 STAILQ_FOREACH(iface, &cap_ifs, entries) {
332 /* We have a BSD-like BPF, we can select() on it. */
333 FD_SET(iface->fd, read_set);
334 *max_fd = MAX(*max_fd, iface->fd);
335 }
336 }
337 #endif
338 }
339
340 unsigned int cap_pkts_recv = 0, cap_pkts_drop = 0;
341
342 static void cap_stats_update(void) {
343 struct cap_iface *iface;
344
345 cap_pkts_recv = 0;
346 cap_pkts_drop = 0;
347 STAILQ_FOREACH(iface, &cap_ifs, entries) {
348 struct pcap_stat ps;
349 if (pcap_stats(iface->pcap, &ps) != 0) {
350 warnx("pcap_stats('%s'): %s", iface->name, pcap_geterr(iface->pcap));
351 return;
352 }
353 cap_pkts_recv += ps.ps_recv;
354 cap_pkts_drop += ps.ps_drop;
355 }
356 }
357
358 /* Print hexdump of received packet to stdout, for debugging. */
359 static void hexdump(const u_char *buf,
360 const uint32_t len,
361 const struct linkhdr *linkhdr) {
362 uint32_t i, col;
363
364 printf("packet of %u bytes:\n", len);
365 for (i=0, col=0; i<len; i++) {
366 if (col == 0) printf(" ");
367 printf("%02x", buf[i]);
368 if (i+1 == linkhdr->hdrlen)
369 printf("|"); /* marks end of link headers (e.g. ethernet) */
370 else
371 printf(" ");
372 col += 3;
373 if (col >= 72) {
374 printf("\n");
375 col = 0;
376 }
377 }
378 if (col != 0) printf("\n");
379 printf("\n");
380 }
381
382 /* Callback function for pcap_dispatch() which chains to the decoder specified
383 * in the linkhdr struct.
384 */
385 static void callback(u_char *user,
386 const struct pcap_pkthdr *pheader,
387 const u_char *pdata) {
388 const struct cap_iface * const iface = (struct cap_iface *)user;
389 struct pktsummary sm;
390
391 if (opt_want_hexdump)
392 hexdump(pdata, pheader->caplen, iface->linkhdr);
393 memset(&sm, 0, sizeof(sm));
394 if (iface->linkhdr->decoder(pheader, pdata, &sm))
395 acct_for(&sm, &iface->local_ips);
396 }
397
398 /* Process any packets currently in the capture buffer. */
399 void cap_poll(fd_set *read_set _unused_on_linux_) {
400 struct cap_iface *iface;
401
402 STAILQ_FOREACH(iface, &cap_ifs, entries) {
403 /* Once per capture poll, check our IP address. It's used in accounting
404 * for traffic graphs.
405 */
406 localip_update(iface->name, &iface->local_ips);
407
408 for (;;) {
409 struct timespec t;
410 int ret;
411
412 timer_start(&t);
413 ret = pcap_dispatch(
414 iface->pcap,
415 -1, /* count = entire buffer */
416 callback,
417 (u_char*)iface); /* user = struct to pass to callback */
418
419 if (ret < 0) {
420 warnx("pcap_dispatch('%s'): %s",
421 iface->name, pcap_geterr(iface->pcap));
422 continue;
423 }
424 timer_stop(&t,
425 2 * CAP_TIMEOUT_MSEC * 1000000,
426 "pcap_dispatch took too long");
427
428 #if 0 /* debugging */
429 verbosef("iface '%s' got %d pkts", iface->name, ret);
430 #endif
431
432 #ifdef linux
433 /* keep looping until we've dispatched all the outstanding packets */
434 if (ret == 0)
435 break;
436 #else
437 /* we get them all on the first shot */
438 break;
439 #endif
440 }
441 }
442 cap_stats_update();
443 }
444
445 void cap_stop(void) {
446 while (!STAILQ_EMPTY(&cap_ifs)) {
447 struct cap_iface *iface = STAILQ_FIRST(&cap_ifs);
448
449 STAILQ_REMOVE_HEAD(&cap_ifs, entries);
450 pcap_close(iface->pcap);
451 localip_free(&iface->local_ips);
452 free(iface);
453 }
454 free(title_interfaces);
455 title_interfaces = NULL;
456 }
457
458 /* Run through entire capfile. */
459 void cap_from_file(const char *capfile) {
460 char errbuf[PCAP_ERRBUF_SIZE];
461 int linktype, ret;
462 struct cap_iface iface;
463
464 iface.name = NULL;
465 iface.filter = NULL;
466 iface.pcap = NULL;
467 iface.fd = -1;
468 iface.linkhdr = NULL;
469 localip_init(&iface.local_ips);
470
471 /* Process cmdline filters. */
472 if (!STAILQ_EMPTY(&cli_filters))
473 iface.filter = STAILQ_FIRST(&cli_filters)->str;
474 while (!STAILQ_EMPTY(&cli_filters)) {
475 struct strnode *n = STAILQ_FIRST(&cli_filters);
476 STAILQ_REMOVE_HEAD(&cli_filters, entries);
477 free(n);
478 }
479
480 /* Open packet capture descriptor. */
481 errbuf[0] = '\0'; /* zero length string */
482 iface.pcap = pcap_open_offline(capfile, errbuf);
483
484 if (iface.pcap == NULL)
485 errx(1, "pcap_open_offline(): %s", errbuf);
486
487 if (errbuf[0] != '\0') /* not zero length anymore -> warning */
488 warnx("pcap_open_offline() warning: %s", errbuf);
489
490 /* Work out the linktype. */
491 linktype = pcap_datalink(iface.pcap);
492 iface.linkhdr = getlinkhdr(linktype);
493 if (iface.linkhdr == NULL)
494 errx(1, "unknown linktype %d", linktype);
495 if (iface.linkhdr->decoder == NULL)
496 errx(1, "no decoder for linktype %d", linktype);
497
498 cap_set_filter(iface.pcap, iface.filter);
499
500 /* Process file. */
501 ret = pcap_dispatch(
502 iface.pcap,
503 -1, /* count, -1 = entire buffer */
504 callback,
505 (u_char*)&iface); /* user */
506
507 if (ret < 0)
508 errx(1, "pcap_dispatch(): %s", pcap_geterr(iface.pcap));
509
510 localip_free(&iface.local_ips);
511 pcap_close(iface.pcap);
512 }
513
514 /* vim:set ts=3 sw=3 tw=78 expandtab: */