xref: /freebsd/contrib/pf/pflogd/pflogd.c (revision bbde5c07)
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 
7722ac3eadSMax Laier char *copy_argv(char * const *);
7822ac3eadSMax Laier void  dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
7922ac3eadSMax Laier void  dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
80e0bfbfceSBjoern A. Zeeb void  log_pcap_stats(void);
8122ac3eadSMax Laier int   flush_buffer(FILE *);
82e0bfbfceSBjoern A. Zeeb int   if_exists(char *);
8313b9f610SMax Laier int   init_pcap(void);
8422ac3eadSMax Laier void  logmsg(int, const char *, ...);
8522ac3eadSMax Laier void  purge_buffer(void);
865ee7cd21SMax Laier int   reset_dump(int);
8722ac3eadSMax Laier int   scan_dump(FILE *, off_t);
8822ac3eadSMax Laier int   set_snaplen(int);
8922ac3eadSMax Laier void  set_suspended(int);
9013b9f610SMax Laier void  sig_alrm(int);
91e0bfbfceSBjoern A. Zeeb void  sig_usr1(int);
9213b9f610SMax Laier void  sig_close(int);
9313b9f610SMax Laier void  sig_hup(int);
9413b9f610SMax Laier void  usage(void);
9513b9f610SMax Laier 
965ee7cd21SMax Laier static int try_reset_dump(int);
975ee7cd21SMax Laier 
9822ac3eadSMax Laier /* buffer must always be greater than snaplen */
9922ac3eadSMax Laier static int    bufpkt = 0;	/* number of packets in buffer */
10022ac3eadSMax Laier static int    buflen = 0;	/* allocated size of buffer */
10122ac3eadSMax Laier static char  *buffer = NULL;	/* packet buffer */
10222ac3eadSMax Laier static char  *bufpos = NULL;	/* position in buffer */
10322ac3eadSMax Laier static int    bufleft = 0;	/* bytes left in buffer */
10422ac3eadSMax Laier 
10522ac3eadSMax Laier /* if error, stop logging but count dropped packets */
10622ac3eadSMax Laier static int suspended = -1;
10722ac3eadSMax Laier static long packets_dropped = 0;
10822ac3eadSMax Laier 
10922ac3eadSMax Laier void
set_suspended(int s)11022ac3eadSMax Laier set_suspended(int s)
11122ac3eadSMax Laier {
11222ac3eadSMax Laier 	if (suspended == s)
11322ac3eadSMax Laier 		return;
11422ac3eadSMax Laier 
11522ac3eadSMax Laier 	suspended = s;
1165ee7cd21SMax Laier 	setproctitle("[%s] -s %d -i %s -f %s",
1175ee7cd21SMax Laier 	    suspended ? "suspended" : "running",
1185ee7cd21SMax Laier 	    cur_snaplen, interface, filename);
11922ac3eadSMax Laier }
12013b9f610SMax Laier 
12113b9f610SMax Laier char *
copy_argv(char * const * argv)12213b9f610SMax Laier copy_argv(char * const *argv)
12313b9f610SMax Laier {
12413b9f610SMax Laier 	size_t len = 0, n;
12513b9f610SMax Laier 	char *buf;
12613b9f610SMax Laier 
12713b9f610SMax Laier 	if (argv == NULL)
12813b9f610SMax Laier 		return (NULL);
12913b9f610SMax Laier 
13013b9f610SMax Laier 	for (n = 0; argv[n]; n++)
13113b9f610SMax Laier 		len += strlen(argv[n])+1;
13213b9f610SMax Laier 	if (len == 0)
13313b9f610SMax Laier 		return (NULL);
13413b9f610SMax Laier 
13513b9f610SMax Laier 	buf = malloc(len);
13613b9f610SMax Laier 	if (buf == NULL)
13713b9f610SMax Laier 		return (NULL);
13813b9f610SMax Laier 
13913b9f610SMax Laier 	strlcpy(buf, argv[0], len);
14013b9f610SMax Laier 	for (n = 1; argv[n]; n++) {
14113b9f610SMax Laier 		strlcat(buf, " ", len);
14213b9f610SMax Laier 		strlcat(buf, argv[n], len);
14313b9f610SMax Laier 	}
14413b9f610SMax Laier 	return (buf);
14513b9f610SMax Laier }
14613b9f610SMax Laier 
14713b9f610SMax Laier void
logmsg(int pri,const char * message,...)14813b9f610SMax Laier logmsg(int pri, const char *message, ...)
14913b9f610SMax Laier {
15013b9f610SMax Laier 	va_list ap;
15113b9f610SMax Laier 	va_start(ap, message);
15213b9f610SMax Laier 
15313b9f610SMax Laier 	if (log_debug) {
15413b9f610SMax Laier 		vfprintf(stderr, message, ap);
15513b9f610SMax Laier 		fprintf(stderr, "\n");
15613b9f610SMax Laier 	} else
15713b9f610SMax Laier 		vsyslog(pri, message, ap);
15813b9f610SMax Laier 	va_end(ap);
15913b9f610SMax Laier }
16013b9f610SMax Laier 
161b83a49e9SMax Laier #ifdef __FreeBSD__
162b83a49e9SMax Laier __dead2 void
163b83a49e9SMax Laier #else
16413b9f610SMax Laier __dead void
165b83a49e9SMax Laier #endif
usage(void)16613b9f610SMax Laier usage(void)
16713b9f610SMax Laier {
16822ac3eadSMax Laier 	fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
169e0bfbfceSBjoern A. Zeeb 	fprintf(stderr, " [-i interface] [-p pidfile]\n");
170e0bfbfceSBjoern A. Zeeb 	fprintf(stderr, "              [-s snaplen] [expression]\n");
17113b9f610SMax Laier 	exit(1);
17213b9f610SMax Laier }
17313b9f610SMax Laier 
17413b9f610SMax Laier void
sig_close(int sig)17513b9f610SMax Laier sig_close(int sig)
17613b9f610SMax Laier {
17713b9f610SMax Laier 	gotsig_close = 1;
17813b9f610SMax Laier }
17913b9f610SMax Laier 
18013b9f610SMax Laier void
sig_hup(int sig)18113b9f610SMax Laier sig_hup(int sig)
18213b9f610SMax Laier {
18313b9f610SMax Laier 	gotsig_hup = 1;
18413b9f610SMax Laier }
18513b9f610SMax Laier 
18613b9f610SMax Laier void
sig_alrm(int sig)18713b9f610SMax Laier sig_alrm(int sig)
18813b9f610SMax Laier {
18913b9f610SMax Laier 	gotsig_alrm = 1;
19013b9f610SMax Laier }
19113b9f610SMax Laier 
19222ac3eadSMax Laier void
sig_usr1(int sig)193e0bfbfceSBjoern A. Zeeb sig_usr1(int sig)
194e0bfbfceSBjoern A. Zeeb {
195e0bfbfceSBjoern A. Zeeb 	gotsig_usr1 = 1;
196e0bfbfceSBjoern A. Zeeb }
197e0bfbfceSBjoern A. Zeeb 
198e0bfbfceSBjoern A. Zeeb void
set_pcap_filter(void)19922ac3eadSMax Laier set_pcap_filter(void)
20013b9f610SMax Laier {
20113b9f610SMax Laier 	struct bpf_program bprog;
20213b9f610SMax Laier 
20313b9f610SMax Laier 	if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
20413b9f610SMax Laier 		logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
20522ac3eadSMax Laier 	else {
20622ac3eadSMax Laier 		if (pcap_setfilter(hpcap, &bprog) < 0)
20713b9f610SMax Laier 			logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
20822ac3eadSMax Laier 		pcap_freecode(&bprog);
20922ac3eadSMax Laier 	}
21022ac3eadSMax Laier }
21122ac3eadSMax Laier 
21222ac3eadSMax Laier int
if_exists(char * ifname)213e0bfbfceSBjoern A. Zeeb if_exists(char *ifname)
214e0bfbfceSBjoern A. Zeeb {
215e0bfbfceSBjoern A. Zeeb #ifdef __FreeBSD__
216e0bfbfceSBjoern A. Zeeb 	struct ifaddrs *ifdata, *mb;
217e0bfbfceSBjoern A. Zeeb 	int exists = 0;
218e0bfbfceSBjoern A. Zeeb 
219e0bfbfceSBjoern A. Zeeb 	getifaddrs(&ifdata);
220e0bfbfceSBjoern A. Zeeb         if (ifdata == NULL)
221e0bfbfceSBjoern A. Zeeb 		return (0);
222e0bfbfceSBjoern A. Zeeb 
223e0bfbfceSBjoern A. Zeeb 	for (mb = ifdata; mb != NULL; mb = mb->ifa_next) {
224e0bfbfceSBjoern A. Zeeb 		if (mb == NULL)
225e0bfbfceSBjoern A. Zeeb 			continue;
226e0bfbfceSBjoern A. Zeeb 		if (strlen(ifname) != strlen(mb->ifa_name))
227e0bfbfceSBjoern A. Zeeb 			continue;
228e0bfbfceSBjoern A. Zeeb 		if (strncmp(ifname, mb->ifa_name, strlen(ifname)) != 0)
229e0bfbfceSBjoern A. Zeeb 			continue;
230e0bfbfceSBjoern A. Zeeb 		exists = 1;
231e0bfbfceSBjoern A. Zeeb 		break;
232e0bfbfceSBjoern A. Zeeb 	}
233e0bfbfceSBjoern A. Zeeb 	freeifaddrs(ifdata);
234e0bfbfceSBjoern A. Zeeb 
235e0bfbfceSBjoern A. Zeeb 	return (exists);
236e0bfbfceSBjoern A. Zeeb #else
237e0bfbfceSBjoern A. Zeeb 	int s;
238e0bfbfceSBjoern A. Zeeb 	struct ifreq ifr;
239e0bfbfceSBjoern A. Zeeb 	struct if_data ifrdat;
240e0bfbfceSBjoern A. Zeeb 
241e0bfbfceSBjoern A. Zeeb 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
242e0bfbfceSBjoern A. Zeeb 		err(1, "socket");
243e0bfbfceSBjoern A. Zeeb 	bzero(&ifr, sizeof(ifr));
244e0bfbfceSBjoern A. Zeeb 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
245e0bfbfceSBjoern A. Zeeb 		sizeof(ifr.ifr_name))
246e0bfbfceSBjoern A. Zeeb 			errx(1, "main ifr_name: strlcpy");
247e0bfbfceSBjoern A. Zeeb 	ifr.ifr_data = (caddr_t)&ifrdat;
248e0bfbfceSBjoern A. Zeeb 	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
249e0bfbfceSBjoern A. Zeeb 		return (0);
250e0bfbfceSBjoern A. Zeeb 	if (close(s))
251e0bfbfceSBjoern A. Zeeb 		err(1, "close");
252e0bfbfceSBjoern A. Zeeb 
253e0bfbfceSBjoern A. Zeeb 	return (1);
254e0bfbfceSBjoern A. Zeeb #endif
255e0bfbfceSBjoern A. Zeeb }
256e0bfbfceSBjoern A. Zeeb 
257e0bfbfceSBjoern A. Zeeb int
init_pcap(void)25822ac3eadSMax Laier init_pcap(void)
25922ac3eadSMax Laier {
26022ac3eadSMax Laier 	hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
26122ac3eadSMax Laier 	if (hpcap == NULL) {
26222ac3eadSMax Laier 		logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
26322ac3eadSMax Laier 		return (-1);
26422ac3eadSMax Laier 	}
26513b9f610SMax Laier 
26613b9f610SMax Laier 	if (pcap_datalink(hpcap) != DLT_PFLOG) {
26713b9f610SMax Laier 		logmsg(LOG_ERR, "Invalid datalink type");
26813b9f610SMax Laier 		pcap_close(hpcap);
26922ac3eadSMax Laier 		hpcap = NULL;
27013b9f610SMax Laier 		return (-1);
27113b9f610SMax Laier 	}
27213b9f610SMax Laier 
27322ac3eadSMax Laier 	set_pcap_filter();
27413b9f610SMax Laier 
27522ac3eadSMax Laier 	cur_snaplen = snaplen = pcap_snapshot(hpcap);
27622ac3eadSMax Laier 
27722ac3eadSMax Laier 	/* lock */
27822ac3eadSMax Laier 	if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
27922ac3eadSMax Laier 		logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
28022ac3eadSMax Laier 		return (-1);
28122ac3eadSMax Laier 	}
28222ac3eadSMax Laier 
28322ac3eadSMax Laier 	return (0);
28422ac3eadSMax Laier }
28522ac3eadSMax Laier 
28622ac3eadSMax Laier int
set_snaplen(int snap)28722ac3eadSMax Laier set_snaplen(int snap)
28822ac3eadSMax Laier {
28922ac3eadSMax Laier 	if (priv_set_snaplen(snap))
29022ac3eadSMax Laier 		return (1);
29122ac3eadSMax Laier 
29222ac3eadSMax Laier 	if (cur_snaplen > snap)
29322ac3eadSMax Laier 		purge_buffer();
29422ac3eadSMax Laier 
29522ac3eadSMax Laier 	cur_snaplen = snap;
29622ac3eadSMax Laier 
29713b9f610SMax Laier 	return (0);
29813b9f610SMax Laier }
29913b9f610SMax Laier 
30013b9f610SMax Laier int
reset_dump(int nomove)3015ee7cd21SMax Laier reset_dump(int nomove)
3025ee7cd21SMax Laier {
3035ee7cd21SMax Laier 	int ret;
3045ee7cd21SMax Laier 
3055ee7cd21SMax Laier 	for (;;) {
3065ee7cd21SMax Laier 		ret = try_reset_dump(nomove);
3075ee7cd21SMax Laier 		if (ret <= 0)
3085ee7cd21SMax Laier 			break;
3095ee7cd21SMax Laier 	}
3105ee7cd21SMax Laier 
3115ee7cd21SMax Laier 	return (ret);
3125ee7cd21SMax Laier }
3135ee7cd21SMax Laier 
3145ee7cd21SMax Laier /*
3155ee7cd21SMax Laier  * tries to (re)open log file, nomove flag is used with -x switch
3165ee7cd21SMax Laier  * returns 0: success, 1: retry (log moved), -1: error
3175ee7cd21SMax Laier  */
3185ee7cd21SMax Laier int
try_reset_dump(int nomove)3195ee7cd21SMax Laier try_reset_dump(int nomove)
32013b9f610SMax Laier {
32113b9f610SMax Laier 	struct pcap_file_header hdr;
32213b9f610SMax Laier 	struct stat st;
32322ac3eadSMax Laier 	int fd;
32413b9f610SMax Laier 	FILE *fp;
32513b9f610SMax Laier 
32613b9f610SMax Laier 	if (hpcap == NULL)
32722ac3eadSMax Laier 		return (-1);
32822ac3eadSMax Laier 
32913b9f610SMax Laier 	if (dpcap) {
33022ac3eadSMax Laier 		flush_buffer(dpcap);
33122ac3eadSMax Laier 		fclose(dpcap);
33222ac3eadSMax Laier 		dpcap = NULL;
33313b9f610SMax Laier 	}
33413b9f610SMax Laier 
33513b9f610SMax Laier 	/*
33613b9f610SMax Laier 	 * Basically reimplement pcap_dump_open() because it truncates
33713b9f610SMax Laier 	 * files and duplicates headers and such.
33813b9f610SMax Laier 	 */
33922ac3eadSMax Laier 	fd = priv_open_log();
34022ac3eadSMax Laier 	if (fd < 0)
3415ee7cd21SMax Laier 		return (-1);
34222ac3eadSMax Laier 
34322ac3eadSMax Laier 	fp = fdopen(fd, "a+");
34422ac3eadSMax Laier 
34513b9f610SMax Laier 	if (fp == NULL) {
34622ac3eadSMax Laier 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
3475ee7cd21SMax Laier 		close(fd);
3485ee7cd21SMax Laier 		return (-1);
34913b9f610SMax Laier 	}
35013b9f610SMax Laier 	if (fstat(fileno(fp), &st) == -1) {
35122ac3eadSMax Laier 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
3525ee7cd21SMax Laier 		fclose(fp);
3535ee7cd21SMax Laier 		return (-1);
35413b9f610SMax Laier 	}
35513b9f610SMax Laier 
35622ac3eadSMax Laier 	/* set FILE unbuffered, we do our own buffering */
35722ac3eadSMax Laier 	if (setvbuf(fp, NULL, _IONBF, 0)) {
35822ac3eadSMax Laier 		logmsg(LOG_ERR, "Failed to set output buffers");
3595ee7cd21SMax Laier 		fclose(fp);
3605ee7cd21SMax Laier 		return (-1);
36122ac3eadSMax Laier 	}
36213b9f610SMax Laier 
36313b9f610SMax Laier #define TCPDUMP_MAGIC 0xa1b2c3d4
36413b9f610SMax Laier 
36513b9f610SMax Laier 	if (st.st_size == 0) {
36622ac3eadSMax Laier 		if (snaplen != cur_snaplen) {
36713b9f610SMax Laier 			logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
3685ee7cd21SMax Laier 			if (set_snaplen(snaplen))
36922ac3eadSMax Laier 				logmsg(LOG_WARNING,
37022ac3eadSMax Laier 				    "Failed, using old settings");
37113b9f610SMax Laier 		}
37213b9f610SMax Laier 		hdr.magic = TCPDUMP_MAGIC;
37313b9f610SMax Laier 		hdr.version_major = PCAP_VERSION_MAJOR;
37413b9f610SMax Laier 		hdr.version_minor = PCAP_VERSION_MINOR;
3750c59e0b4SJoseph Mingrone 		hdr.thiszone = 0;
37613b9f610SMax Laier 		hdr.snaplen = hpcap->snapshot;
37713b9f610SMax Laier 		hdr.sigfigs = 0;
37813b9f610SMax Laier 		hdr.linktype = hpcap->linktype;
37913b9f610SMax Laier 
38013b9f610SMax Laier 		if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
38113b9f610SMax Laier 			fclose(fp);
3825ee7cd21SMax Laier 			return (-1);
38313b9f610SMax Laier 		}
38422ac3eadSMax Laier 	} else if (scan_dump(fp, st.st_size)) {
38522ac3eadSMax Laier 		fclose(fp);
3865ee7cd21SMax Laier 		if (nomove || priv_move_log()) {
3875ee7cd21SMax Laier 			logmsg(LOG_ERR,
3885ee7cd21SMax Laier 			    "Invalid/incompatible log file, move it away");
3895ee7cd21SMax Laier 			return (-1);
3905ee7cd21SMax Laier 		}
39122ac3eadSMax Laier 		return (1);
39213b9f610SMax Laier 	}
39322ac3eadSMax Laier 
39422ac3eadSMax Laier 	dpcap = fp;
39522ac3eadSMax Laier 
39622ac3eadSMax Laier 	set_suspended(0);
39722ac3eadSMax Laier 	flush_buffer(fp);
39822ac3eadSMax Laier 
39922ac3eadSMax Laier 	return (0);
40022ac3eadSMax Laier }
40122ac3eadSMax Laier 
40222ac3eadSMax Laier int
scan_dump(FILE * fp,off_t size)40322ac3eadSMax Laier scan_dump(FILE *fp, off_t size)
40422ac3eadSMax Laier {
40522ac3eadSMax Laier 	struct pcap_file_header hdr;
4066964e37dSMax Laier #ifdef __FreeBSD__
4076964e37dSMax Laier 	struct pcap_sf_pkthdr ph;
4086964e37dSMax Laier #else
40922ac3eadSMax Laier 	struct pcap_pkthdr ph;
4106964e37dSMax Laier #endif
41122ac3eadSMax Laier 	off_t pos;
41222ac3eadSMax Laier 
41322ac3eadSMax Laier 	/*
41422ac3eadSMax Laier 	 * Must read the file, compare the header against our new
41522ac3eadSMax Laier 	 * options (in particular, snaplen) and adjust our options so
41622ac3eadSMax Laier 	 * that we generate a correct file. Furthermore, check the file
41722ac3eadSMax Laier 	 * for consistency so that we can append safely.
41822ac3eadSMax Laier 	 *
41922ac3eadSMax Laier 	 * XXX this may take a long time for large logs.
42022ac3eadSMax Laier 	 */
42122ac3eadSMax Laier 	(void) fseek(fp, 0L, SEEK_SET);
42222ac3eadSMax Laier 
42322ac3eadSMax Laier 	if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
42422ac3eadSMax Laier 		logmsg(LOG_ERR, "Short file header");
42522ac3eadSMax Laier 		return (1);
42622ac3eadSMax Laier 	}
42722ac3eadSMax Laier 
42822ac3eadSMax Laier 	if (hdr.magic != TCPDUMP_MAGIC ||
42922ac3eadSMax Laier 	    hdr.version_major != PCAP_VERSION_MAJOR ||
43022ac3eadSMax Laier 	    hdr.version_minor != PCAP_VERSION_MINOR ||
43122ac3eadSMax Laier 	    hdr.linktype != hpcap->linktype ||
43222ac3eadSMax Laier 	    hdr.snaplen > PFLOGD_MAXSNAPLEN) {
43322ac3eadSMax Laier 		return (1);
43422ac3eadSMax Laier 	}
43522ac3eadSMax Laier 
43622ac3eadSMax Laier 	pos = sizeof(hdr);
43722ac3eadSMax Laier 
43822ac3eadSMax Laier 	while (!feof(fp)) {
43922ac3eadSMax Laier 		off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
44022ac3eadSMax Laier 		if (len == 0)
44122ac3eadSMax Laier 			break;
44222ac3eadSMax Laier 
44322ac3eadSMax Laier 		if (len != sizeof(ph))
44422ac3eadSMax Laier 			goto error;
44522ac3eadSMax Laier 		if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
44622ac3eadSMax Laier 			goto error;
44722ac3eadSMax Laier 		pos += sizeof(ph) + ph.caplen;
44822ac3eadSMax Laier 		if (pos > size)
44922ac3eadSMax Laier 			goto error;
45022ac3eadSMax Laier 		fseek(fp, ph.caplen, SEEK_CUR);
45122ac3eadSMax Laier 	}
45222ac3eadSMax Laier 
45322ac3eadSMax Laier 	if (pos != size)
45422ac3eadSMax Laier 		goto error;
45522ac3eadSMax Laier 
45622ac3eadSMax Laier 	if (hdr.snaplen != cur_snaplen) {
45722ac3eadSMax Laier 		logmsg(LOG_WARNING,
45822ac3eadSMax Laier 		       "Existing file has different snaplen %u, using it",
45922ac3eadSMax Laier 		       hdr.snaplen);
46022ac3eadSMax Laier 		if (set_snaplen(hdr.snaplen)) {
46122ac3eadSMax Laier 			logmsg(LOG_WARNING,
46222ac3eadSMax Laier 			       "Failed, using old settings, offset %llu",
46322ac3eadSMax Laier 			       (unsigned long long) size);
46413b9f610SMax Laier 		}
46513b9f610SMax Laier 	}
46613b9f610SMax Laier 
46713b9f610SMax Laier 	return (0);
46822ac3eadSMax Laier 
46922ac3eadSMax Laier  error:
47022ac3eadSMax Laier 	logmsg(LOG_ERR, "Corrupted log file.");
47122ac3eadSMax Laier 	return (1);
47222ac3eadSMax Laier }
47322ac3eadSMax Laier 
47422ac3eadSMax Laier /* dump a packet directly to the stream, which is unbuffered */
47522ac3eadSMax Laier void
dump_packet_nobuf(u_char * user,const struct pcap_pkthdr * h,const u_char * sp)47622ac3eadSMax Laier dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
47722ac3eadSMax Laier {
47822ac3eadSMax Laier 	FILE *f = (FILE *)user;
4796964e37dSMax Laier #ifdef __FreeBSD__
4806964e37dSMax Laier 	struct pcap_sf_pkthdr sh;
4816964e37dSMax Laier #endif
48222ac3eadSMax Laier 
48322ac3eadSMax Laier 	if (suspended) {
48422ac3eadSMax Laier 		packets_dropped++;
48522ac3eadSMax Laier 		return;
48622ac3eadSMax Laier 	}
48722ac3eadSMax Laier 
4886964e37dSMax Laier #ifdef __FreeBSD__
4896964e37dSMax Laier 	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
4906964e37dSMax Laier 	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
4916964e37dSMax Laier 	sh.caplen = h->caplen;
4926964e37dSMax Laier 	sh.len = h->len;
4936964e37dSMax Laier 
4946964e37dSMax Laier 	if (fwrite((char *)&sh, sizeof(sh), 1, f) != 1) {
4956964e37dSMax Laier #else
49622ac3eadSMax Laier 	if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
4976964e37dSMax Laier #endif
49822ac3eadSMax Laier 		off_t pos = ftello(f);
4990baf7c86SMax Laier 
5000baf7c86SMax Laier 		/* try to undo header to prevent corruption */
5016964e37dSMax Laier #ifdef __FreeBSD__
5026964e37dSMax Laier 		if (pos < sizeof(sh) ||
5036964e37dSMax Laier 		    ftruncate(fileno(f), pos - sizeof(sh))) {
5046964e37dSMax Laier #else
50522ac3eadSMax Laier 		if (pos < sizeof(*h) ||
50622ac3eadSMax Laier 		    ftruncate(fileno(f), pos - sizeof(*h))) {
5076964e37dSMax Laier #endif
50822ac3eadSMax Laier 			logmsg(LOG_ERR, "Write failed, corrupted logfile!");
50922ac3eadSMax Laier 			set_suspended(1);
51022ac3eadSMax Laier 			gotsig_close = 1;
51122ac3eadSMax Laier 			return;
51222ac3eadSMax Laier 		}
51322ac3eadSMax Laier 		goto error;
51422ac3eadSMax Laier 	}
51522ac3eadSMax Laier 
51622ac3eadSMax Laier 	if (fwrite((char *)sp, h->caplen, 1, f) != 1)
51722ac3eadSMax Laier 		goto error;
51822ac3eadSMax Laier 
51922ac3eadSMax Laier 	return;
52022ac3eadSMax Laier 
52122ac3eadSMax Laier error:
52222ac3eadSMax Laier 	set_suspended(1);
52322ac3eadSMax Laier 	packets_dropped ++;
52422ac3eadSMax Laier 	logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
52522ac3eadSMax Laier }
52622ac3eadSMax Laier 
52722ac3eadSMax Laier int
52822ac3eadSMax Laier flush_buffer(FILE *f)
52922ac3eadSMax Laier {
53022ac3eadSMax Laier 	off_t offset;
53122ac3eadSMax Laier 	int len = bufpos - buffer;
53222ac3eadSMax Laier 
53322ac3eadSMax Laier 	if (len <= 0)
53422ac3eadSMax Laier 		return (0);
53522ac3eadSMax Laier 
53622ac3eadSMax Laier 	offset = ftello(f);
53722ac3eadSMax Laier 	if (offset == (off_t)-1) {
53822ac3eadSMax Laier 		set_suspended(1);
53922ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: ftello: %s",
54022ac3eadSMax Laier 		    strerror(errno));
54122ac3eadSMax Laier 		return (1);
54222ac3eadSMax Laier 	}
54322ac3eadSMax Laier 
54422ac3eadSMax Laier 	if (fwrite(buffer, len, 1, f) != 1) {
54522ac3eadSMax Laier 		set_suspended(1);
54622ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
54722ac3eadSMax Laier 		    strerror(errno));
54822ac3eadSMax Laier 		ftruncate(fileno(f), offset);
54922ac3eadSMax Laier 		return (1);
55022ac3eadSMax Laier 	}
55122ac3eadSMax Laier 
55222ac3eadSMax Laier 	set_suspended(0);
55322ac3eadSMax Laier 	bufpos = buffer;
55422ac3eadSMax Laier 	bufleft = buflen;
55522ac3eadSMax Laier 	bufpkt = 0;
55622ac3eadSMax Laier 
55722ac3eadSMax Laier 	return (0);
55822ac3eadSMax Laier }
55922ac3eadSMax Laier 
56022ac3eadSMax Laier void
56122ac3eadSMax Laier purge_buffer(void)
56222ac3eadSMax Laier {
56322ac3eadSMax Laier 	packets_dropped += bufpkt;
56422ac3eadSMax Laier 
56522ac3eadSMax Laier 	set_suspended(0);
56622ac3eadSMax Laier 	bufpos = buffer;
56722ac3eadSMax Laier 	bufleft = buflen;
56822ac3eadSMax Laier 	bufpkt = 0;
56922ac3eadSMax Laier }
57022ac3eadSMax Laier 
57122ac3eadSMax Laier /* append packet to the buffer, flushing if necessary */
57222ac3eadSMax Laier void
57322ac3eadSMax Laier dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
57422ac3eadSMax Laier {
57522ac3eadSMax Laier 	FILE *f = (FILE *)user;
5766964e37dSMax Laier #ifdef __FreeBSD__
5776964e37dSMax Laier 	struct pcap_sf_pkthdr sh;
5786964e37dSMax Laier 	size_t len = sizeof(sh) + h->caplen;
5796964e37dSMax Laier #else
58022ac3eadSMax Laier 	size_t len = sizeof(*h) + h->caplen;
5816964e37dSMax Laier #endif
58222ac3eadSMax Laier 
58322ac3eadSMax Laier 	if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
58422ac3eadSMax Laier 		logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped",
58522ac3eadSMax Laier 		       len, cur_snaplen, snaplen);
58622ac3eadSMax Laier 		packets_dropped++;
58722ac3eadSMax Laier 		return;
58822ac3eadSMax Laier 	}
58922ac3eadSMax Laier 
59022ac3eadSMax Laier 	if (len <= bufleft)
59122ac3eadSMax Laier 		goto append;
59222ac3eadSMax Laier 
59322ac3eadSMax Laier 	if (suspended) {
59422ac3eadSMax Laier 		packets_dropped++;
59522ac3eadSMax Laier 		return;
59622ac3eadSMax Laier 	}
59722ac3eadSMax Laier 
59822ac3eadSMax Laier 	if (flush_buffer(f)) {
59922ac3eadSMax Laier 		packets_dropped++;
60022ac3eadSMax Laier 		return;
60122ac3eadSMax Laier 	}
60222ac3eadSMax Laier 
60322ac3eadSMax Laier 	if (len > bufleft) {
60422ac3eadSMax Laier 		dump_packet_nobuf(user, h, sp);
60522ac3eadSMax Laier 		return;
60622ac3eadSMax Laier 	}
60722ac3eadSMax Laier 
60822ac3eadSMax Laier  append:
6096964e37dSMax Laier #ifdef __FreeBSD__
6106964e37dSMax Laier 	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
6116964e37dSMax Laier 	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
6126964e37dSMax Laier 	sh.caplen = h->caplen;
6136964e37dSMax Laier 	sh.len = h->len;
6146964e37dSMax Laier 
6156964e37dSMax Laier 	memcpy(bufpos, &sh, sizeof(sh));
6166964e37dSMax Laier 	memcpy(bufpos + sizeof(sh), sp, h->caplen);
6176964e37dSMax Laier #else
61822ac3eadSMax Laier 	memcpy(bufpos, h, sizeof(*h));
61922ac3eadSMax Laier 	memcpy(bufpos + sizeof(*h), sp, h->caplen);
6206964e37dSMax Laier #endif
62122ac3eadSMax Laier 
62222ac3eadSMax Laier 	bufpos += len;
62322ac3eadSMax Laier 	bufleft -= len;
62422ac3eadSMax Laier 	bufpkt++;
62522ac3eadSMax Laier 
62622ac3eadSMax Laier 	return;
62713b9f610SMax Laier }
62813b9f610SMax Laier 
629e0bfbfceSBjoern A. Zeeb void
630e0bfbfceSBjoern A. Zeeb log_pcap_stats(void)
631e0bfbfceSBjoern A. Zeeb {
632e0bfbfceSBjoern A. Zeeb 	struct pcap_stat pstat;
633e0bfbfceSBjoern A. Zeeb 	if (pcap_stats(hpcap, &pstat) < 0)
634e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
635e0bfbfceSBjoern A. Zeeb 	else
636e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_NOTICE,
637e0bfbfceSBjoern A. Zeeb 			"%u packets received, %u/%u dropped (kernel/pflogd)",
638e0bfbfceSBjoern A. Zeeb 			pstat.ps_recv, pstat.ps_drop, packets_dropped);
639e0bfbfceSBjoern A. Zeeb }
640e0bfbfceSBjoern A. Zeeb 
64113b9f610SMax Laier int
64213b9f610SMax Laier main(int argc, char **argv)
64313b9f610SMax Laier {
644e0bfbfceSBjoern A. Zeeb 	int ch, np, ret, Xflag = 0;
64522ac3eadSMax Laier 	pcap_handler phandler = dump_packet;
6461a58af5eSMax Laier 	const char *errstr = NULL;
647e0bfbfceSBjoern A. Zeeb 	char *pidf = NULL;
648e0bfbfceSBjoern A. Zeeb 
649e0bfbfceSBjoern A. Zeeb 	ret = 0;
65013b9f610SMax Laier 
65122ac3eadSMax Laier 	closefrom(STDERR_FILENO + 1);
65222ac3eadSMax Laier 
653e0bfbfceSBjoern A. Zeeb 	while ((ch = getopt(argc, argv, "Dxd:f:i:p:s:")) != -1) {
65413b9f610SMax Laier 		switch (ch) {
65513b9f610SMax Laier 		case 'D':
65613b9f610SMax Laier 			Debug = 1;
65713b9f610SMax Laier 			break;
65813b9f610SMax Laier 		case 'd':
6590baf7c86SMax Laier 			delay = strtonum(optarg, 5, 60*60, &errstr);
6600baf7c86SMax Laier 			if (errstr)
66113b9f610SMax Laier 				usage();
66213b9f610SMax Laier 			break;
66313b9f610SMax Laier 		case 'f':
66413b9f610SMax Laier 			filename = optarg;
66513b9f610SMax Laier 			break;
6665ee7cd21SMax Laier 		case 'i':
6675ee7cd21SMax Laier 			interface = optarg;
6685ee7cd21SMax Laier 			break;
669e0bfbfceSBjoern A. Zeeb 		case 'p':
670e0bfbfceSBjoern A. Zeeb 			pidf = optarg;
671e0bfbfceSBjoern A. Zeeb 			break;
67213b9f610SMax Laier 		case 's':
6730baf7c86SMax Laier 			snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
6740baf7c86SMax Laier 			    &errstr);
67513b9f610SMax Laier 			if (snaplen <= 0)
67613b9f610SMax Laier 				snaplen = DEF_SNAPLEN;
6770baf7c86SMax Laier 			if (errstr)
67822ac3eadSMax Laier 				snaplen = PFLOGD_MAXSNAPLEN;
67922ac3eadSMax Laier 			break;
68022ac3eadSMax Laier 		case 'x':
68122ac3eadSMax Laier 			Xflag++;
68213b9f610SMax Laier 			break;
68313b9f610SMax Laier 		default:
68413b9f610SMax Laier 			usage();
68513b9f610SMax Laier 		}
68613b9f610SMax Laier 
68713b9f610SMax Laier 	}
68813b9f610SMax Laier 
68913b9f610SMax Laier 	log_debug = Debug;
69013b9f610SMax Laier 	argc -= optind;
69113b9f610SMax Laier 	argv += optind;
69213b9f610SMax Laier 
693e0bfbfceSBjoern A. Zeeb 	/* does interface exist */
694e0bfbfceSBjoern A. Zeeb 	if (!if_exists(interface)) {
695e0bfbfceSBjoern A. Zeeb 		warn("Failed to initialize: %s", interface);
696e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_ERR, "Failed to initialize: %s", interface);
697e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_ERR, "Exiting, init failure");
698e0bfbfceSBjoern A. Zeeb 		exit(1);
699e0bfbfceSBjoern A. Zeeb 	}
700e0bfbfceSBjoern A. Zeeb 
70113b9f610SMax Laier 	if (!Debug) {
70213b9f610SMax Laier 		openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
70313b9f610SMax Laier 		if (daemon(0, 0)) {
70413b9f610SMax Laier 			logmsg(LOG_WARNING, "Failed to become daemon: %s",
70513b9f610SMax Laier 			    strerror(errno));
70613b9f610SMax Laier 		}
707e0bfbfceSBjoern A. Zeeb 		pidfile(pidf);
70813b9f610SMax Laier 	}
70913b9f610SMax Laier 
7100baf7c86SMax Laier 	tzset();
71113b9f610SMax Laier 	(void)umask(S_IRWXG | S_IRWXO);
71213b9f610SMax Laier 
71322ac3eadSMax Laier 	/* filter will be used by the privileged process */
71422ac3eadSMax Laier 	if (argc) {
71522ac3eadSMax Laier 		filter = copy_argv(argv);
71622ac3eadSMax Laier 		if (filter == NULL)
71722ac3eadSMax Laier 			logmsg(LOG_NOTICE, "Failed to form filter expression");
71822ac3eadSMax Laier 	}
71922ac3eadSMax Laier 
72022ac3eadSMax Laier 	/* initialize pcap before dropping privileges */
72122ac3eadSMax Laier 	if (init_pcap()) {
72222ac3eadSMax Laier 		logmsg(LOG_ERR, "Exiting, init failure");
72322ac3eadSMax Laier 		exit(1);
72422ac3eadSMax Laier 	}
72522ac3eadSMax Laier 
72622ac3eadSMax Laier 	/* Privilege separation begins here */
72722ac3eadSMax Laier 	if (priv_init()) {
72822ac3eadSMax Laier 		logmsg(LOG_ERR, "unable to privsep");
72922ac3eadSMax Laier 		exit(1);
73022ac3eadSMax Laier 	}
73122ac3eadSMax Laier 
73222ac3eadSMax Laier 	setproctitle("[initializing]");
73322ac3eadSMax Laier 	/* Process is now unprivileged and inside a chroot */
73413b9f610SMax Laier 	signal(SIGTERM, sig_close);
73513b9f610SMax Laier 	signal(SIGINT, sig_close);
73613b9f610SMax Laier 	signal(SIGQUIT, sig_close);
73713b9f610SMax Laier 	signal(SIGALRM, sig_alrm);
738e0bfbfceSBjoern A. Zeeb 	signal(SIGUSR1, sig_usr1);
73913b9f610SMax Laier 	signal(SIGHUP, sig_hup);
74013b9f610SMax Laier 	alarm(delay);
74113b9f610SMax Laier 
74222ac3eadSMax Laier 	buffer = malloc(PFLOGD_BUFSIZE);
74313b9f610SMax Laier 
74422ac3eadSMax Laier 	if (buffer == NULL) {
74522ac3eadSMax Laier 		logmsg(LOG_WARNING, "Failed to allocate output buffer");
74622ac3eadSMax Laier 		phandler = dump_packet_nobuf;
74722ac3eadSMax Laier 	} else {
74822ac3eadSMax Laier 		bufleft = buflen = PFLOGD_BUFSIZE;
74922ac3eadSMax Laier 		bufpos = buffer;
75022ac3eadSMax Laier 		bufpkt = 0;
75113b9f610SMax Laier 	}
75213b9f610SMax Laier 
7535ee7cd21SMax Laier 	if (reset_dump(Xflag) < 0) {
75422ac3eadSMax Laier 		if (Xflag)
75522ac3eadSMax Laier 			return (1);
75622ac3eadSMax Laier 
75722ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: open error");
75822ac3eadSMax Laier 		set_suspended(1);
75922ac3eadSMax Laier 	} else if (Xflag)
76022ac3eadSMax Laier 		return (0);
76113b9f610SMax Laier 
76213b9f610SMax Laier 	while (1) {
76322ac3eadSMax Laier 		np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
7640baf7c86SMax Laier 		    phandler, (u_char *)dpcap);
76522d6889bSMax Laier 		if (np < 0) {
766f7862a87SDimitry Andric 			if (!if_exists(interface)) {
767e0bfbfceSBjoern A. Zeeb 				logmsg(LOG_NOTICE, "interface %s went away",
768e0bfbfceSBjoern A. Zeeb 				    interface);
769e0bfbfceSBjoern A. Zeeb 				ret = -1;
77022d6889bSMax Laier 				break;
77122d6889bSMax Laier 			}
77213b9f610SMax Laier 			logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
77322d6889bSMax Laier 		}
77413b9f610SMax Laier 
77513b9f610SMax Laier 		if (gotsig_close)
77613b9f610SMax Laier 			break;
77713b9f610SMax Laier 		if (gotsig_hup) {
7785ee7cd21SMax Laier 			if (reset_dump(0)) {
77922ac3eadSMax Laier 				logmsg(LOG_ERR,
78022ac3eadSMax Laier 				    "Logging suspended: open error");
78122ac3eadSMax Laier 				set_suspended(1);
78213b9f610SMax Laier 			}
78313b9f610SMax Laier 			gotsig_hup = 0;
78413b9f610SMax Laier 		}
78513b9f610SMax Laier 
78613b9f610SMax Laier 		if (gotsig_alrm) {
78722ac3eadSMax Laier 			if (dpcap)
78822ac3eadSMax Laier 				flush_buffer(dpcap);
7895ee7cd21SMax Laier 			else
7905ee7cd21SMax Laier 				gotsig_hup = 1;
79113b9f610SMax Laier 			gotsig_alrm = 0;
79213b9f610SMax Laier 			alarm(delay);
79313b9f610SMax Laier 		}
794e0bfbfceSBjoern A. Zeeb 
795e0bfbfceSBjoern A. Zeeb 		if (gotsig_usr1) {
796e0bfbfceSBjoern A. Zeeb 			log_pcap_stats();
797e0bfbfceSBjoern A. Zeeb 			gotsig_usr1 = 0;
798e0bfbfceSBjoern A. Zeeb 		}
79913b9f610SMax Laier 	}
80013b9f610SMax Laier 
80122ac3eadSMax Laier 	logmsg(LOG_NOTICE, "Exiting");
80222ac3eadSMax Laier 	if (dpcap) {
80322ac3eadSMax Laier 		flush_buffer(dpcap);
80422ac3eadSMax Laier 		fclose(dpcap);
80522ac3eadSMax Laier 	}
80622ac3eadSMax Laier 	purge_buffer();
80713b9f610SMax Laier 
808e0bfbfceSBjoern A. Zeeb 	log_pcap_stats();
80913b9f610SMax Laier 	pcap_close(hpcap);
81013b9f610SMax Laier 	if (!Debug)
81113b9f610SMax Laier 		closelog();
812e0bfbfceSBjoern A. Zeeb 	return (ret);
81313b9f610SMax Laier }
814