/* $NetBSD: npfd.c,v 1.7 2017/01/24 20:24:59 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Mindaugas Rasiukevicius. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __RCSID("$NetBSD: npfd.c,v 1.7 2017/01/24 20:24:59 christos Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "npfd.h" static volatile sig_atomic_t hup, stats, done, flush; static int npfd_getctl(void) { int fd, ver; fd = open(NPF_DEV_PATH, O_RDONLY); if (fd == -1) { err(EXIT_FAILURE, "cannot open '%s'", NPF_DEV_PATH); } if (ioctl(fd, IOC_NPF_VERSION, &ver) == -1) { err(EXIT_FAILURE, "ioctl(IOC_NPF_VERSION)"); } if (ver != NPF_VERSION) { errx(EXIT_FAILURE, "Incompatible NPF interface version (%d, kernel %d)\n" "Hint: update userland?", NPF_VERSION, ver); } return fd; } static void npfd_event_loop(npfd_log_t *log, int delay) { struct pollfd pfd; size_t count = 0; pfd.fd = npfd_log_getsock(log); pfd.events = POLLHUP | POLLIN; while (!done) { if (hup) { hup = false; npfd_log_reopen(log, false); } if (stats) { stats = false; npfd_log_stats(log); } if (flush) { flush = false; npfd_log_flush(log); count = 0; } switch (poll(&pfd, 1, delay)) { case -1: if (errno == EINTR) continue; syslog(LOG_ERR, "poll failed: %m"); exit(EXIT_FAILURE); /*NOTREACHED*/ case 0: npfd_log_flush(log); count = 0; continue; default: if (count++ >= 100) { npfd_log_flush(log); count = 0; } npfd_log(log); } } npfd_log_destroy(log); } static void sighandler(int sig) { switch (sig) { case SIGHUP: hup = true; break; case SIGTERM: case SIGINT: done = true; break; case SIGINFO: stats = true; break; case SIGALRM: flush = true; break; default: syslog(LOG_ERR, "Unhandled signal %d", sig); break; } } static __dead void usage(void) { fprintf(stderr, "Usage: %s [-D] [-d ] [-i ]" " [-f ] [-p ] [-s ] expression\n", getprogname()); exit(EXIT_FAILURE); } static char * copyargs(int argc, char **argv) { if (argc == 0) return NULL; size_t len = 0, p = 0; char *buf = NULL; for (int i = 0; i < argc; i++) { size_t l = strlen(argv[i]); if (p + l + 1 >= len) buf = erealloc(buf, len = p + l + 1); memcpy(buf + p, argv[i], l); p += l; buf[p++] = i == argc - 1 ? '\0' : ' '; } return buf; } int main(int argc, char **argv) { bool daemon_off = false; int ch; int delay = 5 * 1000; const char *iface = "npflog0"; int snaplen = 116; char *pidname = NULL; char *filename = NULL; int fd = npfd_getctl(); (void)close(fd); while ((ch = getopt(argc, argv, "Dd:f:i:p:s:")) != -1) { switch (ch) { case 'D': daemon_off = true; break; case 'd': delay = atoi(optarg) * 1000; break; case 'f': filename = optarg; break; case 'i': iface = optarg; break; case 'p': pidname = optarg; break; case 's': snaplen = atoi(optarg); break; default: usage(); } } argc -= optind; argv += optind; char *filter = copyargs(argc, argv); npfd_log_t *log = npfd_log_create(filename, iface, filter, snaplen); if (!daemon_off) { if (daemon(0, 0) == -1) err(EXIT_FAILURE, "daemon"); pidfile(pidname); } openlog(argv[0], LOG_PID | LOG_NDELAY | LOG_CONS, LOG_DAEMON); signal(SIGHUP, sighandler); signal(SIGINT, sighandler); signal(SIGTERM, sighandler); signal(SIGINFO, sighandler); signal(SIGQUIT, sighandler); npfd_event_loop(log, delay); closelog(); return 0; }