xref: /freebsd/contrib/pf/pflogd/pflogd.c (revision f7862a87)
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 
33a10f530fSDavid E. O'Brien #include <sys/cdefs.h>
34a10f530fSDavid E. O'Brien __FBSDID("$FreeBSD$");
35a10f530fSDavid E. O'Brien 
3613b9f610SMax Laier #include <sys/types.h>
3722ac3eadSMax Laier #include <sys/ioctl.h>
3813b9f610SMax Laier #include <sys/file.h>
3913b9f610SMax Laier #include <sys/stat.h>
40e0bfbfceSBjoern A. Zeeb #include <sys/socket.h>
41e0bfbfceSBjoern A. Zeeb #include <net/if.h>
4213b9f610SMax Laier #include <stdio.h>
4313b9f610SMax Laier #include <stdlib.h>
4413b9f610SMax Laier #include <string.h>
4513b9f610SMax Laier #include <unistd.h>
4613b9f610SMax Laier #include <pcap-int.h>
4713b9f610SMax Laier #include <pcap.h>
4813b9f610SMax Laier #include <syslog.h>
4913b9f610SMax Laier #include <signal.h>
50e0bfbfceSBjoern A. Zeeb #include <err.h>
5113b9f610SMax Laier #include <errno.h>
5213b9f610SMax Laier #include <stdarg.h>
5313b9f610SMax Laier #include <fcntl.h>
54b83a49e9SMax Laier #ifdef __FreeBSD__
55e0bfbfceSBjoern A. Zeeb #include <ifaddrs.h>
568c8618f5SMax Laier #include "pidfile.h"
578c8618f5SMax Laier #else
5813b9f610SMax Laier #include <util.h>
598c8618f5SMax Laier #endif
6022ac3eadSMax Laier #include "pflogd.h"
6113b9f610SMax Laier 
6213b9f610SMax Laier pcap_t *hpcap;
6322ac3eadSMax Laier static FILE *dpcap;
6413b9f610SMax Laier 
6513b9f610SMax Laier int Debug = 0;
6622ac3eadSMax Laier static int snaplen = DEF_SNAPLEN;
6722ac3eadSMax Laier static int cur_snaplen = DEF_SNAPLEN;
6813b9f610SMax Laier 
69e0bfbfceSBjoern A. Zeeb volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup, gotsig_usr1;
7013b9f610SMax Laier 
7113b9f610SMax Laier char *filename = PFLOGD_LOG_FILE;
7213b9f610SMax Laier char *interface = PFLOGD_DEFAULT_IF;
7313b9f610SMax Laier char *filter = NULL;
7413b9f610SMax Laier 
7513b9f610SMax Laier char errbuf[PCAP_ERRBUF_SIZE];
7613b9f610SMax Laier 
7713b9f610SMax Laier int log_debug = 0;
7813b9f610SMax Laier unsigned int delay = FLUSH_DELAY;
7913b9f610SMax Laier 
8022ac3eadSMax Laier char *copy_argv(char * const *);
8122ac3eadSMax Laier void  dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
8222ac3eadSMax Laier void  dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
83e0bfbfceSBjoern A. Zeeb void  log_pcap_stats(void);
8422ac3eadSMax Laier int   flush_buffer(FILE *);
85e0bfbfceSBjoern A. Zeeb int   if_exists(char *);
8613b9f610SMax Laier int   init_pcap(void);
8722ac3eadSMax Laier void  logmsg(int, const char *, ...);
8822ac3eadSMax Laier void  purge_buffer(void);
895ee7cd21SMax Laier int   reset_dump(int);
9022ac3eadSMax Laier int   scan_dump(FILE *, off_t);
9122ac3eadSMax Laier int   set_snaplen(int);
9222ac3eadSMax Laier void  set_suspended(int);
9313b9f610SMax Laier void  sig_alrm(int);
94e0bfbfceSBjoern A. Zeeb void  sig_usr1(int);
9513b9f610SMax Laier void  sig_close(int);
9613b9f610SMax Laier void  sig_hup(int);
9713b9f610SMax Laier void  usage(void);
9813b9f610SMax Laier 
995ee7cd21SMax Laier static int try_reset_dump(int);
1005ee7cd21SMax Laier 
10122ac3eadSMax Laier /* buffer must always be greater than snaplen */
10222ac3eadSMax Laier static int    bufpkt = 0;	/* number of packets in buffer */
10322ac3eadSMax Laier static int    buflen = 0;	/* allocated size of buffer */
10422ac3eadSMax Laier static char  *buffer = NULL;	/* packet buffer */
10522ac3eadSMax Laier static char  *bufpos = NULL;	/* position in buffer */
10622ac3eadSMax Laier static int    bufleft = 0;	/* bytes left in buffer */
10722ac3eadSMax Laier 
10822ac3eadSMax Laier /* if error, stop logging but count dropped packets */
10922ac3eadSMax Laier static int suspended = -1;
11022ac3eadSMax Laier static long packets_dropped = 0;
11122ac3eadSMax Laier 
11222ac3eadSMax Laier void
11322ac3eadSMax Laier set_suspended(int s)
11422ac3eadSMax Laier {
11522ac3eadSMax Laier 	if (suspended == s)
11622ac3eadSMax Laier 		return;
11722ac3eadSMax Laier 
11822ac3eadSMax Laier 	suspended = s;
1195ee7cd21SMax Laier 	setproctitle("[%s] -s %d -i %s -f %s",
1205ee7cd21SMax Laier 	    suspended ? "suspended" : "running",
1215ee7cd21SMax Laier 	    cur_snaplen, interface, filename);
12222ac3eadSMax Laier }
12313b9f610SMax Laier 
12413b9f610SMax Laier char *
12513b9f610SMax Laier copy_argv(char * const *argv)
12613b9f610SMax Laier {
12713b9f610SMax Laier 	size_t len = 0, n;
12813b9f610SMax Laier 	char *buf;
12913b9f610SMax Laier 
13013b9f610SMax Laier 	if (argv == NULL)
13113b9f610SMax Laier 		return (NULL);
13213b9f610SMax Laier 
13313b9f610SMax Laier 	for (n = 0; argv[n]; n++)
13413b9f610SMax Laier 		len += strlen(argv[n])+1;
13513b9f610SMax Laier 	if (len == 0)
13613b9f610SMax Laier 		return (NULL);
13713b9f610SMax Laier 
13813b9f610SMax Laier 	buf = malloc(len);
13913b9f610SMax Laier 	if (buf == NULL)
14013b9f610SMax Laier 		return (NULL);
14113b9f610SMax Laier 
14213b9f610SMax Laier 	strlcpy(buf, argv[0], len);
14313b9f610SMax Laier 	for (n = 1; argv[n]; n++) {
14413b9f610SMax Laier 		strlcat(buf, " ", len);
14513b9f610SMax Laier 		strlcat(buf, argv[n], len);
14613b9f610SMax Laier 	}
14713b9f610SMax Laier 	return (buf);
14813b9f610SMax Laier }
14913b9f610SMax Laier 
15013b9f610SMax Laier void
15113b9f610SMax Laier logmsg(int pri, const char *message, ...)
15213b9f610SMax Laier {
15313b9f610SMax Laier 	va_list ap;
15413b9f610SMax Laier 	va_start(ap, message);
15513b9f610SMax Laier 
15613b9f610SMax Laier 	if (log_debug) {
15713b9f610SMax Laier 		vfprintf(stderr, message, ap);
15813b9f610SMax Laier 		fprintf(stderr, "\n");
15913b9f610SMax Laier 	} else
16013b9f610SMax Laier 		vsyslog(pri, message, ap);
16113b9f610SMax Laier 	va_end(ap);
16213b9f610SMax Laier }
16313b9f610SMax Laier 
164b83a49e9SMax Laier #ifdef __FreeBSD__
165b83a49e9SMax Laier __dead2 void
166b83a49e9SMax Laier #else
16713b9f610SMax Laier __dead void
168b83a49e9SMax Laier #endif
16913b9f610SMax Laier usage(void)
17013b9f610SMax Laier {
17122ac3eadSMax Laier 	fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
172e0bfbfceSBjoern A. Zeeb 	fprintf(stderr, " [-i interface] [-p pidfile]\n");
173e0bfbfceSBjoern A. Zeeb 	fprintf(stderr, "              [-s snaplen] [expression]\n");
17413b9f610SMax Laier 	exit(1);
17513b9f610SMax Laier }
17613b9f610SMax Laier 
17713b9f610SMax Laier void
17813b9f610SMax Laier sig_close(int sig)
17913b9f610SMax Laier {
18013b9f610SMax Laier 	gotsig_close = 1;
18113b9f610SMax Laier }
18213b9f610SMax Laier 
18313b9f610SMax Laier void
18413b9f610SMax Laier sig_hup(int sig)
18513b9f610SMax Laier {
18613b9f610SMax Laier 	gotsig_hup = 1;
18713b9f610SMax Laier }
18813b9f610SMax Laier 
18913b9f610SMax Laier void
19013b9f610SMax Laier sig_alrm(int sig)
19113b9f610SMax Laier {
19213b9f610SMax Laier 	gotsig_alrm = 1;
19313b9f610SMax Laier }
19413b9f610SMax Laier 
19522ac3eadSMax Laier void
196e0bfbfceSBjoern A. Zeeb sig_usr1(int sig)
197e0bfbfceSBjoern A. Zeeb {
198e0bfbfceSBjoern A. Zeeb 	gotsig_usr1 = 1;
199e0bfbfceSBjoern A. Zeeb }
200e0bfbfceSBjoern A. Zeeb 
201e0bfbfceSBjoern A. Zeeb void
20222ac3eadSMax Laier set_pcap_filter(void)
20313b9f610SMax Laier {
20413b9f610SMax Laier 	struct bpf_program bprog;
20513b9f610SMax Laier 
20613b9f610SMax Laier 	if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
20713b9f610SMax Laier 		logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
20822ac3eadSMax Laier 	else {
20922ac3eadSMax Laier 		if (pcap_setfilter(hpcap, &bprog) < 0)
21013b9f610SMax Laier 			logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
21122ac3eadSMax Laier 		pcap_freecode(&bprog);
21222ac3eadSMax Laier 	}
21322ac3eadSMax Laier }
21422ac3eadSMax Laier 
21522ac3eadSMax Laier int
216e0bfbfceSBjoern A. Zeeb if_exists(char *ifname)
217e0bfbfceSBjoern A. Zeeb {
218e0bfbfceSBjoern A. Zeeb #ifdef __FreeBSD__
219e0bfbfceSBjoern A. Zeeb 	struct ifaddrs *ifdata, *mb;
220e0bfbfceSBjoern A. Zeeb 	int exists = 0;
221e0bfbfceSBjoern A. Zeeb 
222e0bfbfceSBjoern A. Zeeb 	getifaddrs(&ifdata);
223e0bfbfceSBjoern A. Zeeb         if (ifdata == NULL)
224e0bfbfceSBjoern A. Zeeb 		return (0);
225e0bfbfceSBjoern A. Zeeb 
226e0bfbfceSBjoern A. Zeeb 	for (mb = ifdata; mb != NULL; mb = mb->ifa_next) {
227e0bfbfceSBjoern A. Zeeb 		if (mb == NULL)
228e0bfbfceSBjoern A. Zeeb 			continue;
229e0bfbfceSBjoern A. Zeeb 		if (strlen(ifname) != strlen(mb->ifa_name))
230e0bfbfceSBjoern A. Zeeb 			continue;
231e0bfbfceSBjoern A. Zeeb 		if (strncmp(ifname, mb->ifa_name, strlen(ifname)) != 0)
232e0bfbfceSBjoern A. Zeeb 			continue;
233e0bfbfceSBjoern A. Zeeb 		exists = 1;
234e0bfbfceSBjoern A. Zeeb 		break;
235e0bfbfceSBjoern A. Zeeb 	}
236e0bfbfceSBjoern A. Zeeb 	freeifaddrs(ifdata);
237e0bfbfceSBjoern A. Zeeb 
238e0bfbfceSBjoern A. Zeeb 	return (exists);
239e0bfbfceSBjoern A. Zeeb #else
240e0bfbfceSBjoern A. Zeeb 	int s;
241e0bfbfceSBjoern A. Zeeb 	struct ifreq ifr;
242e0bfbfceSBjoern A. Zeeb 	struct if_data ifrdat;
243e0bfbfceSBjoern A. Zeeb 
244e0bfbfceSBjoern A. Zeeb 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
245e0bfbfceSBjoern A. Zeeb 		err(1, "socket");
246e0bfbfceSBjoern A. Zeeb 	bzero(&ifr, sizeof(ifr));
247e0bfbfceSBjoern A. Zeeb 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
248e0bfbfceSBjoern A. Zeeb 		sizeof(ifr.ifr_name))
249e0bfbfceSBjoern A. Zeeb 			errx(1, "main ifr_name: strlcpy");
250e0bfbfceSBjoern A. Zeeb 	ifr.ifr_data = (caddr_t)&ifrdat;
251e0bfbfceSBjoern A. Zeeb 	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
252e0bfbfceSBjoern A. Zeeb 		return (0);
253e0bfbfceSBjoern A. Zeeb 	if (close(s))
254e0bfbfceSBjoern A. Zeeb 		err(1, "close");
255e0bfbfceSBjoern A. Zeeb 
256e0bfbfceSBjoern A. Zeeb 	return (1);
257e0bfbfceSBjoern A. Zeeb #endif
258e0bfbfceSBjoern A. Zeeb }
259e0bfbfceSBjoern A. Zeeb 
260e0bfbfceSBjoern A. Zeeb int
26122ac3eadSMax Laier init_pcap(void)
26222ac3eadSMax Laier {
26322ac3eadSMax Laier 	hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
26422ac3eadSMax Laier 	if (hpcap == NULL) {
26522ac3eadSMax Laier 		logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
26622ac3eadSMax Laier 		return (-1);
26722ac3eadSMax Laier 	}
26813b9f610SMax Laier 
26913b9f610SMax Laier 	if (pcap_datalink(hpcap) != DLT_PFLOG) {
27013b9f610SMax Laier 		logmsg(LOG_ERR, "Invalid datalink type");
27113b9f610SMax Laier 		pcap_close(hpcap);
27222ac3eadSMax Laier 		hpcap = NULL;
27313b9f610SMax Laier 		return (-1);
27413b9f610SMax Laier 	}
27513b9f610SMax Laier 
27622ac3eadSMax Laier 	set_pcap_filter();
27713b9f610SMax Laier 
27822ac3eadSMax Laier 	cur_snaplen = snaplen = pcap_snapshot(hpcap);
27922ac3eadSMax Laier 
28022ac3eadSMax Laier 	/* lock */
28122ac3eadSMax Laier 	if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
28222ac3eadSMax Laier 		logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
28322ac3eadSMax Laier 		return (-1);
28422ac3eadSMax Laier 	}
28522ac3eadSMax Laier 
28622ac3eadSMax Laier 	return (0);
28722ac3eadSMax Laier }
28822ac3eadSMax Laier 
28922ac3eadSMax Laier int
29022ac3eadSMax Laier set_snaplen(int snap)
29122ac3eadSMax Laier {
29222ac3eadSMax Laier 	if (priv_set_snaplen(snap))
29322ac3eadSMax Laier 		return (1);
29422ac3eadSMax Laier 
29522ac3eadSMax Laier 	if (cur_snaplen > snap)
29622ac3eadSMax Laier 		purge_buffer();
29722ac3eadSMax Laier 
29822ac3eadSMax Laier 	cur_snaplen = snap;
29922ac3eadSMax Laier 
30013b9f610SMax Laier 	return (0);
30113b9f610SMax Laier }
30213b9f610SMax Laier 
30313b9f610SMax Laier int
3045ee7cd21SMax Laier reset_dump(int nomove)
3055ee7cd21SMax Laier {
3065ee7cd21SMax Laier 	int ret;
3075ee7cd21SMax Laier 
3085ee7cd21SMax Laier 	for (;;) {
3095ee7cd21SMax Laier 		ret = try_reset_dump(nomove);
3105ee7cd21SMax Laier 		if (ret <= 0)
3115ee7cd21SMax Laier 			break;
3125ee7cd21SMax Laier 	}
3135ee7cd21SMax Laier 
3145ee7cd21SMax Laier 	return (ret);
3155ee7cd21SMax Laier }
3165ee7cd21SMax Laier 
3175ee7cd21SMax Laier /*
3185ee7cd21SMax Laier  * tries to (re)open log file, nomove flag is used with -x switch
3195ee7cd21SMax Laier  * returns 0: success, 1: retry (log moved), -1: error
3205ee7cd21SMax Laier  */
3215ee7cd21SMax Laier int
3225ee7cd21SMax Laier try_reset_dump(int nomove)
32313b9f610SMax Laier {
32413b9f610SMax Laier 	struct pcap_file_header hdr;
32513b9f610SMax Laier 	struct stat st;
32622ac3eadSMax Laier 	int fd;
32713b9f610SMax Laier 	FILE *fp;
32813b9f610SMax Laier 
32913b9f610SMax Laier 	if (hpcap == NULL)
33022ac3eadSMax Laier 		return (-1);
33122ac3eadSMax Laier 
33213b9f610SMax Laier 	if (dpcap) {
33322ac3eadSMax Laier 		flush_buffer(dpcap);
33422ac3eadSMax Laier 		fclose(dpcap);
33522ac3eadSMax Laier 		dpcap = NULL;
33613b9f610SMax Laier 	}
33713b9f610SMax Laier 
33813b9f610SMax Laier 	/*
33913b9f610SMax Laier 	 * Basically reimplement pcap_dump_open() because it truncates
34013b9f610SMax Laier 	 * files and duplicates headers and such.
34113b9f610SMax Laier 	 */
34222ac3eadSMax Laier 	fd = priv_open_log();
34322ac3eadSMax Laier 	if (fd < 0)
3445ee7cd21SMax Laier 		return (-1);
34522ac3eadSMax Laier 
34622ac3eadSMax Laier 	fp = fdopen(fd, "a+");
34722ac3eadSMax Laier 
34813b9f610SMax Laier 	if (fp == NULL) {
34922ac3eadSMax Laier 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
3505ee7cd21SMax Laier 		close(fd);
3515ee7cd21SMax Laier 		return (-1);
35213b9f610SMax Laier 	}
35313b9f610SMax Laier 	if (fstat(fileno(fp), &st) == -1) {
35422ac3eadSMax Laier 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
3555ee7cd21SMax Laier 		fclose(fp);
3565ee7cd21SMax Laier 		return (-1);
35713b9f610SMax Laier 	}
35813b9f610SMax Laier 
35922ac3eadSMax Laier 	/* set FILE unbuffered, we do our own buffering */
36022ac3eadSMax Laier 	if (setvbuf(fp, NULL, _IONBF, 0)) {
36122ac3eadSMax Laier 		logmsg(LOG_ERR, "Failed to set output buffers");
3625ee7cd21SMax Laier 		fclose(fp);
3635ee7cd21SMax Laier 		return (-1);
36422ac3eadSMax Laier 	}
36513b9f610SMax Laier 
36613b9f610SMax Laier #define TCPDUMP_MAGIC 0xa1b2c3d4
36713b9f610SMax Laier 
36813b9f610SMax Laier 	if (st.st_size == 0) {
36922ac3eadSMax Laier 		if (snaplen != cur_snaplen) {
37013b9f610SMax Laier 			logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
3715ee7cd21SMax Laier 			if (set_snaplen(snaplen))
37222ac3eadSMax Laier 				logmsg(LOG_WARNING,
37322ac3eadSMax Laier 				    "Failed, using old settings");
37413b9f610SMax Laier 		}
37513b9f610SMax Laier 		hdr.magic = TCPDUMP_MAGIC;
37613b9f610SMax Laier 		hdr.version_major = PCAP_VERSION_MAJOR;
37713b9f610SMax Laier 		hdr.version_minor = PCAP_VERSION_MINOR;
37813b9f610SMax Laier 		hdr.thiszone = hpcap->tzoff;
37913b9f610SMax Laier 		hdr.snaplen = hpcap->snapshot;
38013b9f610SMax Laier 		hdr.sigfigs = 0;
38113b9f610SMax Laier 		hdr.linktype = hpcap->linktype;
38213b9f610SMax Laier 
38313b9f610SMax Laier 		if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
38413b9f610SMax Laier 			fclose(fp);
3855ee7cd21SMax Laier 			return (-1);
38613b9f610SMax Laier 		}
38722ac3eadSMax Laier 	} else if (scan_dump(fp, st.st_size)) {
38822ac3eadSMax Laier 		fclose(fp);
3895ee7cd21SMax Laier 		if (nomove || priv_move_log()) {
3905ee7cd21SMax Laier 			logmsg(LOG_ERR,
3915ee7cd21SMax Laier 			    "Invalid/incompatible log file, move it away");
3925ee7cd21SMax Laier 			return (-1);
3935ee7cd21SMax Laier 		}
39422ac3eadSMax Laier 		return (1);
39513b9f610SMax Laier 	}
39622ac3eadSMax Laier 
39722ac3eadSMax Laier 	dpcap = fp;
39822ac3eadSMax Laier 
39922ac3eadSMax Laier 	set_suspended(0);
40022ac3eadSMax Laier 	flush_buffer(fp);
40122ac3eadSMax Laier 
40222ac3eadSMax Laier 	return (0);
40322ac3eadSMax Laier }
40422ac3eadSMax Laier 
40522ac3eadSMax Laier int
40622ac3eadSMax Laier scan_dump(FILE *fp, off_t size)
40722ac3eadSMax Laier {
40822ac3eadSMax Laier 	struct pcap_file_header hdr;
4096964e37dSMax Laier #ifdef __FreeBSD__
4106964e37dSMax Laier 	struct pcap_sf_pkthdr ph;
4116964e37dSMax Laier #else
41222ac3eadSMax Laier 	struct pcap_pkthdr ph;
4136964e37dSMax Laier #endif
41422ac3eadSMax Laier 	off_t pos;
41522ac3eadSMax Laier 
41622ac3eadSMax Laier 	/*
41722ac3eadSMax Laier 	 * Must read the file, compare the header against our new
41822ac3eadSMax Laier 	 * options (in particular, snaplen) and adjust our options so
41922ac3eadSMax Laier 	 * that we generate a correct file. Furthermore, check the file
42022ac3eadSMax Laier 	 * for consistency so that we can append safely.
42122ac3eadSMax Laier 	 *
42222ac3eadSMax Laier 	 * XXX this may take a long time for large logs.
42322ac3eadSMax Laier 	 */
42422ac3eadSMax Laier 	(void) fseek(fp, 0L, SEEK_SET);
42522ac3eadSMax Laier 
42622ac3eadSMax Laier 	if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
42722ac3eadSMax Laier 		logmsg(LOG_ERR, "Short file header");
42822ac3eadSMax Laier 		return (1);
42922ac3eadSMax Laier 	}
43022ac3eadSMax Laier 
43122ac3eadSMax Laier 	if (hdr.magic != TCPDUMP_MAGIC ||
43222ac3eadSMax Laier 	    hdr.version_major != PCAP_VERSION_MAJOR ||
43322ac3eadSMax Laier 	    hdr.version_minor != PCAP_VERSION_MINOR ||
43422ac3eadSMax Laier 	    hdr.linktype != hpcap->linktype ||
43522ac3eadSMax Laier 	    hdr.snaplen > PFLOGD_MAXSNAPLEN) {
43622ac3eadSMax Laier 		return (1);
43722ac3eadSMax Laier 	}
43822ac3eadSMax Laier 
43922ac3eadSMax Laier 	pos = sizeof(hdr);
44022ac3eadSMax Laier 
44122ac3eadSMax Laier 	while (!feof(fp)) {
44222ac3eadSMax Laier 		off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
44322ac3eadSMax Laier 		if (len == 0)
44422ac3eadSMax Laier 			break;
44522ac3eadSMax Laier 
44622ac3eadSMax Laier 		if (len != sizeof(ph))
44722ac3eadSMax Laier 			goto error;
44822ac3eadSMax Laier 		if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
44922ac3eadSMax Laier 			goto error;
45022ac3eadSMax Laier 		pos += sizeof(ph) + ph.caplen;
45122ac3eadSMax Laier 		if (pos > size)
45222ac3eadSMax Laier 			goto error;
45322ac3eadSMax Laier 		fseek(fp, ph.caplen, SEEK_CUR);
45422ac3eadSMax Laier 	}
45522ac3eadSMax Laier 
45622ac3eadSMax Laier 	if (pos != size)
45722ac3eadSMax Laier 		goto error;
45822ac3eadSMax Laier 
45922ac3eadSMax Laier 	if (hdr.snaplen != cur_snaplen) {
46022ac3eadSMax Laier 		logmsg(LOG_WARNING,
46122ac3eadSMax Laier 		       "Existing file has different snaplen %u, using it",
46222ac3eadSMax Laier 		       hdr.snaplen);
46322ac3eadSMax Laier 		if (set_snaplen(hdr.snaplen)) {
46422ac3eadSMax Laier 			logmsg(LOG_WARNING,
46522ac3eadSMax Laier 			       "Failed, using old settings, offset %llu",
46622ac3eadSMax Laier 			       (unsigned long long) size);
46713b9f610SMax Laier 		}
46813b9f610SMax Laier 	}
46913b9f610SMax Laier 
47013b9f610SMax Laier 	return (0);
47122ac3eadSMax Laier 
47222ac3eadSMax Laier  error:
47322ac3eadSMax Laier 	logmsg(LOG_ERR, "Corrupted log file.");
47422ac3eadSMax Laier 	return (1);
47522ac3eadSMax Laier }
47622ac3eadSMax Laier 
47722ac3eadSMax Laier /* dump a packet directly to the stream, which is unbuffered */
47822ac3eadSMax Laier void
47922ac3eadSMax Laier dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
48022ac3eadSMax Laier {
48122ac3eadSMax Laier 	FILE *f = (FILE *)user;
4826964e37dSMax Laier #ifdef __FreeBSD__
4836964e37dSMax Laier 	struct pcap_sf_pkthdr sh;
4846964e37dSMax Laier #endif
48522ac3eadSMax Laier 
48622ac3eadSMax Laier 	if (suspended) {
48722ac3eadSMax Laier 		packets_dropped++;
48822ac3eadSMax Laier 		return;
48922ac3eadSMax Laier 	}
49022ac3eadSMax Laier 
4916964e37dSMax Laier #ifdef __FreeBSD__
4926964e37dSMax Laier 	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
4936964e37dSMax Laier 	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
4946964e37dSMax Laier 	sh.caplen = h->caplen;
4956964e37dSMax Laier 	sh.len = h->len;
4966964e37dSMax Laier 
4976964e37dSMax Laier 	if (fwrite((char *)&sh, sizeof(sh), 1, f) != 1) {
4986964e37dSMax Laier #else
49922ac3eadSMax Laier 	if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
5006964e37dSMax Laier #endif
50122ac3eadSMax Laier 		off_t pos = ftello(f);
5020baf7c86SMax Laier 
5030baf7c86SMax Laier 		/* try to undo header to prevent corruption */
5046964e37dSMax Laier #ifdef __FreeBSD__
5056964e37dSMax Laier 		if (pos < sizeof(sh) ||
5066964e37dSMax Laier 		    ftruncate(fileno(f), pos - sizeof(sh))) {
5076964e37dSMax Laier #else
50822ac3eadSMax Laier 		if (pos < sizeof(*h) ||
50922ac3eadSMax Laier 		    ftruncate(fileno(f), pos - sizeof(*h))) {
5106964e37dSMax Laier #endif
51122ac3eadSMax Laier 			logmsg(LOG_ERR, "Write failed, corrupted logfile!");
51222ac3eadSMax Laier 			set_suspended(1);
51322ac3eadSMax Laier 			gotsig_close = 1;
51422ac3eadSMax Laier 			return;
51522ac3eadSMax Laier 		}
51622ac3eadSMax Laier 		goto error;
51722ac3eadSMax Laier 	}
51822ac3eadSMax Laier 
51922ac3eadSMax Laier 	if (fwrite((char *)sp, h->caplen, 1, f) != 1)
52022ac3eadSMax Laier 		goto error;
52122ac3eadSMax Laier 
52222ac3eadSMax Laier 	return;
52322ac3eadSMax Laier 
52422ac3eadSMax Laier error:
52522ac3eadSMax Laier 	set_suspended(1);
52622ac3eadSMax Laier 	packets_dropped ++;
52722ac3eadSMax Laier 	logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
52822ac3eadSMax Laier }
52922ac3eadSMax Laier 
53022ac3eadSMax Laier int
53122ac3eadSMax Laier flush_buffer(FILE *f)
53222ac3eadSMax Laier {
53322ac3eadSMax Laier 	off_t offset;
53422ac3eadSMax Laier 	int len = bufpos - buffer;
53522ac3eadSMax Laier 
53622ac3eadSMax Laier 	if (len <= 0)
53722ac3eadSMax Laier 		return (0);
53822ac3eadSMax Laier 
53922ac3eadSMax Laier 	offset = ftello(f);
54022ac3eadSMax Laier 	if (offset == (off_t)-1) {
54122ac3eadSMax Laier 		set_suspended(1);
54222ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: ftello: %s",
54322ac3eadSMax Laier 		    strerror(errno));
54422ac3eadSMax Laier 		return (1);
54522ac3eadSMax Laier 	}
54622ac3eadSMax Laier 
54722ac3eadSMax Laier 	if (fwrite(buffer, len, 1, f) != 1) {
54822ac3eadSMax Laier 		set_suspended(1);
54922ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
55022ac3eadSMax Laier 		    strerror(errno));
55122ac3eadSMax Laier 		ftruncate(fileno(f), offset);
55222ac3eadSMax Laier 		return (1);
55322ac3eadSMax Laier 	}
55422ac3eadSMax Laier 
55522ac3eadSMax Laier 	set_suspended(0);
55622ac3eadSMax Laier 	bufpos = buffer;
55722ac3eadSMax Laier 	bufleft = buflen;
55822ac3eadSMax Laier 	bufpkt = 0;
55922ac3eadSMax Laier 
56022ac3eadSMax Laier 	return (0);
56122ac3eadSMax Laier }
56222ac3eadSMax Laier 
56322ac3eadSMax Laier void
56422ac3eadSMax Laier purge_buffer(void)
56522ac3eadSMax Laier {
56622ac3eadSMax Laier 	packets_dropped += bufpkt;
56722ac3eadSMax Laier 
56822ac3eadSMax Laier 	set_suspended(0);
56922ac3eadSMax Laier 	bufpos = buffer;
57022ac3eadSMax Laier 	bufleft = buflen;
57122ac3eadSMax Laier 	bufpkt = 0;
57222ac3eadSMax Laier }
57322ac3eadSMax Laier 
57422ac3eadSMax Laier /* append packet to the buffer, flushing if necessary */
57522ac3eadSMax Laier void
57622ac3eadSMax Laier dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
57722ac3eadSMax Laier {
57822ac3eadSMax Laier 	FILE *f = (FILE *)user;
5796964e37dSMax Laier #ifdef __FreeBSD__
5806964e37dSMax Laier 	struct pcap_sf_pkthdr sh;
5816964e37dSMax Laier 	size_t len = sizeof(sh) + h->caplen;
5826964e37dSMax Laier #else
58322ac3eadSMax Laier 	size_t len = sizeof(*h) + h->caplen;
5846964e37dSMax Laier #endif
58522ac3eadSMax Laier 
58622ac3eadSMax Laier 	if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
58722ac3eadSMax Laier 		logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped",
58822ac3eadSMax Laier 		       len, cur_snaplen, snaplen);
58922ac3eadSMax Laier 		packets_dropped++;
59022ac3eadSMax Laier 		return;
59122ac3eadSMax Laier 	}
59222ac3eadSMax Laier 
59322ac3eadSMax Laier 	if (len <= bufleft)
59422ac3eadSMax Laier 		goto append;
59522ac3eadSMax Laier 
59622ac3eadSMax Laier 	if (suspended) {
59722ac3eadSMax Laier 		packets_dropped++;
59822ac3eadSMax Laier 		return;
59922ac3eadSMax Laier 	}
60022ac3eadSMax Laier 
60122ac3eadSMax Laier 	if (flush_buffer(f)) {
60222ac3eadSMax Laier 		packets_dropped++;
60322ac3eadSMax Laier 		return;
60422ac3eadSMax Laier 	}
60522ac3eadSMax Laier 
60622ac3eadSMax Laier 	if (len > bufleft) {
60722ac3eadSMax Laier 		dump_packet_nobuf(user, h, sp);
60822ac3eadSMax Laier 		return;
60922ac3eadSMax Laier 	}
61022ac3eadSMax Laier 
61122ac3eadSMax Laier  append:
6126964e37dSMax Laier #ifdef __FreeBSD__
6136964e37dSMax Laier 	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
6146964e37dSMax Laier 	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
6156964e37dSMax Laier 	sh.caplen = h->caplen;
6166964e37dSMax Laier 	sh.len = h->len;
6176964e37dSMax Laier 
6186964e37dSMax Laier 	memcpy(bufpos, &sh, sizeof(sh));
6196964e37dSMax Laier 	memcpy(bufpos + sizeof(sh), sp, h->caplen);
6206964e37dSMax Laier #else
62122ac3eadSMax Laier 	memcpy(bufpos, h, sizeof(*h));
62222ac3eadSMax Laier 	memcpy(bufpos + sizeof(*h), sp, h->caplen);
6236964e37dSMax Laier #endif
62422ac3eadSMax Laier 
62522ac3eadSMax Laier 	bufpos += len;
62622ac3eadSMax Laier 	bufleft -= len;
62722ac3eadSMax Laier 	bufpkt++;
62822ac3eadSMax Laier 
62922ac3eadSMax Laier 	return;
63013b9f610SMax Laier }
63113b9f610SMax Laier 
632e0bfbfceSBjoern A. Zeeb void
633e0bfbfceSBjoern A. Zeeb log_pcap_stats(void)
634e0bfbfceSBjoern A. Zeeb {
635e0bfbfceSBjoern A. Zeeb 	struct pcap_stat pstat;
636e0bfbfceSBjoern A. Zeeb 	if (pcap_stats(hpcap, &pstat) < 0)
637e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
638e0bfbfceSBjoern A. Zeeb 	else
639e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_NOTICE,
640e0bfbfceSBjoern A. Zeeb 			"%u packets received, %u/%u dropped (kernel/pflogd)",
641e0bfbfceSBjoern A. Zeeb 			pstat.ps_recv, pstat.ps_drop, packets_dropped);
642e0bfbfceSBjoern A. Zeeb }
643e0bfbfceSBjoern A. Zeeb 
64413b9f610SMax Laier int
64513b9f610SMax Laier main(int argc, char **argv)
64613b9f610SMax Laier {
647e0bfbfceSBjoern A. Zeeb 	int ch, np, ret, Xflag = 0;
64822ac3eadSMax Laier 	pcap_handler phandler = dump_packet;
6491a58af5eSMax Laier 	const char *errstr = NULL;
650e0bfbfceSBjoern A. Zeeb 	char *pidf = NULL;
651e0bfbfceSBjoern A. Zeeb 
652e0bfbfceSBjoern A. Zeeb 	ret = 0;
65313b9f610SMax Laier 
65422ac3eadSMax Laier 	closefrom(STDERR_FILENO + 1);
65522ac3eadSMax Laier 
656e0bfbfceSBjoern A. Zeeb 	while ((ch = getopt(argc, argv, "Dxd:f:i:p:s:")) != -1) {
65713b9f610SMax Laier 		switch (ch) {
65813b9f610SMax Laier 		case 'D':
65913b9f610SMax Laier 			Debug = 1;
66013b9f610SMax Laier 			break;
66113b9f610SMax Laier 		case 'd':
6620baf7c86SMax Laier 			delay = strtonum(optarg, 5, 60*60, &errstr);
6630baf7c86SMax Laier 			if (errstr)
66413b9f610SMax Laier 				usage();
66513b9f610SMax Laier 			break;
66613b9f610SMax Laier 		case 'f':
66713b9f610SMax Laier 			filename = optarg;
66813b9f610SMax Laier 			break;
6695ee7cd21SMax Laier 		case 'i':
6705ee7cd21SMax Laier 			interface = optarg;
6715ee7cd21SMax Laier 			break;
672e0bfbfceSBjoern A. Zeeb 		case 'p':
673e0bfbfceSBjoern A. Zeeb 			pidf = optarg;
674e0bfbfceSBjoern A. Zeeb 			break;
67513b9f610SMax Laier 		case 's':
6760baf7c86SMax Laier 			snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
6770baf7c86SMax Laier 			    &errstr);
67813b9f610SMax Laier 			if (snaplen <= 0)
67913b9f610SMax Laier 				snaplen = DEF_SNAPLEN;
6800baf7c86SMax Laier 			if (errstr)
68122ac3eadSMax Laier 				snaplen = PFLOGD_MAXSNAPLEN;
68222ac3eadSMax Laier 			break;
68322ac3eadSMax Laier 		case 'x':
68422ac3eadSMax Laier 			Xflag++;
68513b9f610SMax Laier 			break;
68613b9f610SMax Laier 		default:
68713b9f610SMax Laier 			usage();
68813b9f610SMax Laier 		}
68913b9f610SMax Laier 
69013b9f610SMax Laier 	}
69113b9f610SMax Laier 
69213b9f610SMax Laier 	log_debug = Debug;
69313b9f610SMax Laier 	argc -= optind;
69413b9f610SMax Laier 	argv += optind;
69513b9f610SMax Laier 
696e0bfbfceSBjoern A. Zeeb 	/* does interface exist */
697e0bfbfceSBjoern A. Zeeb 	if (!if_exists(interface)) {
698e0bfbfceSBjoern A. Zeeb 		warn("Failed to initialize: %s", interface);
699e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_ERR, "Failed to initialize: %s", interface);
700e0bfbfceSBjoern A. Zeeb 		logmsg(LOG_ERR, "Exiting, init failure");
701e0bfbfceSBjoern A. Zeeb 		exit(1);
702e0bfbfceSBjoern A. Zeeb 	}
703e0bfbfceSBjoern A. Zeeb 
70413b9f610SMax Laier 	if (!Debug) {
70513b9f610SMax Laier 		openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
70613b9f610SMax Laier 		if (daemon(0, 0)) {
70713b9f610SMax Laier 			logmsg(LOG_WARNING, "Failed to become daemon: %s",
70813b9f610SMax Laier 			    strerror(errno));
70913b9f610SMax Laier 		}
710e0bfbfceSBjoern A. Zeeb 		pidfile(pidf);
71113b9f610SMax Laier 	}
71213b9f610SMax Laier 
7130baf7c86SMax Laier 	tzset();
71413b9f610SMax Laier 	(void)umask(S_IRWXG | S_IRWXO);
71513b9f610SMax Laier 
71622ac3eadSMax Laier 	/* filter will be used by the privileged process */
71722ac3eadSMax Laier 	if (argc) {
71822ac3eadSMax Laier 		filter = copy_argv(argv);
71922ac3eadSMax Laier 		if (filter == NULL)
72022ac3eadSMax Laier 			logmsg(LOG_NOTICE, "Failed to form filter expression");
72122ac3eadSMax Laier 	}
72222ac3eadSMax Laier 
72322ac3eadSMax Laier 	/* initialize pcap before dropping privileges */
72422ac3eadSMax Laier 	if (init_pcap()) {
72522ac3eadSMax Laier 		logmsg(LOG_ERR, "Exiting, init failure");
72622ac3eadSMax Laier 		exit(1);
72722ac3eadSMax Laier 	}
72822ac3eadSMax Laier 
72922ac3eadSMax Laier 	/* Privilege separation begins here */
73022ac3eadSMax Laier 	if (priv_init()) {
73122ac3eadSMax Laier 		logmsg(LOG_ERR, "unable to privsep");
73222ac3eadSMax Laier 		exit(1);
73322ac3eadSMax Laier 	}
73422ac3eadSMax Laier 
73522ac3eadSMax Laier 	setproctitle("[initializing]");
73622ac3eadSMax Laier 	/* Process is now unprivileged and inside a chroot */
73713b9f610SMax Laier 	signal(SIGTERM, sig_close);
73813b9f610SMax Laier 	signal(SIGINT, sig_close);
73913b9f610SMax Laier 	signal(SIGQUIT, sig_close);
74013b9f610SMax Laier 	signal(SIGALRM, sig_alrm);
741e0bfbfceSBjoern A. Zeeb 	signal(SIGUSR1, sig_usr1);
74213b9f610SMax Laier 	signal(SIGHUP, sig_hup);
74313b9f610SMax Laier 	alarm(delay);
74413b9f610SMax Laier 
74522ac3eadSMax Laier 	buffer = malloc(PFLOGD_BUFSIZE);
74613b9f610SMax Laier 
74722ac3eadSMax Laier 	if (buffer == NULL) {
74822ac3eadSMax Laier 		logmsg(LOG_WARNING, "Failed to allocate output buffer");
74922ac3eadSMax Laier 		phandler = dump_packet_nobuf;
75022ac3eadSMax Laier 	} else {
75122ac3eadSMax Laier 		bufleft = buflen = PFLOGD_BUFSIZE;
75222ac3eadSMax Laier 		bufpos = buffer;
75322ac3eadSMax Laier 		bufpkt = 0;
75413b9f610SMax Laier 	}
75513b9f610SMax Laier 
7565ee7cd21SMax Laier 	if (reset_dump(Xflag) < 0) {
75722ac3eadSMax Laier 		if (Xflag)
75822ac3eadSMax Laier 			return (1);
75922ac3eadSMax Laier 
76022ac3eadSMax Laier 		logmsg(LOG_ERR, "Logging suspended: open error");
76122ac3eadSMax Laier 		set_suspended(1);
76222ac3eadSMax Laier 	} else if (Xflag)
76322ac3eadSMax Laier 		return (0);
76413b9f610SMax Laier 
76513b9f610SMax Laier 	while (1) {
76622ac3eadSMax Laier 		np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
7670baf7c86SMax Laier 		    phandler, (u_char *)dpcap);
76822d6889bSMax Laier 		if (np < 0) {
769f7862a87SDimitry Andric 			if (!if_exists(interface)) {
770e0bfbfceSBjoern A. Zeeb 				logmsg(LOG_NOTICE, "interface %s went away",
771e0bfbfceSBjoern A. Zeeb 				    interface);
772e0bfbfceSBjoern A. Zeeb 				ret = -1;
77322d6889bSMax Laier 				break;
77422d6889bSMax Laier 			}
77513b9f610SMax Laier 			logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
77622d6889bSMax Laier 		}
77713b9f610SMax Laier 
77813b9f610SMax Laier 		if (gotsig_close)
77913b9f610SMax Laier 			break;
78013b9f610SMax Laier 		if (gotsig_hup) {
7815ee7cd21SMax Laier 			if (reset_dump(0)) {
78222ac3eadSMax Laier 				logmsg(LOG_ERR,
78322ac3eadSMax Laier 				    "Logging suspended: open error");
78422ac3eadSMax Laier 				set_suspended(1);
78513b9f610SMax Laier 			}
78613b9f610SMax Laier 			gotsig_hup = 0;
78713b9f610SMax Laier 		}
78813b9f610SMax Laier 
78913b9f610SMax Laier 		if (gotsig_alrm) {
79022ac3eadSMax Laier 			if (dpcap)
79122ac3eadSMax Laier 				flush_buffer(dpcap);
7925ee7cd21SMax Laier 			else
7935ee7cd21SMax Laier 				gotsig_hup = 1;
79413b9f610SMax Laier 			gotsig_alrm = 0;
79513b9f610SMax Laier 			alarm(delay);
79613b9f610SMax Laier 		}
797e0bfbfceSBjoern A. Zeeb 
798e0bfbfceSBjoern A. Zeeb 		if (gotsig_usr1) {
799e0bfbfceSBjoern A. Zeeb 			log_pcap_stats();
800e0bfbfceSBjoern A. Zeeb 			gotsig_usr1 = 0;
801e0bfbfceSBjoern A. Zeeb 		}
80213b9f610SMax Laier 	}
80313b9f610SMax Laier 
80422ac3eadSMax Laier 	logmsg(LOG_NOTICE, "Exiting");
80522ac3eadSMax Laier 	if (dpcap) {
80622ac3eadSMax Laier 		flush_buffer(dpcap);
80722ac3eadSMax Laier 		fclose(dpcap);
80822ac3eadSMax Laier 	}
80922ac3eadSMax Laier 	purge_buffer();
81013b9f610SMax Laier 
811e0bfbfceSBjoern A. Zeeb 	log_pcap_stats();
81213b9f610SMax Laier 	pcap_close(hpcap);
81313b9f610SMax Laier 	if (!Debug)
81413b9f610SMax Laier 		closelog();
815e0bfbfceSBjoern A. Zeeb 	return (ret);
81613b9f610SMax Laier }
817