Home | History | Annotate | Line # | Download | only in pflogd
      1 /*	$NetBSD: pflogd.c,v 1.14 2026/03/19 15:02:32 martin Exp $	*/
      2 /*	$OpenBSD: pflogd.c,v 1.45 2007/06/06 14:11:26 henning Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2001 Theo de Raadt
      6  * Copyright (c) 2001 Can Erkin Acar
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  *
     13  *    - Redistributions of source code must retain the above copyright
     14  *      notice, this list of conditions and the following disclaimer.
     15  *    - Redistributions in binary form must reproduce the above
     16  *      copyright notice, this list of conditions and the following
     17  *      disclaimer in the documentation and/or other materials provided
     18  *      with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/types.h>
     35 #include <sys/ioctl.h>
     36 #include <sys/file.h>
     37 #include <sys/stat.h>
     38 #include <sys/socket.h>
     39 #include <net/if.h>
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <unistd.h>
     44 /*
     45  * If we're going to include parts of the libpcap internals we MUST
     46  * set the feature-test macros they expect, or they may misbehave.
     47  */
     48 #define HAVE_STRLCPY
     49 #define HAVE_SNPRINTF
     50 #define HAVE_VSNPRINTF
     51 #define SIZEOF_TIME_T	8
     52 #include <pcap-int.h>
     53 #include <pcap.h>
     54 #include <syslog.h>
     55 #include <signal.h>
     56 #include <err.h>
     57 #include <errno.h>
     58 #include <stdarg.h>
     59 #include <fcntl.h>
     60 #include <util.h>
     61 #include "pflogd.h"
     62 
     63 pcap_t *hpcap;
     64 static FILE *dpcap;
     65 
     66 int Debug = 0;
     67 static uint32_t snaplen = DEF_SNAPLEN;
     68 static uint32_t cur_snaplen = DEF_SNAPLEN;
     69 
     70 volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup;
     71 
     72 const char *filename = PFLOGD_LOG_FILE;
     73 const char *interface = PFLOGD_DEFAULT_IF;
     74 const char *filter = NULL;
     75 
     76 char errbuf[PCAP_ERRBUF_SIZE];
     77 
     78 int log_debug = 0;
     79 unsigned int delay = FLUSH_DELAY;
     80 
     81 char *copy_argv(char * const *);
     82 void  dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
     83 void  dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
     84 int   flush_buffer(FILE *);
     85 int   if_exists(const char *);
     86 int   init_pcap(void);
     87 void  logmsg(int, const char *, ...);
     88 void  purge_buffer(void);
     89 int   reset_dump(int);
     90 int   scan_dump(FILE *, off_t);
     91 int   set_snaplen(uint32_t);
     92 void  set_suspended(int);
     93 void  sig_alrm(int);
     94 void  sig_close(int);
     95 void  sig_hup(int);
     96 void  usage(void);
     97 
     98 static int try_reset_dump(int);
     99 
    100 /* buffer must always be greater than snaplen */
    101 static size_t bufpkt = 0;	/* number of packets in buffer */
    102 static size_t buflen = 0;	/* allocated size of buffer */
    103 static char  *buffer = NULL;	/* packet buffer */
    104 static char  *bufpos = NULL;	/* position in buffer */
    105 static size_t bufleft = 0;	/* bytes left in buffer */
    106 
    107 /* if error, stop logging but count dropped packets */
    108 static int suspended = -1;
    109 static long packets_dropped = 0;
    110 
    111 /*
    112  * XXX Taken from libpcap. These are no longer exposed for >= 1.10.5,
    113  * for which tv_{,u}sec were converted to unsigned.
    114  */
    115 struct pcap_timeval {
    116 	uint32_t tv_sec;
    117 	uint32_t tv_usec;
    118 };
    119 struct pcap_sf_pkthdr {
    120 	struct pcap_timeval ts;
    121 	uint32_t caplen;
    122 	uint32_t len;
    123 };
    124 
    125 void
    126 set_suspended(int s)
    127 {
    128 	if (suspended == s)
    129 		return;
    130 
    131 	suspended = s;
    132 	setproctitle("[%s] -s %d -i %s -f %s",
    133 	    suspended ? "suspended" : "running",
    134 	    cur_snaplen, interface, filename);
    135 }
    136 
    137 char *
    138 copy_argv(char * const *argv)
    139 {
    140 	size_t len = 0, n;
    141 	char *buf;
    142 
    143 	if (argv == NULL)
    144 		return (NULL);
    145 
    146 	for (n = 0; argv[n]; n++)
    147 		len += strlen(argv[n])+1;
    148 	if (len == 0)
    149 		return (NULL);
    150 
    151 	buf = malloc(len);
    152 	if (buf == NULL)
    153 		return (NULL);
    154 
    155 	strlcpy(buf, argv[0], len);
    156 	for (n = 1; argv[n]; n++) {
    157 		strlcat(buf, " ", len);
    158 		strlcat(buf, argv[n], len);
    159 	}
    160 	return (buf);
    161 }
    162 
    163 void
    164 logmsg(int pri, const char *message, ...)
    165 {
    166 	va_list ap;
    167 	va_start(ap, message);
    168 
    169 	if (log_debug) {
    170 		vfprintf(stderr, message, ap);
    171 		fprintf(stderr, "\n");
    172 	} else
    173 		vsyslog(pri, message, ap);
    174 	va_end(ap);
    175 }
    176 
    177 __dead void
    178 usage(void)
    179 {
    180 	fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
    181 	fprintf(stderr, " [-i interface] [-p pidfile]\n");
    182 	fprintf(stderr, "              [-s snaplen] [expression]\n");
    183 	exit(1);
    184 }
    185 
    186 void
    187 sig_close(int sig)
    188 {
    189 	gotsig_close = 1;
    190 }
    191 
    192 void
    193 sig_hup(int sig)
    194 {
    195 	gotsig_hup = 1;
    196 }
    197 
    198 void
    199 sig_alrm(int sig)
    200 {
    201 	gotsig_alrm = 1;
    202 }
    203 
    204 void
    205 set_pcap_filter(void)
    206 {
    207 	struct bpf_program bprog;
    208 
    209 	if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
    210 		logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
    211 	else {
    212 		if (pcap_setfilter(hpcap, &bprog) < 0)
    213 			logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
    214 		pcap_freecode(&bprog);
    215 	}
    216 }
    217 
    218 int
    219 if_exists(const char *ifname)
    220 {
    221 	int s;
    222 #ifdef SIOCGIFDATA
    223 	struct ifdatareq ifr;
    224 #define ifr_name ifdr_name
    225 #else
    226 	struct ifreq ifr;
    227 	struct if_data ifrdat;
    228 #endif
    229 
    230 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    231 		err(1, "socket");
    232 	bzero(&ifr, sizeof(ifr));
    233 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
    234 		sizeof(ifr.ifr_name))
    235 			errx(1, "main ifr_name: strlcpy");
    236 #ifndef ifr_name
    237 	ifr.ifr_data = (caddr_t)&ifrdat;
    238 #endif
    239 	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
    240 		return (0);
    241 	if (close(s))
    242 		err(1, "close");
    243 
    244 	return (1);
    245 }
    246 
    247 int
    248 init_pcap(void)
    249 {
    250 	hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
    251 	if (hpcap == NULL) {
    252 		logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
    253 		return (-1);
    254 	}
    255 
    256 	if (pcap_datalink(hpcap) != DLT_PFLOG) {
    257 		logmsg(LOG_ERR, "Invalid datalink type");
    258 		pcap_close(hpcap);
    259 		hpcap = NULL;
    260 		return (-1);
    261 	}
    262 
    263 	set_pcap_filter();
    264 
    265 	cur_snaplen = snaplen = pcap_snapshot(hpcap);
    266 
    267 	/* lock */
    268 #ifdef __OpenBSD__
    269 	if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
    270 		logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
    271 		return (-1);
    272 	}
    273 #endif
    274 
    275 	return (0);
    276 }
    277 
    278 int
    279 set_snaplen(uint32_t snap)
    280 {
    281 	if (priv_set_snaplen(snap))
    282 		return (1);
    283 
    284 	if (cur_snaplen > snap)
    285 		purge_buffer();
    286 
    287 	cur_snaplen = snap;
    288 
    289 	return (0);
    290 }
    291 
    292 int
    293 reset_dump(int nomove)
    294 {
    295 	int ret;
    296 
    297 	for (;;) {
    298 		ret = try_reset_dump(nomove);
    299 		if (ret <= 0)
    300 			break;
    301 	}
    302 
    303 	return (ret);
    304 }
    305 
    306 /*
    307  * tries to (re)open log file, nomove flag is used with -x switch
    308  * returns 0: success, 1: retry (log moved), -1: error
    309  */
    310 int
    311 try_reset_dump(int nomove)
    312 {
    313 	struct pcap_file_header hdr;
    314 	struct stat st;
    315 	int fd;
    316 	FILE *fp;
    317 
    318 	if (hpcap == NULL)
    319 		return (-1);
    320 
    321 	if (dpcap) {
    322 		flush_buffer(dpcap);
    323 		fclose(dpcap);
    324 		dpcap = NULL;
    325 	}
    326 
    327 	/*
    328 	 * Basically reimplement pcap_dump_open() because it truncates
    329 	 * files and duplicates headers and such.
    330 	 */
    331 	fd = priv_open_log();
    332 	if (fd < 0)
    333 		return (-1);
    334 
    335 	fp = fdopen(fd, "a+");
    336 
    337 	if (fp == NULL) {
    338 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
    339 		close(fd);
    340 		return (-1);
    341 	}
    342 	if (fstat(fileno(fp), &st) == -1) {
    343 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
    344 		fclose(fp);
    345 		return (-1);
    346 	}
    347 
    348 	/* set FILE unbuffered, we do our own buffering */
    349 	if (setvbuf(fp, NULL, _IONBF, 0)) {
    350 		logmsg(LOG_ERR, "Failed to set output buffers");
    351 		fclose(fp);
    352 		return (-1);
    353 	}
    354 
    355 #define TCPDUMP_MAGIC 0xa1b2c3d4
    356 
    357 	if (st.st_size == 0) {
    358 		if (snaplen != cur_snaplen) {
    359 			logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
    360 			if (set_snaplen(snaplen))
    361 				logmsg(LOG_WARNING,
    362 				    "Failed, using old settings");
    363 		}
    364 		hdr.magic = TCPDUMP_MAGIC;
    365 		hdr.version_major = PCAP_VERSION_MAJOR;
    366 		hdr.version_minor = PCAP_VERSION_MINOR;
    367 		hdr.thiszone = 0;
    368 		hdr.sigfigs = 0;
    369 		hdr.snaplen = hpcap->snapshot;
    370 		hdr.linktype = hpcap->linktype;
    371 
    372 		if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
    373 			fclose(fp);
    374 			return (-1);
    375 		}
    376 	} else if (scan_dump(fp, st.st_size)) {
    377 		fclose(fp);
    378 		if (nomove || priv_move_log()) {
    379 			logmsg(LOG_ERR,
    380 			    "Invalid/incompatible log file, move it away");
    381 			return (-1);
    382 		}
    383 		return (1);
    384 	}
    385 
    386 	dpcap = fp;
    387 
    388 	set_suspended(0);
    389 	flush_buffer(fp);
    390 
    391 	return (0);
    392 }
    393 
    394 int
    395 scan_dump(FILE *fp, off_t size)
    396 {
    397 	struct pcap_file_header hdr;
    398 #ifdef __OpenBSD__
    399 	struct pcap_pkthdr ph;
    400 #else
    401 	struct pcap_sf_pkthdr ph;
    402 #endif
    403 	off_t pos;
    404 
    405 	/*
    406 	 * Must read the file, compare the header against our new
    407 	 * options (in particular, snaplen) and adjust our options so
    408 	 * that we generate a correct file. Furthermore, check the file
    409 	 * for consistency so that we can append safely.
    410 	 *
    411 	 * XXX this may take a long time for large logs.
    412 	 */
    413 	(void) fseek(fp, 0L, SEEK_SET);
    414 
    415 	if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
    416 		logmsg(LOG_ERR, "Short file header");
    417 		return (1);
    418 	}
    419 
    420 	if (hdr.magic != TCPDUMP_MAGIC ||
    421 	    hdr.version_major != PCAP_VERSION_MAJOR ||
    422 	    hdr.version_minor != PCAP_VERSION_MINOR ||
    423 	    hdr.linktype != (uint32_t)hpcap->linktype ||
    424 	    hdr.snaplen > PFLOGD_MAXSNAPLEN) {
    425 		return (1);
    426 	}
    427 
    428 	pos = sizeof(hdr);
    429 
    430 	while (!feof(fp)) {
    431 		off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
    432 		if (len == 0)
    433 			break;
    434 
    435 		if (len != sizeof(ph))
    436 			goto error;
    437 		if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
    438 			goto error;
    439 		pos += sizeof(ph) + ph.caplen;
    440 		if (pos > size)
    441 			goto error;
    442 		fseek(fp, ph.caplen, SEEK_CUR);
    443 	}
    444 
    445 	if (pos != size)
    446 		goto error;
    447 
    448 	if (hdr.snaplen != cur_snaplen) {
    449 		logmsg(LOG_WARNING,
    450 		       "Existing file has different snaplen %u, using it",
    451 		       hdr.snaplen);
    452 		if (set_snaplen(hdr.snaplen)) {
    453 			logmsg(LOG_WARNING,
    454 			       "Failed, using old settings, offset %llu",
    455 			       (unsigned long long) size);
    456 		}
    457 	}
    458 
    459 	return (0);
    460 
    461  error:
    462 	logmsg(LOG_ERR, "Corrupted log file.");
    463 	return (1);
    464 }
    465 
    466 /* dump a packet directly to the stream, which is unbuffered */
    467 void
    468 dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
    469 {
    470 #ifndef __OpenBSD__
    471 	struct pcap_sf_pkthdr sf_hdr;
    472 #endif
    473 	FILE *f = (FILE *)user;
    474 
    475 	if (suspended) {
    476 		packets_dropped++;
    477 		return;
    478 	}
    479 
    480 #ifndef __OpenBSD__
    481 	sf_hdr.ts.tv_sec  = h->ts.tv_sec;
    482 	sf_hdr.ts.tv_usec = h->ts.tv_usec;
    483 	sf_hdr.caplen     = h->caplen;
    484 	sf_hdr.len        = h->len;
    485 #endif
    486 
    487 #ifdef __OpenBSD__
    488 	if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
    489 #else
    490 	if (fwrite(&sf_hdr, sizeof(sf_hdr), 1, f) != 1) {
    491 #endif
    492 		/* try to undo header to prevent corruption */
    493 		size_t pos = (size_t)ftello(f);
    494 #ifdef __OpenBSD__
    495 		if (pos < sizeof(*h) ||
    496 		    ftruncate(fileno(f), pos - sizeof(*h))) {
    497 #else
    498 		if (pos < sizeof(sf_hdr) ||
    499 		    ftruncate(fileno(f), pos - sizeof(sf_hdr))) {
    500 #endif
    501 			logmsg(LOG_ERR, "Write failed, corrupted logfile!");
    502 			set_suspended(1);
    503 			gotsig_close = 1;
    504 			return;
    505 		}
    506 		goto error;
    507 	}
    508 
    509 	if (fwrite(sp, h->caplen, 1, f) != 1)
    510 		goto error;
    511 
    512 	return;
    513 
    514 error:
    515 	set_suspended(1);
    516 	packets_dropped ++;
    517 	logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
    518 }
    519 
    520 int
    521 flush_buffer(FILE *f)
    522 {
    523 	off_t offset;
    524 	int len = bufpos - buffer;
    525 
    526 	if (len <= 0)
    527 		return (0);
    528 
    529 	offset = ftello(f);
    530 	if (offset == (off_t)-1) {
    531 		set_suspended(1);
    532 		logmsg(LOG_ERR, "Logging suspended: ftello: %s",
    533 		    strerror(errno));
    534 		return (1);
    535 	}
    536 
    537 	if (fwrite(buffer, len, 1, f) != 1) {
    538 		set_suspended(1);
    539 		logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
    540 		    strerror(errno));
    541 		ftruncate(fileno(f), offset);
    542 		return (1);
    543 	}
    544 
    545 	set_suspended(0);
    546 	bufpos = buffer;
    547 	bufleft = buflen;
    548 	bufpkt = 0;
    549 
    550 	return (0);
    551 }
    552 
    553 void
    554 purge_buffer(void)
    555 {
    556 	packets_dropped += bufpkt;
    557 
    558 	set_suspended(0);
    559 	bufpos = buffer;
    560 	bufleft = buflen;
    561 	bufpkt = 0;
    562 }
    563 
    564 /* append packet to the buffer, flushing if necessary */
    565 void
    566 dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
    567 {
    568 	FILE *f = (FILE *)user;
    569 #ifdef __OpenBSD__
    570 	size_t len = sizeof(*h) + h->caplen;
    571 #else
    572 	struct pcap_sf_pkthdr sf_hdr;
    573 	size_t len = sizeof(sf_hdr) + h->caplen;
    574 #endif
    575 
    576 	if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
    577 		logmsg(LOG_NOTICE, "invalid size %zu (%u/%u), packet dropped",
    578 		       len, cur_snaplen, snaplen);
    579 		packets_dropped++;
    580 		return;
    581 	}
    582 
    583 	if (len <= bufleft)
    584 		goto append;
    585 
    586 	if (suspended) {
    587 		packets_dropped++;
    588 		return;
    589 	}
    590 
    591 	if (flush_buffer(f)) {
    592 		packets_dropped++;
    593 		return;
    594 	}
    595 
    596 	if (len > bufleft) {
    597 		dump_packet_nobuf(user, h, sp);
    598 		return;
    599 	}
    600 
    601  append:
    602 #ifdef __OpenBSD__
    603 	memcpy(bufpos, h, sizeof(*h));
    604 	memcpy(bufpos + sizeof(*h), sp, h->caplen);
    605 #else
    606 	sf_hdr.ts.tv_sec  = h->ts.tv_sec;
    607 	sf_hdr.ts.tv_usec = h->ts.tv_usec;
    608 	sf_hdr.caplen     = h->caplen;
    609 	sf_hdr.len        = h->len;
    610 
    611 	memcpy(bufpos, &sf_hdr, sizeof(sf_hdr));
    612 	memcpy(bufpos + sizeof(sf_hdr), sp, h->caplen);
    613 #endif
    614 
    615 	bufpos += len;
    616 	bufleft -= len;
    617 	bufpkt++;
    618 
    619 	return;
    620 }
    621 
    622 int
    623 main(int argc, char **argv)
    624 {
    625 	struct pcap_stat pstat;
    626 	int ch, np, ret, Xflag = 0;
    627 	pcap_handler phandler = dump_packet;
    628 	const char *errstr = NULL;
    629 	char *pidf = NULL;
    630 
    631 	ret = 0;
    632 
    633 	closefrom(STDERR_FILENO + 1);
    634 
    635 	while ((ch = getopt(argc, argv, "Dxd:f:i:p:s:")) != -1) {
    636 		switch (ch) {
    637 		case 'D':
    638 			Debug = 1;
    639 			break;
    640 		case 'd':
    641 			delay = strtonum(optarg, 5, 60*60, &errstr);
    642 			if (errstr)
    643 				usage();
    644 			break;
    645 		case 'f':
    646 			filename = optarg;
    647 			break;
    648 		case 'i':
    649 			interface = optarg;
    650 			break;
    651 		case 'p':
    652 			pidf = optarg;
    653 			break;
    654 		case 's':
    655 			snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
    656 			    &errstr);
    657 			if (snaplen <= 0)
    658 				snaplen = DEF_SNAPLEN;
    659 			if (errstr)
    660 				snaplen = PFLOGD_MAXSNAPLEN;
    661 			break;
    662 		case 'x':
    663 			Xflag++;
    664 			break;
    665 		default:
    666 			usage();
    667 		}
    668 
    669 	}
    670 
    671 	log_debug = Debug;
    672 	argc -= optind;
    673 	argv += optind;
    674 
    675 	/* does interface exist */
    676 	if (!if_exists(interface)) {
    677 		warn("Failed to initialize: %s", interface);
    678 		logmsg(LOG_ERR, "Failed to initialize: %s", interface);
    679 		logmsg(LOG_ERR, "Exiting, init failure");
    680 		exit(1);
    681 	}
    682 
    683 	if (!Debug) {
    684 		openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
    685 		if (daemon(0, 0)) {
    686 			logmsg(LOG_WARNING, "Failed to become daemon: %s",
    687 			    strerror(errno));
    688 		}
    689 		pidfile(pidf);
    690 	}
    691 
    692 	tzset();
    693 	(void)umask(S_IRWXG | S_IRWXO);
    694 
    695 	/* filter will be used by the privileged process */
    696 	if (argc) {
    697 		filter = copy_argv(argv);
    698 		if (filter == NULL)
    699 			logmsg(LOG_NOTICE, "Failed to form filter expression");
    700 	}
    701 
    702 	/* initialize pcap before dropping privileges */
    703 	if (init_pcap()) {
    704 		logmsg(LOG_ERR, "Exiting, init failure");
    705 		exit(1);
    706 	}
    707 
    708 	/* Privilege separation begins here */
    709 	if (priv_init()) {
    710 		logmsg(LOG_ERR, "unable to privsep");
    711 		exit(1);
    712 	}
    713 
    714 	setproctitle("[initializing]");
    715 	/* Process is now unprivileged and inside a chroot */
    716 	signal(SIGTERM, sig_close);
    717 	signal(SIGINT, sig_close);
    718 	signal(SIGQUIT, sig_close);
    719 	signal(SIGALRM, sig_alrm);
    720 	signal(SIGHUP, sig_hup);
    721 	alarm(delay);
    722 
    723 	buffer = malloc(PFLOGD_BUFSIZE);
    724 
    725 	if (buffer == NULL) {
    726 		logmsg(LOG_WARNING, "Failed to allocate output buffer");
    727 		phandler = dump_packet_nobuf;
    728 	} else {
    729 		bufleft = buflen = PFLOGD_BUFSIZE;
    730 		bufpos = buffer;
    731 		bufpkt = 0;
    732 	}
    733 
    734 	if (reset_dump(Xflag) < 0) {
    735 		if (Xflag)
    736 			return (1);
    737 
    738 		logmsg(LOG_ERR, "Logging suspended: open error");
    739 		set_suspended(1);
    740 	} else if (Xflag)
    741 		return (0);
    742 
    743 	while (1) {
    744 		np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
    745 		    phandler, (u_char *)dpcap);
    746 		if (np < 0) {
    747 			if (!if_exists(interface)) {
    748 				logmsg(LOG_NOTICE, "interface %s went away",
    749 				    interface);
    750 				ret = -1;
    751 				break;
    752 			}
    753 			logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
    754 		}
    755 
    756 		if (gotsig_close)
    757 			break;
    758 		if (gotsig_hup) {
    759 			if (reset_dump(0)) {
    760 				logmsg(LOG_ERR,
    761 				    "Logging suspended: open error");
    762 				set_suspended(1);
    763 			}
    764 			gotsig_hup = 0;
    765 		}
    766 
    767 		if (gotsig_alrm) {
    768 			if (dpcap)
    769 				flush_buffer(dpcap);
    770 			else
    771 				gotsig_hup = 1;
    772 			gotsig_alrm = 0;
    773 			alarm(delay);
    774 		}
    775 	}
    776 
    777 	logmsg(LOG_NOTICE, "Exiting");
    778 	if (dpcap) {
    779 		flush_buffer(dpcap);
    780 		fclose(dpcap);
    781 	}
    782 	purge_buffer();
    783 
    784 	if (pcap_stats(hpcap, &pstat) < 0)
    785 		logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
    786 	else
    787 		logmsg(LOG_NOTICE,
    788 		    "%u packets received, %u/%ld dropped (kernel/pflogd)",
    789 		    pstat.ps_recv, pstat.ps_drop, packets_dropped);
    790 
    791 	pcap_close(hpcap);
    792 	if (!Debug)
    793 		closelog();
    794 	return (ret);
    795 }
    796