/* darkstat 3
- * copyright (c) 2001-2009 Emil Mikulic.
+ * copyright (c) 2001-2011 Emil Mikulic.
*
* cap.c: interface to libpcap.
*
* GNU General Public License version 2. (see COPYING.GPL)
*/
-#include "darkstat.h"
+#include "cdefs.h"
#include "cap.h"
+#include "config.h"
#include "conv.h"
#include "decode.h"
#include "hosts_db.h"
#include "localip.h"
+#include "opt.h"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
-extern int want_pppoe, want_macs, want_hexdump, want_snaplen;
-
/* The cap process life-cycle:
*
* Init - cap_init()
/* Globals - only useful within this module. */
static pcap_t *pcap = NULL;
static int pcap_fd = -1;
-static const linkhdr_t *linkhdr = NULL;
+static const struct linkhdr *linkhdr = NULL;
#define CAP_TIMEOUT 500 /* granularity of capture buffer, in milliseconds */
cap_init(const char *device, const char *filter, int promisc)
{
char errbuf[PCAP_ERRBUF_SIZE], *tmp_device;
- int linktype, snaplen;
+ int linktype, snaplen, waited;
/* pcap doesn't like device being const */
tmp_device = xstrdup(device);
/* Open packet capture descriptor. */
- errbuf[0] = '\0'; /* zero length string */
- pcap = pcap_open_live(
- tmp_device,
- 1, /* snaplen, irrelevant at this point */
- 0, /* promisc, also irrelevant */
- CAP_TIMEOUT,
- errbuf);
-
- if (pcap == NULL)
- errx(1, "pcap_open_live(): %s", errbuf);
+ waited = 0;
+ for (;;) {
+ errbuf[0] = '\0'; /* zero length string */
+ pcap = pcap_open_live(
+ tmp_device,
+ 1, /* snaplen, irrelevant at this point */
+ 0, /* promisc, also irrelevant */
+ CAP_TIMEOUT,
+ errbuf);
+ if (pcap != NULL) break; /* success! */
+
+ if ((opt_wait_secs != -1) && strstr(errbuf, "device is not up")) {
+ if ((opt_wait_secs > 0) && (waited >= opt_wait_secs))
+ errx(1, "waited %d secs, giving up: pcap_open_live(): %s",
+ waited, errbuf);
+
+ verbosef("waited %d secs, interface is not up", waited);
+ sleep(1);
+ waited++;
+ }
+ else errx(1, "pcap_open_live(): %s", errbuf);
+ }
/* Work out the linktype and what snaplen we need. */
linktype = pcap_datalink(pcap);
verbosef("linktype is %d", linktype);
- if ((linktype == DLT_EN10MB) && want_macs)
- show_mac_addrs = 1;
+ if ((linktype == DLT_EN10MB) && opt_want_macs)
+ hosts_db_show_macs = 1;
linkhdr = getlinkhdr(linktype);
if (linkhdr == NULL)
errx(1, "unknown linktype %d", linktype);
if (linkhdr->handler == NULL)
errx(1, "no handler for linktype %d", linktype);
snaplen = getsnaplen(linkhdr);
- if (want_pppoe) {
+ if (opt_want_pppoe) {
snaplen += PPPOE_HDR_LEN;
if (linktype != DLT_EN10MB)
errx(1, "can't do PPPoE decoding on a non-Ethernet linktype");
*
* Hack to set minimum snaplen to tcpdump's default:
*/
- snaplen = max(snaplen, 68);
+ snaplen = MAX(snaplen, 96);
#endif
- if (want_snaplen > -1)
- snaplen = want_snaplen;
+ if (opt_want_snaplen > -1)
+ snaplen = opt_want_snaplen;
verbosef("using snaplen %d", snaplen);
/* Close and re-open pcap to use the new snaplen. */
#else
/* We have a BSD-like BPF, we can select() on it. */
FD_SET(pcap_fd, read_set);
- *max_fd = max(*max_fd, pcap_fd);
+ *max_fd = MAX(*max_fd, pcap_fd);
#endif
}
-unsigned int pkts_recv = 0, pkts_drop = 0;
+unsigned int cap_pkts_recv = 0, cap_pkts_drop = 0;
static void
cap_stats_update(void)
return;
}
- pkts_recv = ps.ps_recv;
- pkts_drop = ps.ps_drop;
+ cap_pkts_recv = ps.ps_recv;
+ cap_pkts_drop = ps.ps_drop;
}
/*
uint32_t i, col;
printf("packet of %u bytes:\n", len);
- col = 0;
for (i=0, col=0; i<len; i++) {
if (col == 0) printf(" ");
printf("%02x", buf[i]);
static void
callback(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
{
- if (want_hexdump) hexdump(bytes, h->caplen);
+ if (opt_want_hexdump) hexdump(bytes, h->caplen);
linkhdr->handler(user, h, bytes);
}
total = 0;
for (;;) {
+#ifndef NDEBUG
+ struct timeval t1;
+ gettimeofday(&t1, NULL);
+#endif
ret = pcap_dispatch(
pcap,
-1, /* count, -1 = entire buffer */
return;
}
+#ifndef NDEBUG
+ {
+ struct timeval t2;
+ int td;
+
+ gettimeofday(&t2, NULL);
+ td = (t2.tv_sec - t1.tv_sec) * 1000000 + t2.tv_usec - t1.tv_usec;
+ if (td > CAP_TIMEOUT*1000)
+ warnx("pcap_dispatch blocked for %d usec! (expected <= %d usec)\n",
+ td, CAP_TIMEOUT*1000);
+ }
+#endif
+
/* Despite count = -1, Linux will only dispatch one packet at a time. */
total += ret;
break;
#endif
}
- /*FIXME*/if (want_verbose) fprintf(stderr, "%-20d\r", total);
cap_stats_update();
}
if (linkhdr->handler == NULL)
errx(1, "no handler for linktype %d", linktype);
if (linktype == DLT_EN10MB) /* FIXME: impossible with capfile? */
- show_mac_addrs = 1;
+ hosts_db_show_macs = 1;
/* Set filter expression, if any. */ /* FIXME: factor! */
if (filter != NULL)