xref: /freebsd/contrib/pf/pflogd/pflogd.c (revision 34aa6f2c2db5cc9655f201a1ef01adbb9fb484d5)
1e0bfbfceSBjoern A. Zeeb /*	$OpenBSD: pflogd.c,v 1.46 2008/10/22 08:16:49 henning Exp $	*/
213b9f610SMax Laier 
313b9f610SMax Laier /*
413b9f610SMax Laier  * Copyright (c) 2001 Theo de Raadt
513b9f610SMax Laier  * Copyright (c) 2001 Can Erkin Acar
613b9f610SMax Laier  * All rights reserved.
713b9f610SMax Laier  *
813b9f610SMax Laier  * Redistribution and use in source and binary forms, with or without
913b9f610SMax Laier  * modification, are permitted provided that the following conditions
1013b9f610SMax Laier  * are met:
1113b9f610SMax Laier  *
1213b9f610SMax Laier  *    - Redistributions of source code must retain the above copyright
1313b9f610SMax Laier  *      notice, this list of conditions and the following disclaimer.
1413b9f610SMax Laier  *    - Redistributions in binary form must reproduce the above
1513b9f610SMax Laier  *      copyright notice, this list of conditions and the following
1613b9f610SMax Laier  *      disclaimer in the documentation and/or other materials provided
1713b9f610SMax Laier  *      with the distribution.
1813b9f610SMax Laier  *
1913b9f610SMax Laier  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2013b9f610SMax Laier  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2113b9f610SMax Laier  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2213b9f610SMax Laier  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2313b9f610SMax Laier  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2413b9f610SMax Laier  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2513b9f610SMax Laier  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2613b9f610SMax Laier  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2713b9f610SMax Laier  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813b9f610SMax Laier  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2913b9f610SMax Laier  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3013b9f610SMax Laier  * POSSIBILITY OF SUCH DAMAGE.
3113b9f610SMax Laier  */
3213b9f610SMax Laier 
3313b9f610SMax Laier #include <sys/types.h>
3422ac3eadSMax Laier #include <sys/ioctl.h>
3513b9f610SMax Laier #include <sys/file.h>
3613b9f610SMax Laier #include <sys/stat.h>
37e0bfbfceSBjoern A. Zeeb #include <sys/socket.h>
38e0bfbfceSBjoern A. Zeeb #include <net/if.h>
3913b9f610SMax Laier #include <stdio.h>
4013b9f610SMax Laier #include <stdlib.h>
4113b9f610SMax Laier #include <string.h>
4213b9f610SMax Laier #include <unistd.h>
4313b9f610SMax Laier #include <pcap-int.h>
4413b9f610SMax Laier #include <pcap.h>
4513b9f610SMax Laier #include <syslog.h>
4613b9f610SMax Laier #include <signal.h>
47e0bfbfceSBjoern A. Zeeb #include <err.h>
4813b9f610SMax Laier #include <errno.h>
4913b9f610SMax Laier #include <stdarg.h>
5013b9f610SMax Laier #include <fcntl.h>
51b83a49e9SMax Laier #ifdef __FreeBSD__
52e0bfbfceSBjoern A. Zeeb #include <ifaddrs.h>
538c8618f5SMax Laier #include "pidfile.h"
548c8618f5SMax Laier #else
5513b9f610SMax Laier #include <util.h>
568c8618f5SMax Laier #endif
5722ac3eadSMax Laier #include "pflogd.h"
5813b9f610SMax Laier 
5913b9f610SMax Laier pcap_t *hpcap;
6022ac3eadSMax Laier static FILE *dpcap;
6113b9f610SMax Laier 
6213b9f610SMax Laier int Debug = 0;
6322ac3eadSMax Laier static int snaplen = DEF_SNAPLEN;
6422ac3eadSMax Laier static int cur_snaplen = DEF_SNAPLEN;
6513b9f610SMax Laier 
66e0bfbfceSBjoern A. Zeeb volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup, gotsig_usr1;
6713b9f610SMax Laier 
6813b9f610SMax Laier char *filename = PFLOGD_LOG_FILE;
6913b9f610SMax Laier char *interface = PFLOGD_DEFAULT_IF;
7013b9f610SMax Laier char *filter = NULL;
7113b9f610SMax Laier 
7213b9f610SMax Laier char errbuf[PCAP_ERRBUF_SIZE];
7313b9f610SMax Laier 
7413b9f610SMax Laier int log_debug = 0;
7513b9f610SMax Laier unsigned int delay = FLUSH_DELAY;
7613b9f610SMax Laier 
77*34aa6f2cSJoseph Mingrone struct pcap_timeval {
78*34aa6f2cSJoseph Mingrone 	bpf_u_int32 tv_sec;	/* seconds */
79*34aa6f2cSJoseph Mingrone 	bpf_u_int32 tv_usec;	/* microseconds */
80*34aa6f2cSJoseph Mingrone };
81*34aa6f2cSJoseph Mingrone 
82*34aa6f2cSJoseph Mingrone struct pcap_sf_pkthdr {
83*34aa6f2cSJoseph Mingrone 	struct pcap_timeval ts;	/* time stamp */
84*34aa6f2cSJoseph Mingrone 	bpf_u_int32 caplen;	/* length of portion present */
85*34aa6f2cSJoseph Mingrone 	bpf_u_int32 len;	/* length of this packet (off wire) */
86*34aa6f2cSJoseph Mingrone };
87*34aa6f2cSJoseph Mingrone 
8822ac3eadSMax Laier char *copy_argv(char * const *);
8922ac3eadSMax Laier void  dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
9022ac3eadSMax Laier void  dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
91e0bfbfceSBjoern A. Zeeb void  log_pcap_stats(void);
9222ac3eadSMax Laier int   flush_buffer(FILE *);
93e0bfbfceSBjoern A. Zeeb int   if_exists(char *);
9413b9f610SMax Laier int   init_pcap(void);
9522ac3eadSMax Laier void  logmsg(int, const char *, ...);
9622ac3eadSMax Laier void  purge_buffer(void);
975ee7cd21SMax Laier int   reset_dump(int);
9822ac3eadSMax Laier int   scan_dump(FILE *, off_t);
9922ac3eadSMax Laier int   set_snaplen(int);
10022ac3eadSMax Laier void  set_suspended(int);
10113b9f610SMax Laier void  sig_alrm(int);
102e0bfbfceSBjoern A. Zeeb void  sig_usr1(int);
10313b9f610SMax Laier void  sig_close(int);
10413b9f610SMax Laier void  sig_hup(int);
10513b9f610SMax Laier void  usage(void);
10613b9f610SMax Laier 
1075ee7cd21SMax Laier static int try_reset_dump(int);
1085ee7cd21SMax Laier 
10922ac3eadSMax Laier /* buffer must always be greater than snaplen */
11022ac3eadSMax Laier static int    bufpkt = 0;	/* number of packets in buffer */
11122ac3eadSMax Laier static int    buflen = 0;	/* allocated size of buffer */
11222ac3eadSMax Laier static char  *buffer = NULL;	/* packet buffer */
11322ac3eadSMax Laier static char  *bufpos = NULL;	/* position in buffer */
11422ac3eadSMax Laier static int    bufleft = 0;	/* bytes left in buffer */
11522ac3eadSMax Laier 
11622ac3eadSMax Laier /* if error, stop logging but count dropped packets */
11722ac3eadSMax Laier static int suspended = -1;
11822ac3eadSMax Laier static long packets_dropped = 0;
11922ac3eadSMax Laier 
12022ac3eadSMax Laier void
set_suspended(int s)12122ac3eadSMax Laier set_suspended(int s)
12222ac3eadSMax Laier {
12322ac3eadSMax Laier 	if (suspended == s)
12422ac3eadSMax Laier 		return;
12522ac3eadSMax Laier 
12622ac3eadSMax Laier 	suspended = s;
1275ee7cd21SMax Laier 	setproctitle("[%s] -s %d -i %s -f %s",
1285ee7cd21SMax Laier 	    suspended ? "suspended" : "running",
1295ee7cd21SMax Laier 	    cur_snaplen, interface, filename);
13022ac3eadSMax Laier }
13113b9f610SMax Laier 
13213b9f610SMax Laier char *
copy_argv(char * const * argv)13313b9f610SMax Laier copy_argv(char * const *argv)
13413b9f610SMax Laier {
13513b9f610SMax Laier 	size_t len = 0, n;
13613b9f610SMax Laier 	char *buf;
13713b9f610SMax Laier 
13813b9f610SMax Laier 	if (argv == NULL)
13913b9f610SMax Laier 		return (NULL);
14013b9f610SMax Laier 
14113b9f610SMax Laier 	for (n = 0; argv[n]; n++)
14213b9f610SMax Laier 		len += strlen(argv[n])+1;
14313b9f610SMax Laier 	if (len == 0)
14413b9f610SMax Laier 		return (NULL);
14513b9f610SMax Laier 
14613b9f610SMax Laier 	buf = malloc(len);
14713b9f610SMax Laier 	if (buf == NULL)
14813b9f610SMax Laier 		return (NULL);
14913b9f610SMax Laier 
15013b9f610SMax Laier 	strlcpy(buf, argv[0], len);
15113b9f610SMax Laier 	for (n = 1; argv[n]; n++) {
15213b9f610SMax Laier 		strlcat(buf, " ", len);
15313b9f610SMax Laier 		strlcat(buf, argv[n], len);
15413b9f610SMax Laier 	}
15513b9f610SMax Laier 	return (buf);
15613b9f610SMax Laier }
15713b9f610SMax Laier 
15813b9f610SMax Laier void
logmsg(int pri,const char * message,...)15913b9f610SMax Laier logmsg(int pri, const char *message, ...)
16013b9f610SMax Laier {
16113b9f610SMax Laier 	va_list ap;
16213b9f610SMax Laier 	va_start(ap, message);
16313b9f610SMax Laier 
16413b9f610SMax Laier 	if (log_debug) {
16513b9f610SMax Laier 		vfprintf(stderr, message, ap);
16613b9f610SMax Laier 		fprintf(stderr, "\n");
16713b9f610SMax Laier 	} else
16813b9f610SMax Laier 		vsyslog(pri, message, ap);
16913b9f610SMax Laier 	va_end(ap);
17013b9f610SMax Laier }
17113b9f610SMax Laier 
172b83a49e9SMax Laier #ifdef __FreeBSD__
173b83a49e9SMax Laier __dead2 void
174b83a49e9SMax Laier #else
17513b9f610SMax Laier __dead void
176b83a49e9SMax Laier #endif
usage(void)17713b9f610SMax Laier usage(void)
17813b9f610SMax Laier {
17922ac3eadSMax Laier 	fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
180e0bfbfceSBjoern A. Zeeb 	fprintf(stderr, " [-i interface] [-p pidfile]\n");
181e0bfbfceSBjoern A. Zeeb 	fprintf(stderr, "              [-s snaplen] [expression]\n");
18213b9f610SMax Laier 	exit(1);
18313b9f610SMax Laier }
18413b9f610SMax Laier 
18513b9f610SMax Laier void
sig_close(int sig)18613b9f610SMax Laier sig_close(int sig)
18713b9f610SMax Laier {
18813b9f610SMax Laier 	gotsig_close = 1;
18913b9f610SMax Laier }
19013b9f610SMax Laier 
19113b9f610SMax Laier void
sig_hup(int sig)19213b9f610SMax Laier sig_hup(int sig)
19313b9f610SMax Laier {
19413b9f610SMax Laier 	gotsig_hup = 1;
19513b9f610SMax Laier }
19613b9f610SMax Laier 
19713b9f610SMax Laier void
sig_alrm(int sig)19813b9f610SMax Laier sig_alrm(int sig)
19913b9f610SMax Laier {
20013b9f610SMax Laier 	gotsig_alrm = 1;
20113b9f610SMax Laier }
20213b9f610SMax Laier 
20322ac3eadSMax Laier void
sig_usr1(int sig)204e0bfbfceSBjoern A. Zeeb sig_usr1(int sig)
205e0bfbfceSBjoern A. Zeeb {
206e0bfbfceSBjoern A. Zeeb 	gotsig_usr1 = 1;
207e0bfbfceSBjoern A. Zeeb }
208e0bfbfceSBjoern A. Zeeb 
209e0bfbfceSBjoern A. Zeeb void
set_pcap_filter(void)21022ac3eadSMax Laier set_pcap_filter(void)
21113b9f610SMax Laier {
21213b9f610SMax Laier 	struct bpf_program bprog;
21313b9f610SMax Laier 
21413b9f610SMax Laier 	if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
21513b9f610SMax Laier 		logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
21622ac3eadSMax Laier 	else {
21722ac3eadSMax Laier 		if (pcap_setfilter(hpcap, &bprog) < 0)
21813b9f610SMax Laier 			logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
21922ac3eadSMax Laier 		pcap_freecode(&bprog);
22022ac3eadSMax Laier 	}
22122ac3eadSMax Laier }
22222ac3eadSMax Laier 
22322ac3eadSMax Laier int
if_exists(char * ifname)224e0bfbfceSBjoern A. Zeeb if_exists(char *ifname)
225e0bfbfceSBjoern A. Zeeb {
226e0bfbfceSBjoern A. Zeeb #ifdef __FreeBSD__
227e0bfbfceSBjoern A. Zeeb 	struct ifaddrs *ifdata, *mb;
228e0bfbfceSBjoern A. Zeeb 	int exists = 0;
229e0bfbfceSBjoern A. Zeeb 
230e0bfbfceSBjoern A. Zeeb 	getifaddrs(&ifdata);
231e0bfbfceSBjoern A. Zeeb         if (ifdata == NULL)
232e0bfbfceSBjoern A. Zeeb 		return (0);
233e0bfbfceSBjoern A. Zeeb 
234e0bfbfceSBjoern A. Zeeb 	for (mb = ifdata; mb != NULL; mb = mb->ifa_next) {
235e0bfbfceSBjoern A. Zeeb 		if (mb == NULL)
236e0bfbfceSBjoern A. Zeeb 			continue;
237e0bfbfceSBjoern A. Zeeb 		if (strlen(ifname) != strlen(mb->ifa_name))
238e0bfbfceSBjoern A. Zeeb 			continue;
239e0bfbfceSBjoern A. Zeeb 		if (strncmp(ifname, mb->ifa_name, strlen(ifname)) != 0)
240e0bfbfceSBjoern A. Zeeb 			continue;
241e0bfbfceSBjoern A. Zeeb 		exists = 1;
242e0bfbfceSBjoern A. Zeeb 		break;
243e0bfbfceSBjoern A. Zeeb 	}
244e0bfbfceSBjoern A. Zeeb 	freeifaddrs(ifdata);
245e0bfbfceSBjoern A. Zeeb 
246e0bfbfceSBjoern A. Zeeb 	return (exists);
247e0bfbfceSBjoern A. Zeeb #else
248e0bfbfceSBjoern A. Zeeb 	int s;
249e0bfbfceSBjoern A. Zeeb 	struct ifreq ifr;
250e0bfbfceSBjoern A. Zeeb 	struct if_data ifrdat;
251e0bfbfceSBjoern A. Zeeb 
252e0bfbfceSBjoern A. Zeeb 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
253e0bfbfceSBjoern A. Zeeb 		err(1, "socket");
254e0bfbfceSBjoern A. Zeeb 	bzero(&ifr, sizeof(ifr));
255e0bfbfceSBjoern A. Zeeb 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
256e0bfbfceSBjoern A. Zeeb 		sizeof(ifr.ifr_name))
257e0bfbfceSBjoern A. Zeeb 			errx(1, "main ifr_name: strlcpy");
258e0bfbfceSBjoern A. Zeeb 	ifr.ifr_data = (caddr_t)&ifrdat;
259e0bfbfceSBjoern A. Zeeb 	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
260e0bfbfceSBjoern A. Zeeb 		return (0);
261e0bfbfceSBjoern A. Zeeb 	if (close(s))
262e0bfbfceSBjoern A. Zeeb 		err(1, "close");
263e0bfbfceSBjoern A. Zeeb 
264e0bfbfceSBjoern A. Zeeb 	return (1);
265e0bfbfceSBjoern A. Zeeb #endif
266e0bfbfceSBjoern A. Zeeb }
267e0bfbfceSBjoern A. Zeeb 
268e0bfbfceSBjoern A. Zeeb int
init_pcap(void)26922ac3eadSMax Laier init_pcap(void)
27022ac3eadSMax Laier {
27122ac3eadSMax Laier 	hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
27222ac3eadSMax Laier 	if (hpcap == NULL) {
27322ac3eadSMax Laier 		logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
27422ac3eadSMax Laier 		return (-1);
27522ac3eadSMax Laier 	}
27613b9f610SMax Laier 
27713b9f610SMax Laier 	if (pcap_datalink(hpcap) != DLT_PFLOG) {
27813b9f610SMax Laier 		logmsg(LOG_ERR, "Invalid datalink type");
27913b9f610SMax Laier 		pcap_close(hpcap);
28022ac3eadSMax Laier 		hpcap = NULL;
28113b9f610SMax Laier 		return (-1);
28213b9f610SMax Laier 	}
28313b9f610SMax Laier 
28422ac3eadSMax Laier 	set_pcap_filter();
28513b9f610SMax Laier 
28622ac3eadSMax Laier 	cur_snaplen = snaplen = pcap_snapshot(hpcap);
28722ac3eadSMax Laier 
28822ac3eadSMax Laier 	/* lock */
28922ac3eadSMax Laier 	if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
29022ac3eadSMax Laier 		logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
29122ac3eadSMax Laier 		return (-1);
29222ac3eadSMax Laier 	}
29322ac3eadSMax Laier 
29422ac3eadSMax Laier 	return (0);
29522ac3eadSMax Laier }
29622ac3eadSMax Laier 
29722ac3eadSMax Laier int
set_snaplen(int snap)29822ac3eadSMax Laier set_snaplen(int snap)
29922ac3eadSMax Laier {
30022ac3eadSMax Laier 	if (priv_set_snaplen(snap))
30122ac3eadSMax Laier 		return (1);
30222ac3eadSMax Laier 
30322ac3eadSMax Laier 	if (cur_snaplen > snap)
30422ac3eadSMax Laier 		purge_buffer();
30522ac3eadSMax Laier 
30622ac3eadSMax Laier 	cur_snaplen = snap;
30722ac3eadSMax Laier 
30813b9f610SMax Laier 	return (0);
30913b9f610SMax Laier }
31013b9f610SMax Laier 
31113b9f610SMax Laier int
reset_dump(int nomove)3125ee7cd21SMax Laier reset_dump(int nomove)
3135ee7cd21SMax Laier {
3145ee7cd21SMax Laier 	int ret;
3155ee7cd21SMax Laier 
3165ee7cd21SMax Laier 	for (;;) {
3175ee7cd21SMax Laier 		ret = try_reset_dump(nomove);
3185ee7cd21SMax Laier 		if (ret <= 0)
3195ee7cd21SMax Laier 			break;
3205ee7cd21SMax Laier 	}
3215ee7cd21SMax Laier 
3225ee7cd21SMax Laier 	return (ret);
3235ee7cd21SMax Laier }
3245ee7cd21SMax Laier 
3255ee7cd21SMax Laier /*
3265ee7cd21SMax Laier  * tries to (re)open log file, nomove flag is used with -x switch
3275ee7cd21SMax Laier  * returns 0: success, 1: retry (log moved), -1: error
3285ee7cd21SMax Laier  */
3295ee7cd21SMax Laier int
try_reset_dump(int nomove)3305ee7cd21SMax Laier try_reset_dump(int nomove)
33113b9f610SMax Laier {
33213b9f610SMax Laier 	struct pcap_file_header hdr;
33313b9f610SMax Laier 	struct stat st;
33422ac3eadSMax Laier 	int fd;
33513b9f610SMax Laier 	FILE *fp;
33613b9f610SMax Laier 
33713b9f610SMax Laier 	if (hpcap == NULL)
33822ac3eadSMax Laier 		return (-1);
33922ac3eadSMax Laier 
34013b9f610SMax Laier 	if (dpcap) {
34122ac3eadSMax Laier 		flush_buffer(dpcap);
34222ac3eadSMax Laier 		fclose(dpcap);
34322ac3eadSMax Laier 		dpcap = NULL;
34413b9f610SMax Laier 	}
34513b9f610SMax Laier 
34613b9f610SMax Laier 	/*
34713b9f610SMax Laier 	 * Basically reimplement pcap_dump_open() because it truncates
34813b9f610SMax Laier 	 * files and duplicates headers and such.
34913b9f610SMax Laier 	 */
35022ac3eadSMax Laier 	fd = priv_open_log();
35122ac3eadSMax Laier 	if (fd < 0)
3525ee7cd21SMax Laier 		return (-1);
35322ac3eadSMax Laier 
35422ac3eadSMax Laier 	fp = fdopen(fd, "a+");
35522ac3eadSMax Laier 
35613b9f610SMax Laier 	if (fp == NULL) {
35722ac3eadSMax Laier 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
3585ee7cd21SMax Laier 		close(fd);
3595ee7cd21SMax Laier 		return (-1);
36013b9f610SMax Laier 	}
36113b9f610SMax Laier 	if (fstat(fileno(fp), &st) == -1) {
36222ac3eadSMax Laier 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
3635ee7cd21SMax Laier 		fclose(fp);
3645ee7cd21SMax Laier 		return (-1);
36513b9f610SMax Laier 	}
36613b9f610SMax Laier 
36722ac3eadSMax Laier 	/* set FILE unbuffered, we do our own buffering */
36822ac3eadSMax Laier 	if (setvbuf(fp, NULL, _IONBF, 0)) {
36922ac3eadSMax Laier 		logmsg(LOG_ERR, "Failed to set output buffers");
3705ee7cd21SMax Laier 		fclose(fp);
3715ee7cd21SMax Laier 		return (-1);
37222ac3eadSMax Laier 	}
37313b9f610SMax Laier 
37413b9f610SMax Laier #define TCPDUMP_MAGIC 0xa1b2c3d4
37513b9f610SMax Laier 
37613b9f610SMax Laier 	if (st.st_size == 0) {
37722ac3eadSMax Laier 		if (snaplen != cur_snaplen) {
37813b9f610SMax Laier 			logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
3795ee7cd21SMax Laier 			if (set_snaplen(snaplen))
38022ac3eadSMax Laier 				logmsg(LOG_WARNING,
38122ac3eadSMax Laier 				    "Failed, using old settings");
38213b9f610SMax Laier 		}
38313b9f610SMax Laier 		hdr.magic = TCPDUMP_MAGIC;
38413b9f610SMax Laier 		hdr.version_major = PCAP_VERSION_MAJOR;
38513b9f610SMax Laier 		hdr.version_minor = PCAP_VERSION_MINOR;
3860c59e0b4SJoseph Mingrone 		hdr.thiszone = 0;
38713b9f610SMax Laier 		hdr.snaplen = hpcap->snapshot;
38813b9f610SMax Laier 		hdr.sigfigs = 0;
38913b9f610SMax Laier 		hdr.linktype = hpcap->linktype;
39013b9f610SMax Laier 
39113b9f610SMax Laier 		if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
39213b9f610SMax Laier 			fclose(fp);
3935ee7cd21SMax Laier 			return (-1);
39413b9f610SMax Laier 		}
39522ac3eadSMax Laier 	} else if (scan_dump(fp, st.st_size)) {
39622ac3eadSMax Laier 		fclose(fp);
3975ee7cd21SMax Laier 		if (nomove || priv_move_log()) {
3985ee7cd21SMax Laier 			logmsg(LOG_ERR,
3995ee7cd21SMax Laier 			    "Invalid/incompatible log file, move it away");
4005ee7cd21SMax Laier 			return (-1);
4015ee7cd21SMax Laier 		}
40222ac3eadSMax Laier 		return (1);
40313b9f610SMax Laier 	}
40422ac3eadSMax Laier 
40522ac3eadSMax Laier 	dpcap = fp;
40622ac3eadSMax Laier 
40722ac3eadSMax Laier 	set_suspended(0);
40822ac3eadSMax Laier 	flush_buffer(fp);
40922ac3eadSMax Laier 
41022ac3eadSMax Laier 	return (0);
41122ac3eadSMax Laier }
41222ac3eadSMax Laier 
41322ac3eadSMax Laier int
scan_dump(FILE * fp,off_t size)41422ac3eadSMax Laier scan_dump(FILE *fp, off_t size)
41522ac3eadSMax Laier {
41622ac3eadSMax Laier 	struct pcap_file_header hdr;
4176964e37dSMax Laier #ifdef __FreeBSD__
4186964e37dSMax Laier 	struct pcap_sf_pkthdr ph;
4196964e37dSMax Laier #else
42022ac3eadSMax Laier 	struct pcap_pkthdr ph;
4216964e37dSMax Laier #endif
42222ac3eadSMax Laier 	off_t pos;
42322ac3eadSMax Laier 
42422ac3eadSMax Laier 	/*
42522ac3eadSMax Laier 	 * Must read the file, compare the header against our new
42622ac3eadSMax Laier 	 * options (in particular, snaplen) and adjust our options so
42722ac3eadSMax Laier 	 * that we generate a correct file. Furthermore, check the file
42822ac3eadSMax Laier 	 * for consistency so that we can append safely.
42922ac3eadSMax Laier 	 *
43022ac3eadSMax Laier 	 * XXX this may take a long time for large logs.
43122ac3eadSMax Laier 	 */
43222ac3eadSMax Laier 	(void) fseek(fp, 0L, SEEK_SET);
43322ac3eadSMax Laier 
43422ac3eadSMax Laier 	if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
43522ac3eadSMax Laier 		logmsg(LOG_ERR, "Short file header");
43622ac3eadSMax Laier 		return (1);
43722ac3eadSMax Laier 	}
43822ac3eadSMax Laier 
43922ac3eadSMax Laier 	if (hdr.magic != TCPDUMP_MAGIC ||
44022ac3eadSMax Laier 	    hdr.version_major != PCAP_VERSION_MAJOR ||
44122ac3eadSMax Laier 	    hdr.version_minor != PCAP_VERSION_MINOR ||
44222ac3eadSMax Laier 	    hdr.linktype != hpcap->linktype ||
44322ac3eadSMax Laier 	    hdr.snaplen > PFLOGD_MAXSNAPLEN) {
44422ac3eadSMax Laier 		return (1);
44522ac3eadSMax Laier 	}
44622ac3eadSMax Laier 
44722ac3eadSMax Laier 	pos = sizeof(hdr);
44822ac3eadSMax Laier 
44922ac3eadSMax Laier 	while (!feof(fp)) {
45022ac3eadSMax Laier 		off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
45122ac3eadSMax Laier 		if (len == 0)
45222ac3eadSMax Laier 			break;
45322ac3eadSMax Laier 
45422ac3eadSMax Laier 		if (len != sizeof(ph))
45522ac3eadSMax Laier 			goto error;
45622ac3eadSMax Laier 		if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
45722ac3eadSMax Laier 			goto error;
45822ac3eadSMax Laier 		pos += sizeof(ph) + ph.caplen;
45922ac3eadSMax Laier 		if (pos > size)
46022ac3eadSMax Laier 			goto error;
46122ac3eadSMax Laier 		fseek(fp, ph.caplen, SEEK_CUR);
46222ac3eadSMax Laier 	}
46322ac3eadSMax Laier 
46422ac3eadSMax Laier 	if (pos != size)
46522ac3eadSMax Laier 		goto error;
46622ac3eadSMax Laier 
46722ac3eadSMax Laier 	if (hdr.snaplen != cur_snaplen) {
46822ac3eadSMax Laier 		logmsg(LOG_WARNING,
46922ac3eadSMax Laier 		       "Existing file has different snaplen %u, using it",
47022ac3eadSMax Laier 		       hdr.snaplen);
47122ac3eadSMax Laier 		if (set_snaplen(hdr.snaplen)) {
47222ac3eadSMax Laier 			logmsg(LOG_WARNING,
47322ac3eadSMax Laier 			       "Failed, using old settings, offset %llu",
47422ac3eadSMax Laier 			       (unsigned long long) size);
47513b9f610SMax Laier 		}
47613b9f610SMax Laier 	}
47713b9f610SMax Laier 
47813b9f610SMax Laier 	return (0);
47922ac3eadSMax Laier 
48022ac3eadSMax Laier  error:
48122ac3eadSMax Laier 	logmsg(LOG_ERR, "Corrupted log file.");
48222ac3eadSMax Laier 	return (1);
48322ac3eadSMax Laier }
48422ac3eadSMax Laier 
48522ac3eadSMax Laier /* dump a packet directly to the stream, which is unbuffered */
48622ac3eadSMax Laier void
dump_packet_nobuf(u_char * user,const struct pcap_pkthdr * h,const u_char * sp)48722ac3eadSMax Laier dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
48822ac3eadSMax Laier {
48922ac3eadSMax Laier 	FILE *f = (FILE *)user;
4906964e37dSMax Laier #ifdef __FreeBSD__
4916964e37dSMax Laier 	struct pcap_sf_pkthdr sh;
4926964e37dSMax Laier #endif
49322ac3eadSMax Laier 
49422ac3eadSMax Laier 	if (suspended) {
49522ac3eadSMax Laier 		packets_dropped++;
49622ac3eadSMax Laier 		return;
49722ac3eadSMax Laier 	}
49822ac3eadSMax Laier 
4996964e37dSMax Laier #ifdef __FreeBSD__
5006964e37dSMax Laier 	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
5016964e37dSMax Laier 	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
5026964e37dSMax Laier 	sh.caplen = h->caplen;
5036964e37dSMax Laier 	sh.len = h->len;
5046964e37dSMax Laier 
5056964e37dSMax Laier 	if (fwrite((char *)&sh, sizeof(sh), 1, f) != 1) {
5066964e37dSMax Laier #else
50722ac3eadSMax Laier 	if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
5086964e37dSMax Laier #endif
50922ac3eadSMax Laier 		off_t pos = ftello(f);
5100baf7c86SMax Laier 
5110baf7c86SMax Laier 		/* try to undo header to prevent corruption */
5126964e37dSMax Laier #ifdef __FreeBSD__
5136964e37dSMax Laier 		if (pos < sizeof(sh) ||
5146964e37dSMax Laier 		    ftruncate(fileno(f), pos - sizeof(sh))) {
5156964e37dSMax Laier #else
51622ac3eadSMax Laier 		if (pos < sizeof(*h) ||
51722ac3eadSMax Laier 		    ftruncate(fileno(f), pos - sizeof(*h))) {
5186964e37dSMax Laier #endif
51922ac3eadSMax Laier 			logmsg(LOG_ERR, "Write failed, corrupted logfile!");
52022ac3eadSMax Laier 			set_suspended(1);
52122ac3eadSMax Laier 			gotsig_close = 1;
52222ac3eadSMax Laier 			return;
52322ac3eadSMax Laier 		}
52422ac3eadSMax Laier 		goto error;
52522ac3eadSMax Laier 	}
52622ac3eadSMax Laier 
52722ac3eadSMax Laier 	if (fwrite((char *)sp, h->caplen, 1, f) != 1)
52822ac3eadSMax Laier 		goto error;
52922ac3eadSMax Laier 
53022ac3eadSMax Laier 	return;
53122ac3eadSMax Laier 
53222ac3eadSMax Laier error:
53322ac3eadSMax Laier 	set_suspended(1);
53422ac3eadSMax Laier 	packets_dropped ++;
53522ac3eadSMax Laier 	logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
53622ac3eadSMax Laier }
53722ac3eadSMax Laier 
53822ac3eadSMax Laier int
53922ac3eadSMax Laier flush_buffer(FILE *f)
54022ac3eadSMax Laier {
54122ac3eadSMax Laier 	off_t offset;
54222ac3eadSMax Laier 	int len = bufpos - buffer;
54322ac3eadSMax Laier 
54422ac3eadSMax Laier 	if (len <= 0)
54522ac3eadSMax Laier 		return (0);
54622ac3eadSMax Laier 
54722ac3eadSMax Laier 	offset = ftello(f);
54822ac3eadSMax Laier 	if (offset == (off_t)-1) {
54922ac3eadSMax Laier 		set_suspended(1);
55022ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: ftello: %s",
55122ac3eadSMax Laier 		    strerror(errno));
55222ac3eadSMax Laier 		return (1);
55322ac3eadSMax Laier 	}
55422ac3eadSMax Laier 
55522ac3eadSMax Laier 	if (fwrite(buffer, len, 1, f) != 1) {
55622ac3eadSMax Laier 		set_suspended(1);
55722ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
55822ac3eadSMax Laier 		    strerror(errno));
55922ac3eadSMax Laier 		ftruncate(fileno(f), offset);
56022ac3eadSMax Laier 		return (1);
56122ac3eadSMax Laier 	}
56222ac3eadSMax Laier 
56322ac3eadSMax Laier 	set_suspended(0);
56422ac3eadSMax Laier 	bufpos = buffer;
56522ac3eadSMax Laier 	bufleft = buflen;
56622ac3eadSMax Laier 	bufpkt = 0;
56722ac3eadSMax Laier 
56822ac3eadSMax Laier 	return (0);
56922ac3eadSMax Laier }
57022ac3eadSMax Laier 
57122ac3eadSMax Laier void
57222ac3eadSMax Laier purge_buffer(void)
57322ac3eadSMax Laier {
57422ac3eadSMax Laier 	packets_dropped += bufpkt;
57522ac3eadSMax Laier 
57622ac3eadSMax Laier 	set_suspended(0);
57722ac3eadSMax Laier 	bufpos = buffer;
57822ac3eadSMax Laier 	bufleft = buflen;
57922ac3eadSMax Laier 	bufpkt = 0;
58022ac3eadSMax Laier }
58122ac3eadSMax Laier 
58222ac3eadSMax Laier /* append packet to the buffer, flushing if necessary */
58322ac3eadSMax Laier void
58422ac3eadSMax Laier dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
58522ac3eadSMax Laier {
58622ac3eadSMax Laier 	FILE *f = (FILE *)user;
5876964e37dSMax Laier #ifdef __FreeBSD__
5886964e37dSMax Laier 	struct pcap_sf_pkthdr sh;
5896964e37dSMax Laier 	size_t len = sizeof(sh) + h->caplen;
5906964e37dSMax Laier #else
59122ac3eadSMax Laier 	size_t len = sizeof(*h) + h->caplen;
5926964e37dSMax Laier #endif
59322ac3eadSMax Laier 
59422ac3eadSMax Laier 	if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
59522ac3eadSMax Laier 		logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped",
59622ac3eadSMax Laier 		       len, cur_snaplen, snaplen);
59722ac3eadSMax Laier 		packets_dropped++;
59822ac3eadSMax Laier 		return;
59922ac3eadSMax Laier 	}
60022ac3eadSMax Laier 
60122ac3eadSMax Laier 	if (len <= bufleft)
60222ac3eadSMax Laier 		goto append;
60322ac3eadSMax Laier 
60422ac3eadSMax Laier 	if (suspended) {
60522ac3eadSMax Laier 		packets_dropped++;
60622ac3eadSMax Laier 		return;
60722ac3eadSMax Laier 	}
60822ac3eadSMax Laier 
60922ac3eadSMax Laier 	if (flush_buffer(f)) {
61022ac3eadSMax Laier 		packets_dropped++;
61122ac3eadSMax Laier 		return;
61222ac3eadSMax Laier 	}
61322ac3eadSMax Laier 
61422ac3eadSMax Laier 	if (len > bufleft) {
61522ac3eadSMax Laier 		dump_packet_nobuf(user, h, sp);
61622ac3eadSMax Laier 		return;
61722ac3eadSMax Laier 	}
61822ac3eadSMax Laier 
61922ac3eadSMax Laier  append:
6206964e37dSMax Laier #ifdef __FreeBSD__
6216964e37dSMax Laier 	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
6226964e37dSMax Laier 	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
6236964e37dSMax Laier 	sh.caplen = h->caplen;
6246964e37dSMax Laier 	sh.len = h->len;
6256964e37dSMax Laier 
6266964e37dSMax Laier 	memcpy(bufpos, &sh, sizeof(sh));
6276964e37dSMax Laier 	memcpy(bufpos + sizeof(sh), sp, h->caplen);
6286964e37dSMax Laier #else
62922ac3eadSMax Laier 	memcpy(bufpos, h, sizeof(*h));
63022ac3eadSMax Laier 	memcpy(bufpos + sizeof(*h), sp, h->caplen);
6316964e37dSMax Laier #endif
63222ac3eadSMax Laier 
63322ac3eadSMax Laier 	bufpos += len;
63422ac3eadSMax Laier 	bufleft -= len;
63522ac3eadSMax Laier 	bufpkt++;
63622ac3eadSMax Laier 
63722ac3eadSMax Laier 	return;
63813b9f610SMax Laier }
63913b9f610SMax Laier 
640e0bfbfceSBjoern A. Zeeb void
641e0bfbfceSBjoern A. Zeeb log_pcap_stats(void)
642e0bfbfceSBjoern A. Zeeb {
643e0bfbfceSBjoern A. Zeeb 	struct pcap_stat pstat;
644e0bfbfceSBjoern A. Zeeb 	if (pcap_stats(hpcap, &pstat) < 0)
645e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
646e0bfbfceSBjoern A. Zeeb 	else
647e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_NOTICE,
648e0bfbfceSBjoern A. Zeeb 			"%u packets received, %u/%u dropped (kernel/pflogd)",
649e0bfbfceSBjoern A. Zeeb 			pstat.ps_recv, pstat.ps_drop, packets_dropped);
650e0bfbfceSBjoern A. Zeeb }
651e0bfbfceSBjoern A. Zeeb 
65213b9f610SMax Laier int
65313b9f610SMax Laier main(int argc, char **argv)
65413b9f610SMax Laier {
655e0bfbfceSBjoern A. Zeeb 	int ch, np, ret, Xflag = 0;
65622ac3eadSMax Laier 	pcap_handler phandler = dump_packet;
6571a58af5eSMax Laier 	const char *errstr = NULL;
658e0bfbfceSBjoern A. Zeeb 	char *pidf = NULL;
659e0bfbfceSBjoern A. Zeeb 
660e0bfbfceSBjoern A. Zeeb 	ret = 0;
66113b9f610SMax Laier 
66222ac3eadSMax Laier 	closefrom(STDERR_FILENO + 1);
66322ac3eadSMax Laier 
664e0bfbfceSBjoern A. Zeeb 	while ((ch = getopt(argc, argv, "Dxd:f:i:p:s:")) != -1) {
66513b9f610SMax Laier 		switch (ch) {
66613b9f610SMax Laier 		case 'D':
66713b9f610SMax Laier 			Debug = 1;
66813b9f610SMax Laier 			break;
66913b9f610SMax Laier 		case 'd':
6700baf7c86SMax Laier 			delay = strtonum(optarg, 5, 60*60, &errstr);
6710baf7c86SMax Laier 			if (errstr)
67213b9f610SMax Laier 				usage();
67313b9f610SMax Laier 			break;
67413b9f610SMax Laier 		case 'f':
67513b9f610SMax Laier 			filename = optarg;
67613b9f610SMax Laier 			break;
6775ee7cd21SMax Laier 		case 'i':
6785ee7cd21SMax Laier 			interface = optarg;
6795ee7cd21SMax Laier 			break;
680e0bfbfceSBjoern A. Zeeb 		case 'p':
681e0bfbfceSBjoern A. Zeeb 			pidf = optarg;
682e0bfbfceSBjoern A. Zeeb 			break;
68313b9f610SMax Laier 		case 's':
6840baf7c86SMax Laier 			snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
6850baf7c86SMax Laier 			    &errstr);
68613b9f610SMax Laier 			if (snaplen <= 0)
68713b9f610SMax Laier 				snaplen = DEF_SNAPLEN;
6880baf7c86SMax Laier 			if (errstr)
68922ac3eadSMax Laier 				snaplen = PFLOGD_MAXSNAPLEN;
69022ac3eadSMax Laier 			break;
69122ac3eadSMax Laier 		case 'x':
69222ac3eadSMax Laier 			Xflag++;
69313b9f610SMax Laier 			break;
69413b9f610SMax Laier 		default:
69513b9f610SMax Laier 			usage();
69613b9f610SMax Laier 		}
69713b9f610SMax Laier 
69813b9f610SMax Laier 	}
69913b9f610SMax Laier 
70013b9f610SMax Laier 	log_debug = Debug;
70113b9f610SMax Laier 	argc -= optind;
70213b9f610SMax Laier 	argv += optind;
70313b9f610SMax Laier 
704e0bfbfceSBjoern A. Zeeb 	/* does interface exist */
705e0bfbfceSBjoern A. Zeeb 	if (!if_exists(interface)) {
706e0bfbfceSBjoern A. Zeeb 		warn("Failed to initialize: %s", interface);
707e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_ERR, "Failed to initialize: %s", interface);
708e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_ERR, "Exiting, init failure");
709e0bfbfceSBjoern A. Zeeb 		exit(1);
710e0bfbfceSBjoern A. Zeeb 	}
711e0bfbfceSBjoern A. Zeeb 
71213b9f610SMax Laier 	if (!Debug) {
71313b9f610SMax Laier 		openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
71413b9f610SMax Laier 		if (daemon(0, 0)) {
71513b9f610SMax Laier 			logmsg(LOG_WARNING, "Failed to become daemon: %s",
71613b9f610SMax Laier 			    strerror(errno));
71713b9f610SMax Laier 		}
718e0bfbfceSBjoern A. Zeeb 		pidfile(pidf);
71913b9f610SMax Laier 	}
72013b9f610SMax Laier 
7210baf7c86SMax Laier 	tzset();
72213b9f610SMax Laier 	(void)umask(S_IRWXG | S_IRWXO);
72313b9f610SMax Laier 
72422ac3eadSMax Laier 	/* filter will be used by the privileged process */
72522ac3eadSMax Laier 	if (argc) {
72622ac3eadSMax Laier 		filter = copy_argv(argv);
72722ac3eadSMax Laier 		if (filter == NULL)
72822ac3eadSMax Laier 			logmsg(LOG_NOTICE, "Failed to form filter expression");
72922ac3eadSMax Laier 	}
73022ac3eadSMax Laier 
73122ac3eadSMax Laier 	/* initialize pcap before dropping privileges */
73222ac3eadSMax Laier 	if (init_pcap()) {
73322ac3eadSMax Laier 		logmsg(LOG_ERR, "Exiting, init failure");
73422ac3eadSMax Laier 		exit(1);
73522ac3eadSMax Laier 	}
73622ac3eadSMax Laier 
73722ac3eadSMax Laier 	/* Privilege separation begins here */
73822ac3eadSMax Laier 	if (priv_init()) {
73922ac3eadSMax Laier 		logmsg(LOG_ERR, "unable to privsep");
74022ac3eadSMax Laier 		exit(1);
74122ac3eadSMax Laier 	}
74222ac3eadSMax Laier 
74322ac3eadSMax Laier 	setproctitle("[initializing]");
74422ac3eadSMax Laier 	/* Process is now unprivileged and inside a chroot */
74513b9f610SMax Laier 	signal(SIGTERM, sig_close);
74613b9f610SMax Laier 	signal(SIGINT, sig_close);
74713b9f610SMax Laier 	signal(SIGQUIT, sig_close);
74813b9f610SMax Laier 	signal(SIGALRM, sig_alrm);
749e0bfbfceSBjoern A. Zeeb 	signal(SIGUSR1, sig_usr1);
75013b9f610SMax Laier 	signal(SIGHUP, sig_hup);
75113b9f610SMax Laier 	alarm(delay);
75213b9f610SMax Laier 
75322ac3eadSMax Laier 	buffer = malloc(PFLOGD_BUFSIZE);
75413b9f610SMax Laier 
75522ac3eadSMax Laier 	if (buffer == NULL) {
75622ac3eadSMax Laier 		logmsg(LOG_WARNING, "Failed to allocate output buffer");
75722ac3eadSMax Laier 		phandler = dump_packet_nobuf;
75822ac3eadSMax Laier 	} else {
75922ac3eadSMax Laier 		bufleft = buflen = PFLOGD_BUFSIZE;
76022ac3eadSMax Laier 		bufpos = buffer;
76122ac3eadSMax Laier 		bufpkt = 0;
76213b9f610SMax Laier 	}
76313b9f610SMax Laier 
7645ee7cd21SMax Laier 	if (reset_dump(Xflag) < 0) {
76522ac3eadSMax Laier 		if (Xflag)
76622ac3eadSMax Laier 			return (1);
76722ac3eadSMax Laier 
76822ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: open error");
76922ac3eadSMax Laier 		set_suspended(1);
77022ac3eadSMax Laier 	} else if (Xflag)
77122ac3eadSMax Laier 		return (0);
77213b9f610SMax Laier 
77313b9f610SMax Laier 	while (1) {
77422ac3eadSMax Laier 		np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
7750baf7c86SMax Laier 		    phandler, (u_char *)dpcap);
77622d6889bSMax Laier 		if (np < 0) {
777f7862a87SDimitry Andric 			if (!if_exists(interface)) {
778e0bfbfceSBjoern A. Zeeb 				logmsg(LOG_NOTICE, "interface %s went away",
779e0bfbfceSBjoern A. Zeeb 				    interface);
780e0bfbfceSBjoern A. Zeeb 				ret = -1;
78122d6889bSMax Laier 				break;
78222d6889bSMax Laier 			}
78313b9f610SMax Laier 			logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
78422d6889bSMax Laier 		}
78513b9f610SMax Laier 
78613b9f610SMax Laier 		if (gotsig_close)
78713b9f610SMax Laier 			break;
78813b9f610SMax Laier 		if (gotsig_hup) {
7895ee7cd21SMax Laier 			if (reset_dump(0)) {
79022ac3eadSMax Laier 				logmsg(LOG_ERR,
79122ac3eadSMax Laier 				    "Logging suspended: open error");
79222ac3eadSMax Laier 				set_suspended(1);
79313b9f610SMax Laier 			}
79413b9f610SMax Laier 			gotsig_hup = 0;
79513b9f610SMax Laier 		}
79613b9f610SMax Laier 
79713b9f610SMax Laier 		if (gotsig_alrm) {
79822ac3eadSMax Laier 			if (dpcap)
79922ac3eadSMax Laier 				flush_buffer(dpcap);
8005ee7cd21SMax Laier 			else
8015ee7cd21SMax Laier 				gotsig_hup = 1;
80213b9f610SMax Laier 			gotsig_alrm = 0;
80313b9f610SMax Laier 			alarm(delay);
80413b9f610SMax Laier 		}
805e0bfbfceSBjoern A. Zeeb 
806e0bfbfceSBjoern A. Zeeb 		if (gotsig_usr1) {
807e0bfbfceSBjoern A. Zeeb 			log_pcap_stats();
808e0bfbfceSBjoern A. Zeeb 			gotsig_usr1 = 0;
809e0bfbfceSBjoern A. Zeeb 		}
81013b9f610SMax Laier 	}
81113b9f610SMax Laier 
81222ac3eadSMax Laier 	logmsg(LOG_NOTICE, "Exiting");
81322ac3eadSMax Laier 	if (dpcap) {
81422ac3eadSMax Laier 		flush_buffer(dpcap);
81522ac3eadSMax Laier 		fclose(dpcap);
81622ac3eadSMax Laier 	}
81722ac3eadSMax Laier 	purge_buffer();
81813b9f610SMax Laier 
819e0bfbfceSBjoern A. Zeeb 	log_pcap_stats();
82013b9f610SMax Laier 	pcap_close(hpcap);
82113b9f610SMax Laier 	if (!Debug)
82213b9f610SMax Laier 		closelog();
823e0bfbfceSBjoern A. Zeeb 	return (ret);
82413b9f610SMax Laier }
825