On Tue, Sep 22, 2015 at 11:46:08AM -0400, Ted Unangst wrote:
> Todd C. Miller wrote:
> > On Mon, 21 Sep 2015 20:13:05 -0400, "Ted Unangst" wrote:
> > 
> > > We can put a "long" poll() in front of pcap to wait until there are 
> > > packets
> > > (maybe never if you aren't using pf logging), and then let the timeout 
> > > work
> > > it's magic.
> > 
> > This:
> > 
> > > +         if (poll(&pfd, 1, INFTIM) == 1) {
> > 
> > will also match POLLHUP and POLLERR which doesn't appear to be what
> > you want.  You need to explicitly check for pfd.revents & POLLIN.
> 
> poll, you sneaky bastard. I wonder if this program could also benefit from
> handling signals via kevent, but that's a bigger change.
> 

WIP:

Index: pflogd.c
===================================================================
RCS file: /home/vcs/cvs/openbsd/src/sbin/pflogd/pflogd.c,v
retrieving revision 1.51
diff -u -p -r1.51 pflogd.c
--- pflogd.c    7 Feb 2015 02:09:13 -0000       1.51
+++ pflogd.c    23 Sep 2015 03:47:37 -0000
@@ -32,6 +32,7 @@
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#include <sys/event.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <net/if.h>
@@ -57,8 +58,6 @@ int Debug = 0;
 static int snaplen = DEF_SNAPLEN;
 static int cur_snaplen = DEF_SNAPLEN;
 
-volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup, gotsig_usr1;
-
 char *filename = PFLOGD_LOG_FILE;
 char *interface = PFLOGD_DEFAULT_IF;
 char *filter = NULL;
@@ -66,7 +65,6 @@ char *filter = NULL;
 char errbuf[PCAP_ERRBUF_SIZE];
 
 int log_debug = 0;
-unsigned int delay = FLUSH_DELAY;
 
 char *copy_argv(char * const *);
 void  dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
@@ -81,10 +79,6 @@ int   reset_dump(int);
 int   scan_dump(FILE *, off_t);
 int   set_snaplen(int);
 void  set_suspended(int);
-void  sig_alrm(int);
-void  sig_usr1(int);
-void  sig_close(int);
-void  sig_hup(int);
 void  usage(void);
 
 static int try_reset_dump(int);
@@ -95,6 +89,7 @@ static int    buflen = 0;     /* allocated s
 static char  *buffer = NULL;   /* packet buffer */
 static char  *bufpos = NULL;   /* position in buffer */
 static int    bufleft = 0;     /* bytes left in buffer */
+static int    buftimer = 0;     /* periodic buffer flush on/off */
 
 /* if error, stop logging but count dropped packets */
 static int suspended = -1;
@@ -162,30 +157,6 @@ usage(void)
 }
 
 void
-sig_close(int sig)
-{
-       gotsig_close = 1;
-}
-
-void
-sig_hup(int sig)
-{
-       gotsig_hup = 1;
-}
-
-void
-sig_alrm(int sig)
-{
-       gotsig_alrm = 1;
-}
-
-void
-sig_usr1(int sig)
-{
-       gotsig_usr1 = 1;
-}
-
-void
 set_pcap_filter(void)
 {
        struct bpf_program bprog;
@@ -224,7 +195,7 @@ if_exists(char *ifname)
 int
 init_pcap(void)
 {
-       hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
+       hpcap = pcap_open_live(interface, snaplen, 1, 0, errbuf);
        if (hpcap == NULL) {
                logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
                return (-1);
@@ -439,6 +410,7 @@ void
 dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 {
        FILE *f = (FILE *)user;
+       fprintf(stderr, "%s called\n", __func__);
 
        if (suspended) {
                packets_dropped++;
@@ -453,7 +425,7 @@ dump_packet_nobuf(u_char *user, const st
                    ftruncate(fileno(f), pos - sizeof(*h))) {
                        logmsg(LOG_ERR, "Write failed, corrupted logfile!");
                        set_suspended(1);
-                       gotsig_close = 1;
+                       raise(SIGTERM);
                        return;
                }
                goto error;
@@ -499,6 +471,7 @@ flush_buffer(FILE *f)
        bufpos = buffer;
        bufleft = buflen;
        bufpkt = 0;
+       buftimer = 0;
 
        return (0);
 }
@@ -512,6 +485,7 @@ purge_buffer(void)
        bufpos = buffer;
        bufleft = buflen;
        bufpkt = 0;
+       buftimer = 0;
 }
 
 /* append packet to the buffer, flushing if necessary */
@@ -521,6 +495,8 @@ dump_packet(u_char *user, const struct p
        FILE *f = (FILE *)user;
        size_t len = sizeof(*h) + h->caplen;
 
+       fprintf(stderr, "%s called\n", __func__);
+
        if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
                logmsg(LOG_NOTICE, "invalid size %zu (%d/%d), packet dropped",
                       len, cur_snaplen, snaplen);
@@ -553,6 +529,7 @@ dump_packet(u_char *user, const struct p
        bufpos += len;
        bufleft -= len;
        bufpkt++;
+       buftimer = 1;
 
        return;
 }
@@ -575,6 +552,9 @@ main(int argc, char **argv)
        int ch, np, ret, Xflag = 0;
        pcap_handler phandler = dump_packet;
        const char *errstr = NULL;
+       int kq, pcap_fd, nchanges;
+       int delay = FLUSH_DELAY * 1000;
+       struct kevent ev[6];
 
        ret = 0;
 
@@ -586,7 +566,7 @@ main(int argc, char **argv)
                        Debug = 1;
                        break;
                case 'd':
-                       delay = strtonum(optarg, 5, 60*60, &errstr);
+                       delay = strtonum(optarg, 5, 60*60, &errstr) * 1000;
                        if (errstr)
                                usage();
                        break;
@@ -657,16 +637,13 @@ main(int argc, char **argv)
 
        setproctitle("[initializing]");
        /* Process is now unprivileged and inside a chroot */
-       signal(SIGTERM, sig_close);
-       signal(SIGINT, sig_close);
-       signal(SIGQUIT, sig_close);
-       signal(SIGALRM, sig_alrm);
-       signal(SIGUSR1, sig_usr1);
-       signal(SIGHUP, sig_hup);
-       alarm(delay);
 
-       buffer = malloc(PFLOGD_BUFSIZE);
+       if ((kq = kqueue()) < 0) {
+               logmsg(LOG_ERR, "Kqueue failed");
+               exit(1);
+       }
 
+       buffer = malloc(PFLOGD_BUFSIZE);
        if (buffer == NULL) {
                logmsg(LOG_WARNING, "Failed to allocate output buffer");
                phandler = dump_packet_nobuf;
@@ -674,6 +651,7 @@ main(int argc, char **argv)
                bufleft = buflen = PFLOGD_BUFSIZE;
                bufpos = buffer;
                bufpkt = 0;
+               buftimer = 0;
        }
 
        if (reset_dump(Xflag) < 0) {
@@ -685,42 +663,98 @@ main(int argc, char **argv)
        } else if (Xflag)
                return (0);
 
+       if ((pcap_fd = pcap_get_selectable_fd(hpcap)) < 0) {
+               logmsg(LOG_ERR, "pcap_get_selectable_fd failed");
+               exit(1);
+       }
+       EV_SET(&ev[0], pcap_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, NULL);
+
+       signal(SIGTERM, SIG_IGN);
+       EV_SET(&ev[1], SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+       signal(SIGINT, SIG_IGN);
+       EV_SET(&ev[2], SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+       signal(SIGQUIT, SIG_IGN);
+       EV_SET(&ev[3], SIGQUIT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+       signal(SIGUSR1, SIG_IGN);
+       EV_SET(&ev[4], SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+       signal(SIGHUP, SIG_IGN);
+       EV_SET(&ev[5], SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+       nchanges = 6;
+
+
        while (1) {
-               np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
-                   phandler, (u_char *)dpcap);
-               if (np < 0) {
-                       if (!if_exists(interface)) {
-                               logmsg(LOG_NOTICE, "interface %s went away",
-                                   interface);
-                               ret = -1;
+               int events;
+               fprintf(stderr, "main loop (nchanges=%d)...\n", nchanges);
+               events = kevent(kq, ev, nchanges, ev, 1, NULL);
+               nchanges = 0;
+               fprintf(stderr, "kevent returns %d\n", events);
+               if (events == 0) /* timeout */
+                       continue;
+               if (events < 0) {
+                       logmsg(LOG_ERR, "event loop error");
+                       break;
+               }
+
+               if (ev->filter == EVFILT_SIGNAL) {
+                       fprintf(stderr, "received signal %d\n", (int)ev->ident);
+                       if (ev->ident == SIGTERM || ev->ident == SIGINT
+                           || ev->ident == SIGQUIT) {
+                               fprintf(stderr, "leaving main loop\n");
                                break;
                        }
-                       logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
-               }
 
-               if (gotsig_close)
-                       break;
-               if (gotsig_hup) {
-                       if (reset_dump(0)) {
-                               logmsg(LOG_ERR,
-                                   "Logging suspended: open error");
-                               set_suspended(1);
+                       if (ev->ident == SIGHUP) {
+                               fprintf(stderr, "got SIGHUP\n");
+                               if (reset_dump(0)) {
+                                       logmsg(LOG_ERR,
+                                           "Logging suspended: open error");
+                                       set_suspended(1);
+                               }
+                       }
+
+                       if (ev->ident == SIGUSR1) {
+                               fprintf(stderr, "got SIGUSR1\n");
+                               log_pcap_stats();
+                       }
+               } else if (ev->filter == EVFILT_READ) {
+                       fprintf(stderr, "pcap data available\n");
+                       np = pcap_dispatch(hpcap, PCAP_NUM_PKTS, phandler, 
(u_char *)dpcap);
+                       fprintf(stderr, "pcap_dispatch returned %d\n", np);
+                       if (np < 0) {
+                               if (!if_exists(interface)) {
+                                       logmsg(LOG_NOTICE,
+                                           "interface %s went away", 
interface);
+                                       ret = -1;
+                                       break;
+                               }
+                               logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
                        }
-                       gotsig_hup = 0;
-               }
 
-               if (gotsig_alrm) {
-                       if (dpcap)
+                       if (buftimer) {
+                               fprintf(stderr, "arming timer\n");
+                               EV_SET(&ev[nchanges], 0, EVFILT_TIMER,
+                                   EV_ADD | EV_ENABLE, 0, delay, NULL);
+                               nchanges++;
+                       }
+               } else if (ev->filter == EVFILT_TIMER) {
+                       fprintf(stderr, "EVFILT_TIMER event\n");
+                       if (dpcap) {
+                               fprintf(stderr, "calling flush_buffer()\n");
                                flush_buffer(dpcap);
-                       else 
-                               gotsig_hup = 1;
-                       gotsig_alrm = 0;
-                       alarm(delay);
-               }
+                       } else {
+                               if (reset_dump(0)) {
+                                       logmsg(LOG_ERR,
+                                           "Logging suspended: open error");
+                                       set_suspended(1);
+                               }
+                       }
 
-               if (gotsig_usr1) {
-                       log_pcap_stats();
-                       gotsig_usr1 = 0;
+                       if (!buftimer) {
+                               fprintf(stderr, "disarming timer\n");
+                               EV_SET(&ev[nchanges], 0, EVFILT_TIMER,
+                                   EV_ADD | EV_DISABLE, 0, delay, NULL);
+                               nchanges++;
+                       }
                }
        }
 
Index: pflogd.h
===================================================================
RCS file: /home/vcs/cvs/openbsd/src/sbin/pflogd/pflogd.h,v
retrieving revision 1.4
diff -u -p -r1.4 pflogd.h
--- pflogd.h    21 Sep 2010 05:56:58 -0000      1.4
+++ pflogd.h    23 Sep 2015 03:47:37 -0000
@@ -20,7 +20,6 @@
 #include <pcap.h>
 
 #define DEF_SNAPLEN 160                /* pfloghdr + ip hdr + proto hdr fit 
usually */
-#define PCAP_TO_MS 500         /* pcap read timeout (ms) */
 #define PCAP_NUM_PKTS 1000     /* max number of packets to process at each 
loop */
 #define PCAP_OPT_FIL 1         /* filter optimization */
 #define FLUSH_DELAY 60         /* flush delay */

Reply via email to