/* darkstat 3
* copyright (c) 2001-2011 Emil Mikulic.
*
- * cap.c: interface to libpcap.
+ * cap.c: capture packets, and hand them off to decode and acct.
*
* You may use, modify and redistribute this file under the terms of the
* GNU General Public License version 2. (see COPYING.GPL)
#include "localip.h"
#include "now.h"
#include "opt.h"
+#include "queue.h"
+#include "str.h"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
+char *title_interfaces = NULL; /* for html.c */
+
/* The cap process life-cycle:
- *
- * Init - cap_init()
- * Fill fd_set - cap_fd_set()
- * Poll - cap_poll()
- * Stop - cap_stop()
+ * - cap_add_ifname() one or more times
+ * - cap_add_filter() zero or more times
+ * - cap_start() once to start listening
+ * Once per main loop:
+ * - cap_fd_set() to update the select() set
+ * - cap_poll() to read from ready pcap fds
+ * Shutdown:
+ * - cap_stop()
*/
-/* Globals - only useful within this module. */
-static pcap_t *pcap = NULL;
-static int pcap_fd = -1;
-static const struct linkhdr *linkhdr = NULL;
+struct strnode {
+ STAILQ_ENTRY(strnode) entries;
+ const char *str;
+};
-#define CAP_TIMEOUT 500 /* granularity of capture buffer, in milliseconds */
+struct cap_iface {
+ STAILQ_ENTRY(cap_iface) entries;
-/* ---------------------------------------------------------------------------
- * Init pcap. Exits on failure.
- */
-void
-cap_init(const char *device, const char *filter, int promisc)
-{
+ const char *name;
+ const char *filter;
+ pcap_t *pcap;
+ int fd;
+ const struct linkhdr *linkhdr;
+ struct local_ips local_ips;
+};
+
+static STAILQ_HEAD(cli_ifnames_head, strnode) cli_ifnames =
+ STAILQ_HEAD_INITIALIZER(cli_ifnames);
+
+static STAILQ_HEAD(cli_filters_head, strnode) cli_filters =
+ STAILQ_HEAD_INITIALIZER(cli_filters);
+
+static STAILQ_HEAD(cap_ifs_head, cap_iface) cap_ifs =
+ STAILQ_HEAD_INITIALIZER(cap_ifs);
+
+/* The read timeout passed to pcap_open_live() */
+#define CAP_TIMEOUT_MSEC 500
+
+void cap_add_ifname(const char *ifname) {
+ struct strnode *n = xmalloc(sizeof(*n));
+ n->str = ifname;
+ STAILQ_INSERT_TAIL(&cli_ifnames, n, entries);
+}
+
+void cap_add_filter(const char *filter) {
+ struct strnode *n = xmalloc(sizeof(*n));
+ n->str = filter;
+ STAILQ_INSERT_TAIL(&cli_filters, n, entries);
+}
+
+static void cap_set_filter(pcap_t *pcap, const char *filter) {
+ struct bpf_program prog;
+ char *tmp_filter;
+
+ if (filter == NULL)
+ return;
+
+ tmp_filter = xstrdup(filter);
+ if (pcap_compile(
+ pcap,
+ &prog,
+ tmp_filter,
+ 1, /* optimize */
+ 0) /* netmask */
+ == -1)
+ errx(1, "pcap_compile(): %s", pcap_geterr(pcap));
+
+ if (pcap_setfilter(pcap, &prog) == -1)
+ errx(1, "pcap_setfilter(): %s", pcap_geterr(pcap));
+
+ pcap_freecode(&prog);
+ free(tmp_filter);
+}
+
+static void cap_start_one(struct cap_iface *iface, const int promisc) {
char errbuf[PCAP_ERRBUF_SIZE], *tmp_device;
int linktype, snaplen, waited;
- /* pcap doesn't like device being const */
- tmp_device = xstrdup(device);
+ /* pcap wants a non-const interface name string */
+ tmp_device = xstrdup(iface->name);
+ if (iface->filter)
+ verbosef("capturing on interface '%s' with filter '%s'",
+ tmp_device, iface->filter);
+ else
+ verbosef("capturing on interface '%s' with no filter", tmp_device);
/* Open packet capture descriptor. */
waited = 0;
for (;;) {
errbuf[0] = '\0'; /* zero length string */
- pcap = pcap_open_live(
+ iface->pcap = pcap_open_live(
tmp_device,
1, /* snaplen, irrelevant at this point */
0, /* promisc, also irrelevant */
- CAP_TIMEOUT,
+ CAP_TIMEOUT_MSEC,
errbuf);
- if (pcap != NULL) break; /* success! */
+ if (iface->pcap != NULL)
+ break; /* success! */
if ((opt_wait_secs != -1) && strstr(errbuf, "device is not up")) {
if ((opt_wait_secs > 0) && (waited >= opt_wait_secs))
}
/* Work out the linktype and what snaplen we need. */
- linktype = pcap_datalink(pcap);
+ linktype = pcap_datalink(iface->pcap);
verbosef("linktype is %d", linktype);
if ((linktype == DLT_EN10MB) && opt_want_macs)
hosts_db_show_macs = 1;
- linkhdr = getlinkhdr(linktype);
- if (linkhdr == NULL)
+ iface->linkhdr = getlinkhdr(linktype);
+ if (iface->linkhdr == NULL)
errx(1, "unknown linktype %d", linktype);
- if (linkhdr->decoder == NULL)
+ if (iface->linkhdr->decoder == NULL)
errx(1, "no decoder for linktype %d", linktype);
- snaplen = getsnaplen(linkhdr);
+ snaplen = getsnaplen(iface->linkhdr);
if (opt_want_pppoe) {
snaplen += PPPOE_HDR_LEN;
if (linktype != DLT_EN10MB)
}
verbosef("calculated snaplen minimum %d", snaplen);
#ifdef linux
+ /* FIXME: actually due to libpcap moving to mmap (!!!)
+ * work out which version and fix the way we do capture
+ * on linux:
+ */
+
/* Ubuntu 9.04 has a problem where requesting snaplen <= 60 will
* give us 42 bytes, and we need at least 54 for TCP headers.
*
verbosef("using snaplen %d", snaplen);
/* Close and re-open pcap to use the new snaplen. */
- pcap_close(pcap);
+ pcap_close(iface->pcap);
errbuf[0] = '\0'; /* zero length string */
- pcap = pcap_open_live(
+ iface->pcap = pcap_open_live(
tmp_device,
snaplen,
promisc,
- CAP_TIMEOUT,
+ CAP_TIMEOUT_MSEC,
errbuf);
- if (pcap == NULL)
+ if (iface->pcap == NULL)
errx(1, "pcap_open_live(): %s", errbuf);
if (errbuf[0] != '\0') /* not zero length anymore -> warning */
else
verbosef("capturing in non-promiscuous mode");
- /* Set filter expression, if any. */
- if (filter != NULL)
- {
- struct bpf_program prog;
- char *tmp_filter = xstrdup(filter);
- if (pcap_compile(
- pcap,
- &prog,
- tmp_filter,
- 1, /* optimize */
- 0) /* netmask */
- == -1)
- errx(1, "pcap_compile(): %s", pcap_geterr(pcap));
-
- if (pcap_setfilter(pcap, &prog) == -1)
- errx(1, "pcap_setfilter(): %s", pcap_geterr(pcap));
-
- pcap_freecode(&prog);
- free(tmp_filter);
- }
-
- pcap_fd = pcap_fileno(pcap);
+ cap_set_filter(iface->pcap, iface->filter);
+ iface->fd = pcap_fileno(iface->pcap);
/* set non-blocking */
#ifdef linux
- if (pcap_setnonblock(pcap, 1, errbuf) == -1)
+ if (pcap_setnonblock(iface->pcap, 1, errbuf) == -1)
errx(1, "pcap_setnonblock(): %s", errbuf);
#else
-{ int one = 1;
- if (ioctl(pcap_fd, FIONBIO, &one) == -1)
- err(1, "ioctl(pcap_fd, FIONBIO)"); }
+ {
+ int one = 1;
+ if (ioctl(iface->fd, FIONBIO, &one) == -1)
+ err(1, "ioctl(iface->fd, FIONBIO)");
+ }
#endif
#ifdef BIOCSETWF
-{
- /* Deny all writes to the socket */
- struct bpf_insn bpf_wfilter[] = { BPF_STMT(BPF_RET+BPF_K, 0) };
- int wf_len = sizeof(bpf_wfilter) / sizeof(struct bpf_insn);
- struct bpf_program pr;
-
- pr.bf_len = wf_len;
- pr.bf_insns = bpf_wfilter;
-
- if (ioctl(pcap_fd, BIOCSETWF, &pr) == -1)
- err(1, "ioctl(pcap_fd, BIOCSETFW)");
- verbosef("filtered out BPF writes");
-}
+ {
+ /* Deny all writes to the socket */
+ struct bpf_insn bpf_wfilter[] = { BPF_STMT(BPF_RET+BPF_K, 0) };
+ int wf_len = sizeof(bpf_wfilter) / sizeof(struct bpf_insn);
+ struct bpf_program pr;
+
+ pr.bf_len = wf_len;
+ pr.bf_insns = bpf_wfilter;
+
+ if (ioctl(iface->fd, BIOCSETWF, &pr) == -1)
+ err(1, "ioctl(iface->fd, BIOCSETFW)");
+ verbosef("filtered out BPF writes");
+ }
#endif
#ifdef BIOCLOCK
/* set "locked" flag (no reset) */
- if (ioctl(pcap_fd, BIOCLOCK) == -1)
- err(1, "ioctl(pcap_fd, BIOCLOCK)");
+ if (ioctl(iface->fd, BIOCLOCK) == -1)
+ err(1, "ioctl(iface->fd, BIOCLOCK)");
verbosef("locked down BPF for security");
#endif
}
-/*
- * Set pcap_fd in the given fd_set.
- */
-void
-cap_fd_set(
+void cap_start(const int promisc) {
+ struct str *ifs = str_make();
+
+ assert(STAILQ_EMPTY(&cap_ifs));
+ if (STAILQ_EMPTY(&cli_ifnames))
+ errx(1, "no interfaces specified");
+
+ /* For each ifname */
+ while (!STAILQ_EMPTY(&cli_ifnames)) {
+ struct strnode *ifname, *filter = NULL;
+ struct cap_iface *iface = xmalloc(sizeof(*iface));
+
+ ifname = STAILQ_FIRST(&cli_ifnames);
+ STAILQ_REMOVE_HEAD(&cli_ifnames, entries);
+
+ if (!STAILQ_EMPTY(&cli_filters)) {
+ filter = STAILQ_FIRST(&cli_filters);
+ STAILQ_REMOVE_HEAD(&cli_filters, entries);
+ }
+
+ iface->name = ifname->str;
+ iface->filter = (filter == NULL) ? NULL : filter->str;
+ iface->pcap = NULL;
+ iface->fd = -1;
+ iface->linkhdr = NULL;
+ localip_init(&iface->local_ips);
+ STAILQ_INSERT_TAIL(&cap_ifs, iface, entries);
+ cap_start_one(iface, promisc);
+
+ free(ifname);
+ if (filter) free(filter);
+
+ if (str_len(ifs) == 0)
+ str_append(ifs, iface->name);
+ else
+ str_appendf(ifs, ", %s", iface->name);
+ }
+ verbosef("all capture interfaces prepared");
+
+ /* Deallocate extra filters, if any. */
+ while (!STAILQ_EMPTY(&cli_filters)) {
+ struct strnode *filter = STAILQ_FIRST(&cli_filters);
+
+ verbosef("ignoring extraneous filter '%s'", filter->str);
+ STAILQ_REMOVE_HEAD(&cli_filters, entries);
+ free(filter);
+ }
+
+ str_appendn(ifs, "", 1); /* NUL terminate */
+ {
+ size_t _;
+ str_extract(ifs, &_, &title_interfaces);
+ }
+}
+
#ifdef linux
- fd_set *read_set _unused_,
- int *max_fd _unused_,
- struct timeval *timeout,
+# define _unused_on_linux_ _unused_
#else
- fd_set *read_set,
- int *max_fd,
- struct timeval *timeout _unused_,
+# define _unused_on_linux_
#endif
- int *need_timeout)
-{
- assert(*need_timeout == 0); /* we're first to get a shot at this */
+
+/*
+ * Set pcap_fd in the given fd_set.
+ */
+void cap_fd_set(fd_set *read_set _unused_on_linux_,
+ int *max_fd _unused_on_linux_,
+ struct timeval *timeout,
+ int *need_timeout) {
+ assert(*need_timeout == 0); /* we're first to get a shot at the fd_set */
+
#ifdef linux
/*
* Linux's BPF is immediate, so don't select() as it will lead to horrible
*/
*need_timeout = 1;
timeout->tv_sec = 0;
- timeout->tv_usec = CAP_TIMEOUT * 1000; /* msec->usec */
+ timeout->tv_usec = CAP_TIMEOUT_MSEC * 1000;
#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);
+ {
+ struct cap_iface *iface;
+ STAILQ_FOREACH(iface, &cap_ifs, entries) {
+ /* We have a BSD-like BPF, we can select() on it. */
+ FD_SET(iface->fd, read_set);
+ *max_fd = MAX(*max_fd, iface->fd);
+ }
+ }
#endif
}
unsigned int cap_pkts_recv = 0, cap_pkts_drop = 0;
-static void
-cap_stats_update(void)
-{
- struct pcap_stat ps;
+static void cap_stats_update(void) {
+ struct cap_iface *iface;
- if (pcap_stats(pcap, &ps) != 0) {
- warnx("pcap_stats(): %s", pcap_geterr(pcap));
- return;
+ cap_pkts_recv = 0;
+ cap_pkts_drop = 0;
+ STAILQ_FOREACH(iface, &cap_ifs, entries) {
+ struct pcap_stat ps;
+ if (pcap_stats(iface->pcap, &ps) != 0) {
+ warnx("pcap_stats('%s'): %s", iface->name, pcap_geterr(iface->pcap));
+ return;
+ }
+ cap_pkts_recv += ps.ps_recv;
+ cap_pkts_drop += ps.ps_drop;
}
-
- cap_pkts_recv = ps.ps_recv;
- cap_pkts_drop = ps.ps_drop;
}
-/*
- * Print hexdump of received packet.
- */
-static void
-hexdump(const u_char *buf, const uint32_t len)
-{
+/* Print hexdump of received packet to stdout, for debugging. */
+static void hexdump(const u_char *buf,
+ const uint32_t len,
+ const struct linkhdr *linkhdr) {
uint32_t i, col;
printf("packet of %u bytes:\n", len);
}
/* Callback function for pcap_dispatch() which chains to the decoder specified
- * in linkhdr struct.
+ * in the linkhdr struct.
*/
-static void callback(u_char *user _unused_,
+static void callback(u_char *user,
const struct pcap_pkthdr *pheader,
const u_char *pdata) {
+ const struct cap_iface * const iface = (struct cap_iface *)user;
struct pktsummary sm;
if (opt_want_hexdump)
- hexdump(pdata, pheader->caplen);
+ hexdump(pdata, pheader->caplen, iface->linkhdr);
memset(&sm, 0, sizeof(sm));
- if (linkhdr->decoder(pheader, pdata, &sm))
- acct_for(&sm);
+ if (iface->linkhdr->decoder(pheader, pdata, &sm))
+ acct_for(&sm, &iface->local_ips);
}
-/*
- * Process any packets currently in the capture buffer.
- */
-void
-cap_poll(fd_set *read_set
-#ifdef linux
- _unused_
-#endif
-)
-{
- int total, ret;
+/* Process any packets currently in the capture buffer. */
+void cap_poll(fd_set *read_set _unused_on_linux_) {
+ int ret, premature = 1;
+ struct cap_iface *iface;
+ STAILQ_FOREACH(iface, &cap_ifs, entries) {
#ifndef linux /* We don't use select() on Linux. */
- if (!FD_ISSET(pcap_fd, read_set)) {
- verbosef("cap_poll premature");
- return;
- }
+ if (FD_ISSET(iface->fd, read_set))
+ premature = 0;
+ else
+ continue; /* skip this interface */
#endif
- /* Once per capture poll, check our IP address. It's used in accounting
- * for traffic graphs.
- */
- localip_update(opt_interface, local_ips);
-
- total = 0;
- for (;;) {
- struct timespec t;
-
- timer_start(&t);
- ret = pcap_dispatch(
- pcap,
- -1, /* count, -1 = entire buffer */
- callback,
- NULL); /* user */
- if (ret < 0) {
- warnx("pcap_dispatch(): %s", pcap_geterr(pcap));
- return;
- }
- timer_stop(&t, 2*CAP_TIMEOUT*1000000, "pcap_dispatch took too long");
-
- /* Despite count = -1, Linux will only dispatch one packet at a time. */
- total += ret;
+ /* Once per capture poll, check our IP address. It's used in accounting
+ * for traffic graphs.
+ */
+ localip_update(iface->name, &iface->local_ips);
+
+ for (;;) {
+ struct timespec t;
+
+ timer_start(&t);
+ ret = pcap_dispatch(
+ iface->pcap,
+ -1, /* count = entire buffer */
+ callback,
+ (u_char*)iface); /* user = struct to pass to callback */
+
+ if (ret < 0) {
+ warnx("pcap_dispatch('%s'): %s",
+ iface->name, pcap_geterr(iface->pcap));
+ continue;
+ }
+ timer_stop(&t,
+ 2 * CAP_TIMEOUT_MSEC * 1000000,
+ "pcap_dispatch took too long");
+
+ if (0) /* debugging */
+ verbosef("iface '%s' got %d pkts", iface->name, ret);
#ifdef linux
- /* keep looping until we've dispatched all the outstanding packets */
- if (ret == 0) break;
+ /* keep looping until we've dispatched all the outstanding packets */
+ if (ret == 0)
+ break;
+ else
+ premature = 0;
#else
- /* we get them all on the first shot */
- break;
+ /* we get them all on the first shot */
+ break;
#endif
+ }
}
+ if (premature)
+ verbosef("cap_poll() premature");
cap_stats_update();
}
-void
-cap_stop(void)
-{
- pcap_close(pcap);
+void cap_stop(void) {
+ while (!STAILQ_EMPTY(&cap_ifs)) {
+ struct cap_iface *iface = STAILQ_FIRST(&cap_ifs);
+
+ STAILQ_REMOVE_HEAD(&cap_ifs, entries);
+ pcap_close(iface->pcap);
+ localip_free(&iface->local_ips);
+ free(iface);
+ }
+ free(title_interfaces);
+ title_interfaces = NULL;
}
/* Run through entire capfile. */
-void
-cap_from_file(const char *capfile, const char *filter)
-{
+void cap_from_file(const char *capfile) {
char errbuf[PCAP_ERRBUF_SIZE];
int linktype, ret;
+ struct cap_iface iface;
+
+ iface.name = NULL;
+ iface.filter = NULL;
+ iface.pcap = NULL;
+ iface.fd = -1;
+ iface.linkhdr = NULL;
+ localip_init(&iface.local_ips);
+
+ /* Process cmdline filters. */
+ if (!STAILQ_EMPTY(&cli_filters))
+ iface.filter = STAILQ_FIRST(&cli_filters)->str;
+ while (!STAILQ_EMPTY(&cli_filters)) {
+ struct strnode *n = STAILQ_FIRST(&cli_filters);
+ STAILQ_REMOVE_HEAD(&cli_filters, entries);
+ free(n);
+ }
/* Open packet capture descriptor. */
errbuf[0] = '\0'; /* zero length string */
- pcap = pcap_open_offline(capfile, errbuf);
+ iface.pcap = pcap_open_offline(capfile, errbuf);
- if (pcap == NULL)
+ if (iface.pcap == NULL)
errx(1, "pcap_open_offline(): %s", errbuf);
if (errbuf[0] != '\0') /* not zero length anymore -> warning */
warnx("pcap_open_offline() warning: %s", errbuf);
/* Work out the linktype. */
- linktype = pcap_datalink(pcap);
- linkhdr = getlinkhdr(linktype);
- if (linkhdr == NULL)
+ linktype = pcap_datalink(iface.pcap);
+ iface.linkhdr = getlinkhdr(linktype);
+ if (iface.linkhdr == NULL)
errx(1, "unknown linktype %d", linktype);
- if (linkhdr->decoder == NULL)
+ if (iface.linkhdr->decoder == NULL)
errx(1, "no decoder for linktype %d", linktype);
- if (linktype == DLT_EN10MB) /* FIXME: impossible with capfile? */
- hosts_db_show_macs = 1;
- /* Set filter expression, if any. */ /* FIXME: factor! */
- if (filter != NULL)
- {
- struct bpf_program prog;
- char *tmp_filter = xstrdup(filter);
- if (pcap_compile(
- pcap,
- &prog,
- tmp_filter,
- 1, /* optimize */
- 0) /* netmask */
- == -1)
- errx(1, "pcap_compile(): %s", pcap_geterr(pcap));
-
- if (pcap_setfilter(pcap, &prog) == -1)
- errx(1, "pcap_setfilter(): %s", pcap_geterr(pcap));
-
- pcap_freecode(&prog);
- free(tmp_filter);
- }
+ cap_set_filter(iface.pcap, iface.filter);
/* Process file. */
ret = pcap_dispatch(
- pcap,
+ iface.pcap,
-1, /* count, -1 = entire buffer */
callback,
- NULL); /* user */
+ (u_char*)&iface); /* user */
if (ret < 0)
- errx(1, "pcap_dispatch(): %s", pcap_geterr(pcap));
+ errx(1, "pcap_dispatch(): %s", pcap_geterr(iface.pcap));
+
+ localip_free(&iface.local_ips);
+ pcap_close(iface.pcap);
}
/* vim:set ts=3 sw=3 tw=78 expandtab: */
static void sig_shutdown(int signum _unused_) { running = 0; }
static volatile int reset_pending = 0, export_pending = 0;
-static void sig_reset(int signum _unused_)
-{
+static void sig_reset(int signum _unused_) {
reset_pending = 1;
export_pending = 1;
}
static void sig_export(int signum _unused_) { export_pending = 1; }
/* --- Commandline parsing --- */
-static unsigned long
-parsenum(const char *str, unsigned long max /* 0 for no max */)
-{
+static unsigned long parsenum(const char *str,
+ unsigned long max /* 0 for no max */) {
unsigned long n;
char *end;
return n;
}
-const char *opt_interface = NULL;
-static void cb_interface(const char *arg) { opt_interface = arg; }
+static int opt_iface_seen = 0;
+static void cb_interface(const char *arg) {
+ cap_add_ifname(arg);
+ opt_iface_seen = 1;
+}
+
+static void cb_filter(const char *arg) { cap_add_filter(arg); }
const char *opt_capfile = NULL;
static void cb_capfile(const char *arg) { opt_capfile = arg; }
static void cb_bindaddr(const char *arg) { http_add_bindaddr(arg); }
-const char *opt_filter = NULL;
-static void cb_filter(const char *arg) { opt_filter = arg; }
-
static int is_localnet_specified = 0;
static void cb_local(const char *arg)
{
};
static struct cmdline_arg cmdline_args[] = {
- {"-i", "interface", cb_interface, 0},
- {"-r", "file", cb_capfile, 0},
+ {"-i", "interface", cb_interface, -1},
+ {"-f", "filter", cb_filter, -1},
+ {"-r", "capfile", cb_capfile, 0},
{"-p", "port", cb_port, 0},
{"-b", "bindaddr", cb_bindaddr, -1},
- {"-f", "filter", cb_filter, 0},
{"-l", "network/netmask", cb_local, 0},
{"--local-only", NULL, cb_local_only, 0},
{"--snaplen", "bytes", cb_snaplen, 0},
{NULL, NULL, NULL, 0}
};
-/*
- * We autogenerate the usage statement from the cmdline_args data structure.
- */
-static void
-usage(void)
-{
+/* We autogenerate the usage statement from the cmdline_args data structure. */
+static void usage(void) {
static char intro[] = "usage: darkstat ";
char indent[sizeof(intro)];
struct cmdline_arg *arg;
"documentation and usage examples.\n");
}
-static void
-parse_sub_cmdline(const int argc, char * const *argv)
-{
+static void parse_sub_cmdline(const int argc, char * const *argv) {
struct cmdline_arg *arg;
if (argc == 0) return;
exit(EXIT_FAILURE);
}
-static void
-parse_cmdline(const int argc, char * const *argv)
-{
+static void parse_cmdline(const int argc, char * const *argv) {
if (argc < 1) {
/* Not enough args. */
usage();
}
/* start syslogging as early as possible */
- if (opt_want_syslog) openlog("darkstat", LOG_NDELAY | LOG_PID, LOG_DAEMON);
+ if (opt_want_syslog)
+ openlog("darkstat", LOG_NDELAY | LOG_PID, LOG_DAEMON);
/* some default values */
- if (opt_chroot_dir == NULL) opt_chroot_dir = CHROOT_DIR;
- if (opt_privdrop_user == NULL) opt_privdrop_user = PRIVDROP_USER;
+ if (opt_chroot_dir == NULL)
+ opt_chroot_dir = CHROOT_DIR;
+ if (opt_privdrop_user == NULL)
+ opt_privdrop_user = PRIVDROP_USER;
/* sanity check args */
- if ((opt_interface == NULL) && (opt_capfile == NULL))
+ if (!opt_iface_seen && opt_capfile == NULL)
errx(1, "must specify either interface (-i) or capture file (-r)");
- if ((opt_interface != NULL) && (opt_capfile != NULL))
+ if (opt_iface_seen && opt_capfile != NULL)
errx(1, "can't specify both interface (-i) and capture file (-r)");
if ((opt_hosts_max != 0) && (opt_hosts_keep >= opt_hosts_max)) {
verbosef("WARNING: --local-only without -l only matches the local host");
}
-static void
-run_from_capfile(void)
-{
+static void run_from_capfile(void) {
+ now_init();
graph_init();
hosts_db_init();
- cap_from_file(opt_capfile, opt_filter);
- cap_stop();
+ cap_from_file(opt_capfile);
if (export_fn != NULL) db_export(export_fn);
hosts_db_free();
graph_free();
-#ifndef PRIu64
-#warning "PRIu64 is not defined, using qu instead"
-#define PRIu64 "qu"
-#endif
- verbosef("Total packets: %"PRIu64", bytes: %"PRIu64,
- acct_total_packets, acct_total_bytes);
+ verbosef("Total packets: %llu, bytes: %llu",
+ (unsigned long long)acct_total_packets,
+ (unsigned long long)acct_total_bytes);
}
/* --- Program body --- */
parse_cmdline(argc-1, argv+1);
if (opt_capfile) {
- /*
- * This is very different from a regular run against a network
- * interface.
- */
run_from_capfile();
return 0;
}
/* do this first as it forks - minimize memory use */
if (opt_want_dns) dns_init(opt_privdrop_user);
- cap_init(opt_interface, opt_filter, opt_want_promisc); /* needs root */
+ cap_start(opt_want_promisc); /* needs root */
http_listen(opt_bindport);
ncache_init(); /* must do before chroot() */
hosts_db_init();
if (import_fn != NULL) db_import(import_fn);
- local_ips = localip_make();
- localip_update(opt_interface, local_ips);
-
if (signal(SIGTERM, sig_shutdown) == SIG_ERR)
errx(1, "signal(SIGTERM) failed");
if (signal(SIGINT, sig_shutdown) == SIG_ERR)
if (daylog_fn != NULL) daylog_free();
ncache_free();
if (pid_fn) pidfile_unlink();
- localip_free(local_ips);
verbosef("shut down");
return (EXIT_SUCCESS);
}