xref: /dflybsd-src/usr.sbin/pflogd/pflogd.c (revision 3f75611e55cda2794a40d4231ecca0f75812a7dd)
1315a7da3SJan Lentfer /*	$OpenBSD: pflogd.c,v 1.45 2007/06/06 14:11:26 henning Exp $	*/
295cc27f0SJoerg Sonnenberger 
395cc27f0SJoerg Sonnenberger /*
495cc27f0SJoerg Sonnenberger  * Copyright (c) 2001 Theo de Raadt
595cc27f0SJoerg Sonnenberger  * Copyright (c) 2001 Can Erkin Acar
695cc27f0SJoerg Sonnenberger  * All rights reserved.
795cc27f0SJoerg Sonnenberger  *
895cc27f0SJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
995cc27f0SJoerg Sonnenberger  * modification, are permitted provided that the following conditions
1095cc27f0SJoerg Sonnenberger  * are met:
1195cc27f0SJoerg Sonnenberger  *
1295cc27f0SJoerg Sonnenberger  *    - Redistributions of source code must retain the above copyright
1395cc27f0SJoerg Sonnenberger  *      notice, this list of conditions and the following disclaimer.
1495cc27f0SJoerg Sonnenberger  *    - Redistributions in binary form must reproduce the above
1595cc27f0SJoerg Sonnenberger  *      copyright notice, this list of conditions and the following
1695cc27f0SJoerg Sonnenberger  *      disclaimer in the documentation and/or other materials provided
1795cc27f0SJoerg Sonnenberger  *      with the distribution.
1895cc27f0SJoerg Sonnenberger  *
1995cc27f0SJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2095cc27f0SJoerg Sonnenberger  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2195cc27f0SJoerg Sonnenberger  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2295cc27f0SJoerg Sonnenberger  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2395cc27f0SJoerg Sonnenberger  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2495cc27f0SJoerg Sonnenberger  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2595cc27f0SJoerg Sonnenberger  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2695cc27f0SJoerg Sonnenberger  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2795cc27f0SJoerg Sonnenberger  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2895cc27f0SJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2995cc27f0SJoerg Sonnenberger  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3095cc27f0SJoerg Sonnenberger  * POSSIBILITY OF SUCH DAMAGE.
3195cc27f0SJoerg Sonnenberger  */
3295cc27f0SJoerg Sonnenberger 
3395cc27f0SJoerg Sonnenberger #include <sys/types.h>
3495cc27f0SJoerg Sonnenberger #include <sys/ioctl.h>
3595cc27f0SJoerg Sonnenberger #include <sys/file.h>
3695cc27f0SJoerg Sonnenberger #include <sys/stat.h>
37315a7da3SJan Lentfer #include <sys/socket.h>
38315a7da3SJan Lentfer #include <net/if.h>
39315a7da3SJan Lentfer 
4095cc27f0SJoerg Sonnenberger #include <errno.h>
41315a7da3SJan Lentfer #include <err.h>
4295cc27f0SJoerg Sonnenberger #include <fcntl.h>
4395cc27f0SJoerg Sonnenberger #include <syslog.h>
4495cc27f0SJoerg Sonnenberger #include <signal.h>
4595cc27f0SJoerg Sonnenberger #include <stdarg.h>
4695cc27f0SJoerg Sonnenberger #include <stdio.h>
4795cc27f0SJoerg Sonnenberger #include <stdlib.h>
4895cc27f0SJoerg Sonnenberger #include <string.h>
4995cc27f0SJoerg Sonnenberger #include <unistd.h>
5095cc27f0SJoerg Sonnenberger 
5195cc27f0SJoerg Sonnenberger #include <libutil.h>
5295cc27f0SJoerg Sonnenberger #include <pcap-int.h>
5395cc27f0SJoerg Sonnenberger #include <pcap.h>
5495cc27f0SJoerg Sonnenberger 
5595cc27f0SJoerg Sonnenberger #include "pflogd.h"
5695cc27f0SJoerg Sonnenberger 
5795cc27f0SJoerg Sonnenberger pcap_t *hpcap;
5895cc27f0SJoerg Sonnenberger static FILE *dpcap;
5995cc27f0SJoerg Sonnenberger 
6095cc27f0SJoerg Sonnenberger int Debug = 0;
6195cc27f0SJoerg Sonnenberger static int snaplen = DEF_SNAPLEN;
6295cc27f0SJoerg Sonnenberger static int cur_snaplen = DEF_SNAPLEN;
6395cc27f0SJoerg Sonnenberger 
64e437855fSPeeter volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup, gotsig_usr1;
6595cc27f0SJoerg Sonnenberger 
6695cc27f0SJoerg Sonnenberger const char *filename = PFLOGD_LOG_FILE;
6795cc27f0SJoerg Sonnenberger const char *interface = PFLOGD_DEFAULT_IF;
6895cc27f0SJoerg Sonnenberger char *filter = NULL;
6995cc27f0SJoerg Sonnenberger 
7095cc27f0SJoerg Sonnenberger char errbuf[PCAP_ERRBUF_SIZE];
7195cc27f0SJoerg Sonnenberger 
7295cc27f0SJoerg Sonnenberger int log_debug = 0;
7395cc27f0SJoerg Sonnenberger unsigned int delay = FLUSH_DELAY;
7495cc27f0SJoerg Sonnenberger 
7595cc27f0SJoerg Sonnenberger char *copy_argv(char * const *);
7695cc27f0SJoerg Sonnenberger void  dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
7795cc27f0SJoerg Sonnenberger void  dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
78e437855fSPeeter void  log_pcap_stats(void);
7995cc27f0SJoerg Sonnenberger int   flush_buffer(FILE *);
80315a7da3SJan Lentfer int   if_exists(char *);
8195cc27f0SJoerg Sonnenberger int   init_pcap(void);
8295cc27f0SJoerg Sonnenberger void  purge_buffer(void);
83c929e0dfSJan Lentfer int   reset_dump(int);
8495cc27f0SJoerg Sonnenberger int   scan_dump(FILE *, off_t);
8595cc27f0SJoerg Sonnenberger int   set_snaplen(int);
8695cc27f0SJoerg Sonnenberger void  set_suspended(int);
8795cc27f0SJoerg Sonnenberger void  sig_alrm(int);
88e437855fSPeeter void  sig_usr1(int);
8995cc27f0SJoerg Sonnenberger void  sig_close(int);
9095cc27f0SJoerg Sonnenberger void  sig_hup(int);
91fe08e20dSSascha Wildner void  usage(void) __dead2;
9295cc27f0SJoerg Sonnenberger 
93c929e0dfSJan Lentfer static int try_reset_dump(int);
94c929e0dfSJan Lentfer 
9595cc27f0SJoerg Sonnenberger /* buffer must always be greater than snaplen */
9695cc27f0SJoerg Sonnenberger static int    bufpkt = 0;	/* number of packets in buffer */
9795cc27f0SJoerg Sonnenberger static size_t buflen = 0;	/* allocated size of buffer */
9895cc27f0SJoerg Sonnenberger static char  *buffer = NULL;	/* packet buffer */
9995cc27f0SJoerg Sonnenberger static char  *bufpos = NULL;	/* position in buffer */
10095cc27f0SJoerg Sonnenberger static size_t bufleft = 0;	/* bytes left in buffer */
10195cc27f0SJoerg Sonnenberger 
10295cc27f0SJoerg Sonnenberger /* if error, stop logging but count dropped packets */
10395cc27f0SJoerg Sonnenberger static int suspended = -1;
10495cc27f0SJoerg Sonnenberger static long packets_dropped = 0;
10595cc27f0SJoerg Sonnenberger 
10695cc27f0SJoerg Sonnenberger void
set_suspended(int s)10795cc27f0SJoerg Sonnenberger set_suspended(int s)
10895cc27f0SJoerg Sonnenberger {
10995cc27f0SJoerg Sonnenberger 	if (suspended == s)
11095cc27f0SJoerg Sonnenberger 		return;
11195cc27f0SJoerg Sonnenberger 
11295cc27f0SJoerg Sonnenberger 	suspended = s;
113c929e0dfSJan Lentfer 	setproctitle("[%s] -s %d -i %s -f %s",
114c929e0dfSJan Lentfer 	    suspended ? "suspended" : "running",
115c929e0dfSJan Lentfer 	    cur_snaplen, interface, filename);
11695cc27f0SJoerg Sonnenberger }
11795cc27f0SJoerg Sonnenberger 
11895cc27f0SJoerg Sonnenberger char *
copy_argv(char * const * argv)11995cc27f0SJoerg Sonnenberger copy_argv(char * const *argv)
12095cc27f0SJoerg Sonnenberger {
12195cc27f0SJoerg Sonnenberger 	size_t len = 0, n;
12295cc27f0SJoerg Sonnenberger 	char *buf;
12395cc27f0SJoerg Sonnenberger 
12495cc27f0SJoerg Sonnenberger 	if (argv == NULL)
12595cc27f0SJoerg Sonnenberger 		return (NULL);
12695cc27f0SJoerg Sonnenberger 
12795cc27f0SJoerg Sonnenberger 	for (n = 0; argv[n]; n++)
12895cc27f0SJoerg Sonnenberger 		len += strlen(argv[n])+1;
12995cc27f0SJoerg Sonnenberger 	if (len == 0)
13095cc27f0SJoerg Sonnenberger 		return (NULL);
13195cc27f0SJoerg Sonnenberger 
13295cc27f0SJoerg Sonnenberger 	buf = malloc(len);
13395cc27f0SJoerg Sonnenberger 	if (buf == NULL)
13495cc27f0SJoerg Sonnenberger 		return (NULL);
13595cc27f0SJoerg Sonnenberger 
13695cc27f0SJoerg Sonnenberger 	strlcpy(buf, argv[0], len);
13795cc27f0SJoerg Sonnenberger 	for (n = 1; argv[n]; n++) {
13895cc27f0SJoerg Sonnenberger 		strlcat(buf, " ", len);
13995cc27f0SJoerg Sonnenberger 		strlcat(buf, argv[n], len);
14095cc27f0SJoerg Sonnenberger 	}
14195cc27f0SJoerg Sonnenberger 	return (buf);
14295cc27f0SJoerg Sonnenberger }
14395cc27f0SJoerg Sonnenberger 
14495cc27f0SJoerg Sonnenberger void
logmsg(int pri,const char * message,...)14595cc27f0SJoerg Sonnenberger logmsg(int pri, const char *message, ...)
14695cc27f0SJoerg Sonnenberger {
14795cc27f0SJoerg Sonnenberger 	va_list ap;
14895cc27f0SJoerg Sonnenberger 	va_start(ap, message);
14995cc27f0SJoerg Sonnenberger 
15095cc27f0SJoerg Sonnenberger 	if (log_debug) {
15195cc27f0SJoerg Sonnenberger 		vfprintf(stderr, message, ap);
15295cc27f0SJoerg Sonnenberger 		fprintf(stderr, "\n");
15395cc27f0SJoerg Sonnenberger 	} else
15495cc27f0SJoerg Sonnenberger 		vsyslog(pri, message, ap);
15595cc27f0SJoerg Sonnenberger 	va_end(ap);
15695cc27f0SJoerg Sonnenberger }
15795cc27f0SJoerg Sonnenberger 
15895cc27f0SJoerg Sonnenberger void
usage(void)15995cc27f0SJoerg Sonnenberger usage(void)
16095cc27f0SJoerg Sonnenberger {
16195cc27f0SJoerg Sonnenberger 	fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
162315a7da3SJan Lentfer 	fprintf(stderr, " [-i interface] [-p pidfile]\n");
163315a7da3SJan Lentfer 	fprintf(stderr, "              [-s snaplen] [expression]\n");
16495cc27f0SJoerg Sonnenberger 	exit(1);
16595cc27f0SJoerg Sonnenberger }
16695cc27f0SJoerg Sonnenberger 
16795cc27f0SJoerg Sonnenberger void
sig_close(int sig __unused)16895cc27f0SJoerg Sonnenberger sig_close(int sig __unused)
16995cc27f0SJoerg Sonnenberger {
17095cc27f0SJoerg Sonnenberger 	gotsig_close = 1;
17195cc27f0SJoerg Sonnenberger }
17295cc27f0SJoerg Sonnenberger 
17395cc27f0SJoerg Sonnenberger void
sig_hup(int sig __unused)17495cc27f0SJoerg Sonnenberger sig_hup(int sig __unused)
17595cc27f0SJoerg Sonnenberger {
17695cc27f0SJoerg Sonnenberger 	gotsig_hup = 1;
17795cc27f0SJoerg Sonnenberger }
17895cc27f0SJoerg Sonnenberger 
17995cc27f0SJoerg Sonnenberger void
sig_alrm(int sig __unused)18095cc27f0SJoerg Sonnenberger sig_alrm(int sig __unused)
18195cc27f0SJoerg Sonnenberger {
18295cc27f0SJoerg Sonnenberger 	gotsig_alrm = 1;
18395cc27f0SJoerg Sonnenberger }
18495cc27f0SJoerg Sonnenberger 
18595cc27f0SJoerg Sonnenberger void
sig_usr1(int sig __unused)186e437855fSPeeter sig_usr1(int sig __unused)
187e437855fSPeeter {
188e437855fSPeeter 	gotsig_usr1 = 1;
189e437855fSPeeter }
190e437855fSPeeter 
191e437855fSPeeter void
set_pcap_filter(void)19295cc27f0SJoerg Sonnenberger set_pcap_filter(void)
19395cc27f0SJoerg Sonnenberger {
19495cc27f0SJoerg Sonnenberger 	struct bpf_program bprog;
19595cc27f0SJoerg Sonnenberger 
19695cc27f0SJoerg Sonnenberger 	if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
19795cc27f0SJoerg Sonnenberger 		logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
19895cc27f0SJoerg Sonnenberger 	else {
19995cc27f0SJoerg Sonnenberger 		if (pcap_setfilter(hpcap, &bprog) < 0)
20095cc27f0SJoerg Sonnenberger 			logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
20195cc27f0SJoerg Sonnenberger 		pcap_freecode(&bprog);
20295cc27f0SJoerg Sonnenberger 	}
20395cc27f0SJoerg Sonnenberger }
20495cc27f0SJoerg Sonnenberger 
20595cc27f0SJoerg Sonnenberger int
if_exists(char * ifname)206315a7da3SJan Lentfer if_exists(char *ifname)
207315a7da3SJan Lentfer {
208315a7da3SJan Lentfer 	int s;
209315a7da3SJan Lentfer 	struct ifreq ifr;
210315a7da3SJan Lentfer 	struct if_data ifrdat;
211315a7da3SJan Lentfer 
212315a7da3SJan Lentfer 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
213315a7da3SJan Lentfer 		err(1, "socket");
214315a7da3SJan Lentfer 	bzero(&ifr, sizeof(ifr));
215315a7da3SJan Lentfer 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
216315a7da3SJan Lentfer 		sizeof(ifr.ifr_name))
217315a7da3SJan Lentfer 			errx(1, "main ifr_name: strlcpy");
218315a7da3SJan Lentfer 	ifr.ifr_data = (caddr_t)&ifrdat;
219315a7da3SJan Lentfer 	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
220315a7da3SJan Lentfer 		return (0);
221315a7da3SJan Lentfer 	if (close(s))
222315a7da3SJan Lentfer 		err(1, "close");
223315a7da3SJan Lentfer 
224315a7da3SJan Lentfer 	return (1);
225315a7da3SJan Lentfer }
226315a7da3SJan Lentfer 
227315a7da3SJan Lentfer int
init_pcap(void)22895cc27f0SJoerg Sonnenberger init_pcap(void)
22995cc27f0SJoerg Sonnenberger {
23095cc27f0SJoerg Sonnenberger 	hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
23195cc27f0SJoerg Sonnenberger 	if (hpcap == NULL) {
23295cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
23395cc27f0SJoerg Sonnenberger 		return (-1);
23495cc27f0SJoerg Sonnenberger 	}
23595cc27f0SJoerg Sonnenberger 
23695cc27f0SJoerg Sonnenberger 	if (pcap_datalink(hpcap) != DLT_PFLOG) {
23795cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Invalid datalink type");
23895cc27f0SJoerg Sonnenberger 		pcap_close(hpcap);
23995cc27f0SJoerg Sonnenberger 		hpcap = NULL;
24095cc27f0SJoerg Sonnenberger 		return (-1);
24195cc27f0SJoerg Sonnenberger 	}
24295cc27f0SJoerg Sonnenberger 
24395cc27f0SJoerg Sonnenberger 	set_pcap_filter();
24495cc27f0SJoerg Sonnenberger 
24595cc27f0SJoerg Sonnenberger 	cur_snaplen = snaplen = pcap_snapshot(hpcap);
24695cc27f0SJoerg Sonnenberger 
24795cc27f0SJoerg Sonnenberger 	/* From contrib/pf/pflogd.c 1.5 FreeBSD: BPF locking is not
24895cc27f0SJoerg Sonnenberger 	 * (yet) supported.
24995cc27f0SJoerg Sonnenberger 	 */
25095cc27f0SJoerg Sonnenberger 	#ifndef __DragonFly__
25195cc27f0SJoerg Sonnenberger 	/* lock */
25295cc27f0SJoerg Sonnenberger 	if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
25395cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
25495cc27f0SJoerg Sonnenberger 		return (-1);
25595cc27f0SJoerg Sonnenberger 	}
25695cc27f0SJoerg Sonnenberger 	#endif
25795cc27f0SJoerg Sonnenberger 
25895cc27f0SJoerg Sonnenberger 	return (0);
25995cc27f0SJoerg Sonnenberger }
26095cc27f0SJoerg Sonnenberger 
26195cc27f0SJoerg Sonnenberger int
set_snaplen(int snap)26295cc27f0SJoerg Sonnenberger set_snaplen(int snap)
26395cc27f0SJoerg Sonnenberger {
26495cc27f0SJoerg Sonnenberger 	if (priv_set_snaplen(snap))
26595cc27f0SJoerg Sonnenberger 		return (1);
26695cc27f0SJoerg Sonnenberger 
26795cc27f0SJoerg Sonnenberger 	if (cur_snaplen > snap)
26895cc27f0SJoerg Sonnenberger 		purge_buffer();
26995cc27f0SJoerg Sonnenberger 
27095cc27f0SJoerg Sonnenberger 	cur_snaplen = snap;
27195cc27f0SJoerg Sonnenberger 
27295cc27f0SJoerg Sonnenberger 	return (0);
27395cc27f0SJoerg Sonnenberger }
27495cc27f0SJoerg Sonnenberger 
27595cc27f0SJoerg Sonnenberger int
reset_dump(int nomove)276c929e0dfSJan Lentfer reset_dump(int nomove)
277c929e0dfSJan Lentfer {
278c929e0dfSJan Lentfer 	int ret;
279c929e0dfSJan Lentfer 
280c929e0dfSJan Lentfer 	for (;;) {
281c929e0dfSJan Lentfer 		ret = try_reset_dump(nomove);
282c929e0dfSJan Lentfer 		if (ret <= 0)
283c929e0dfSJan Lentfer 			break;
284c929e0dfSJan Lentfer 	}
285c929e0dfSJan Lentfer 
286c929e0dfSJan Lentfer 	return (ret);
287c929e0dfSJan Lentfer }
288c929e0dfSJan Lentfer 
289c929e0dfSJan Lentfer /*
290c929e0dfSJan Lentfer  * tries to (re)open log file, nomove flag is used with -x switch
291c929e0dfSJan Lentfer  * returns 0: success, 1: retry (log moved), -1: error
292c929e0dfSJan Lentfer  */
293c929e0dfSJan Lentfer int
try_reset_dump(int nomove)294c929e0dfSJan Lentfer try_reset_dump(int nomove)
29595cc27f0SJoerg Sonnenberger {
29695cc27f0SJoerg Sonnenberger 	struct pcap_file_header hdr;
29795cc27f0SJoerg Sonnenberger 	struct stat st;
29895cc27f0SJoerg Sonnenberger 	int fd;
29995cc27f0SJoerg Sonnenberger 	FILE *fp;
30095cc27f0SJoerg Sonnenberger 
30195cc27f0SJoerg Sonnenberger 	if (hpcap == NULL)
30295cc27f0SJoerg Sonnenberger 		return (-1);
30395cc27f0SJoerg Sonnenberger 
30495cc27f0SJoerg Sonnenberger 	if (dpcap) {
30595cc27f0SJoerg Sonnenberger 		flush_buffer(dpcap);
30695cc27f0SJoerg Sonnenberger 		fclose(dpcap);
30795cc27f0SJoerg Sonnenberger 		dpcap = NULL;
30895cc27f0SJoerg Sonnenberger 	}
30995cc27f0SJoerg Sonnenberger 
31095cc27f0SJoerg Sonnenberger 	/*
31195cc27f0SJoerg Sonnenberger 	 * Basically reimplement pcap_dump_open() because it truncates
31295cc27f0SJoerg Sonnenberger 	 * files and duplicates headers and such.
31395cc27f0SJoerg Sonnenberger 	 */
31495cc27f0SJoerg Sonnenberger 	fd = priv_open_log();
31595cc27f0SJoerg Sonnenberger 	if (fd < 0)
316c929e0dfSJan Lentfer 		return (-1);
31795cc27f0SJoerg Sonnenberger 
31895cc27f0SJoerg Sonnenberger 	fp = fdopen(fd, "a+");
31995cc27f0SJoerg Sonnenberger 
32095cc27f0SJoerg Sonnenberger 	if (fp == NULL) {
32195cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
322c929e0dfSJan Lentfer 		close(fd);
323c929e0dfSJan Lentfer 		return (-1);
32495cc27f0SJoerg Sonnenberger 	}
32595cc27f0SJoerg Sonnenberger 	if (fstat(fileno(fp), &st) == -1) {
32695cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
327c929e0dfSJan Lentfer 		fclose(fp);
328c929e0dfSJan Lentfer 		return (-1);
32995cc27f0SJoerg Sonnenberger 	}
33095cc27f0SJoerg Sonnenberger 
33195cc27f0SJoerg Sonnenberger 	/* set FILE unbuffered, we do our own buffering */
33295cc27f0SJoerg Sonnenberger 	if (setvbuf(fp, NULL, _IONBF, 0)) {
33395cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Failed to set output buffers");
334c929e0dfSJan Lentfer 		fclose(fp);
335c929e0dfSJan Lentfer 		return (-1);
33695cc27f0SJoerg Sonnenberger 	}
33795cc27f0SJoerg Sonnenberger 
33895cc27f0SJoerg Sonnenberger #define TCPDUMP_MAGIC 0xa1b2c3d4
33995cc27f0SJoerg Sonnenberger 
34095cc27f0SJoerg Sonnenberger 	if (st.st_size == 0) {
34195cc27f0SJoerg Sonnenberger 		if (snaplen != cur_snaplen) {
34295cc27f0SJoerg Sonnenberger 			logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
343c929e0dfSJan Lentfer 			if (set_snaplen(snaplen))
34495cc27f0SJoerg Sonnenberger 				logmsg(LOG_WARNING,
34595cc27f0SJoerg Sonnenberger 				    "Failed, using old settings");
34695cc27f0SJoerg Sonnenberger 		}
34795cc27f0SJoerg Sonnenberger 		hdr.magic = TCPDUMP_MAGIC;
34895cc27f0SJoerg Sonnenberger 		hdr.version_major = PCAP_VERSION_MAJOR;
34995cc27f0SJoerg Sonnenberger 		hdr.version_minor = PCAP_VERSION_MINOR;
350*3f75611eSAntonio Huete Jimenez 		/* https://www.tcpdump.org/manpages/pcap-savefile.5.txt */
351*3f75611eSAntonio Huete Jimenez 		hdr.thiszone = 0;
35295cc27f0SJoerg Sonnenberger 		hdr.snaplen = hpcap->snapshot;
35395cc27f0SJoerg Sonnenberger 		hdr.sigfigs = 0;
35495cc27f0SJoerg Sonnenberger 		hdr.linktype = hpcap->linktype;
35595cc27f0SJoerg Sonnenberger 
35695cc27f0SJoerg Sonnenberger 		if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
35795cc27f0SJoerg Sonnenberger 			fclose(fp);
358c929e0dfSJan Lentfer 			return (-1);
35995cc27f0SJoerg Sonnenberger 		}
36095cc27f0SJoerg Sonnenberger 	} else if (scan_dump(fp, st.st_size)) {
36195cc27f0SJoerg Sonnenberger 		fclose(fp);
362c929e0dfSJan Lentfer 		if (nomove || priv_move_log()) {
363c929e0dfSJan Lentfer 			logmsg(LOG_ERR,
364c929e0dfSJan Lentfer 			    "Invalid/incompatible log file, move it away");
365c929e0dfSJan Lentfer 			return (-1);
366c929e0dfSJan Lentfer 		}
36795cc27f0SJoerg Sonnenberger 		return (1);
36895cc27f0SJoerg Sonnenberger 	}
36995cc27f0SJoerg Sonnenberger 
37095cc27f0SJoerg Sonnenberger 	dpcap = fp;
37195cc27f0SJoerg Sonnenberger 
37295cc27f0SJoerg Sonnenberger 	set_suspended(0);
37395cc27f0SJoerg Sonnenberger 	flush_buffer(fp);
37495cc27f0SJoerg Sonnenberger 
37595cc27f0SJoerg Sonnenberger 	return (0);
37695cc27f0SJoerg Sonnenberger }
37795cc27f0SJoerg Sonnenberger 
37895cc27f0SJoerg Sonnenberger int
scan_dump(FILE * fp,off_t size)37995cc27f0SJoerg Sonnenberger scan_dump(FILE *fp, off_t size)
38095cc27f0SJoerg Sonnenberger {
38195cc27f0SJoerg Sonnenberger 	struct pcap_file_header hdr;
382e437855fSPeeter 	struct pcap_sf_pkthdr ph;
38395cc27f0SJoerg Sonnenberger 	off_t pos;
38495cc27f0SJoerg Sonnenberger 
38595cc27f0SJoerg Sonnenberger 	/*
38695cc27f0SJoerg Sonnenberger 	 * Must read the file, compare the header against our new
38795cc27f0SJoerg Sonnenberger 	 * options (in particular, snaplen) and adjust our options so
38895cc27f0SJoerg Sonnenberger 	 * that we generate a correct file. Furthermore, check the file
38995cc27f0SJoerg Sonnenberger 	 * for consistency so that we can append safely.
39095cc27f0SJoerg Sonnenberger 	 *
39195cc27f0SJoerg Sonnenberger 	 * XXX this may take a long time for large logs.
39295cc27f0SJoerg Sonnenberger 	 */
39371126e33SSascha Wildner 	fseek(fp, 0L, SEEK_SET);
39495cc27f0SJoerg Sonnenberger 
39595cc27f0SJoerg Sonnenberger 	if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
39695cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Short file header");
39795cc27f0SJoerg Sonnenberger 		return (1);
39895cc27f0SJoerg Sonnenberger 	}
39995cc27f0SJoerg Sonnenberger 
40095cc27f0SJoerg Sonnenberger 	if (hdr.magic != TCPDUMP_MAGIC ||
40195cc27f0SJoerg Sonnenberger 	    hdr.version_major != PCAP_VERSION_MAJOR ||
40295cc27f0SJoerg Sonnenberger 	    hdr.version_minor != PCAP_VERSION_MINOR ||
40395cc27f0SJoerg Sonnenberger 	    (int)hdr.linktype != hpcap->linktype ||
40495cc27f0SJoerg Sonnenberger 	    hdr.snaplen > PFLOGD_MAXSNAPLEN) {
40595cc27f0SJoerg Sonnenberger 		return (1);
40695cc27f0SJoerg Sonnenberger 	}
40795cc27f0SJoerg Sonnenberger 
40895cc27f0SJoerg Sonnenberger 	pos = sizeof(hdr);
40995cc27f0SJoerg Sonnenberger 
41095cc27f0SJoerg Sonnenberger 	while (!feof(fp)) {
41195cc27f0SJoerg Sonnenberger 		off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
41295cc27f0SJoerg Sonnenberger 		if (len == 0)
41395cc27f0SJoerg Sonnenberger 			break;
41495cc27f0SJoerg Sonnenberger 
41595cc27f0SJoerg Sonnenberger 		if (len != sizeof(ph))
41695cc27f0SJoerg Sonnenberger 			goto error;
41795cc27f0SJoerg Sonnenberger 		if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
41895cc27f0SJoerg Sonnenberger 			goto error;
41995cc27f0SJoerg Sonnenberger 		pos += sizeof(ph) + ph.caplen;
42095cc27f0SJoerg Sonnenberger 		if (pos > size)
42195cc27f0SJoerg Sonnenberger 			goto error;
42295cc27f0SJoerg Sonnenberger 		fseek(fp, ph.caplen, SEEK_CUR);
42395cc27f0SJoerg Sonnenberger 	}
42495cc27f0SJoerg Sonnenberger 
42595cc27f0SJoerg Sonnenberger 	if (pos != size)
42695cc27f0SJoerg Sonnenberger 		goto error;
42795cc27f0SJoerg Sonnenberger 
42895cc27f0SJoerg Sonnenberger 	if ((int)hdr.snaplen != cur_snaplen) {
42995cc27f0SJoerg Sonnenberger 		logmsg(LOG_WARNING,
43095cc27f0SJoerg Sonnenberger 		       "Existing file has different snaplen %u, using it",
43195cc27f0SJoerg Sonnenberger 		       hdr.snaplen);
43295cc27f0SJoerg Sonnenberger 		if (set_snaplen(hdr.snaplen)) {
43395cc27f0SJoerg Sonnenberger 			logmsg(LOG_WARNING,
43495cc27f0SJoerg Sonnenberger 			       "Failed, using old settings, offset %llu",
43595cc27f0SJoerg Sonnenberger 			       (unsigned long long) size);
43695cc27f0SJoerg Sonnenberger 		}
43795cc27f0SJoerg Sonnenberger 	}
43895cc27f0SJoerg Sonnenberger 
43995cc27f0SJoerg Sonnenberger 	return (0);
44095cc27f0SJoerg Sonnenberger 
44195cc27f0SJoerg Sonnenberger  error:
44295cc27f0SJoerg Sonnenberger 	logmsg(LOG_ERR, "Corrupted log file.");
44395cc27f0SJoerg Sonnenberger 	return (1);
44495cc27f0SJoerg Sonnenberger }
44595cc27f0SJoerg Sonnenberger 
44695cc27f0SJoerg Sonnenberger /* dump a packet directly to the stream, which is unbuffered */
44795cc27f0SJoerg Sonnenberger void
dump_packet_nobuf(u_char * user,const struct pcap_pkthdr * h,const u_char * sp)44895cc27f0SJoerg Sonnenberger dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
44995cc27f0SJoerg Sonnenberger {
45095cc27f0SJoerg Sonnenberger 	FILE *f = (FILE *)user;
4512461cb13SPeeter 	struct pcap_sf_pkthdr sh;
45295cc27f0SJoerg Sonnenberger 
45395cc27f0SJoerg Sonnenberger 	if (suspended) {
45495cc27f0SJoerg Sonnenberger 		packets_dropped++;
45595cc27f0SJoerg Sonnenberger 		return;
45695cc27f0SJoerg Sonnenberger 	}
45795cc27f0SJoerg Sonnenberger 
4582461cb13SPeeter 	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
4592461cb13SPeeter 	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
4602461cb13SPeeter 	sh.caplen = h->caplen;
4612461cb13SPeeter 	sh.len = h->len;
4622461cb13SPeeter 
4632461cb13SPeeter 	if (fwrite((char *)&sh, sizeof(sh), 1, f) != 1) {
46495cc27f0SJoerg Sonnenberger 		off_t pos = ftello(f);
465c929e0dfSJan Lentfer 
466c929e0dfSJan Lentfer 		/* try to undo header to prevent corruption */
4672461cb13SPeeter 		if ((size_t)pos < sizeof(sh) ||
4682461cb13SPeeter 		    ftruncate(fileno(f), pos - sizeof(sh))) {
46995cc27f0SJoerg Sonnenberger 			logmsg(LOG_ERR, "Write failed, corrupted logfile!");
47095cc27f0SJoerg Sonnenberger 			set_suspended(1);
47195cc27f0SJoerg Sonnenberger 			gotsig_close = 1;
47295cc27f0SJoerg Sonnenberger 			return;
47395cc27f0SJoerg Sonnenberger 		}
47495cc27f0SJoerg Sonnenberger 		goto error;
47595cc27f0SJoerg Sonnenberger 	}
47695cc27f0SJoerg Sonnenberger 
47795cc27f0SJoerg Sonnenberger 	if (fwrite(sp, h->caplen, 1, f) != 1)
47895cc27f0SJoerg Sonnenberger 		goto error;
47995cc27f0SJoerg Sonnenberger 
48095cc27f0SJoerg Sonnenberger 	return;
48195cc27f0SJoerg Sonnenberger 
48295cc27f0SJoerg Sonnenberger error:
48395cc27f0SJoerg Sonnenberger 	set_suspended(1);
48495cc27f0SJoerg Sonnenberger 	packets_dropped ++;
48595cc27f0SJoerg Sonnenberger 	logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
48695cc27f0SJoerg Sonnenberger }
48795cc27f0SJoerg Sonnenberger 
48895cc27f0SJoerg Sonnenberger int
flush_buffer(FILE * f)48995cc27f0SJoerg Sonnenberger flush_buffer(FILE *f)
49095cc27f0SJoerg Sonnenberger {
49195cc27f0SJoerg Sonnenberger 	off_t offset;
49295cc27f0SJoerg Sonnenberger 	int len = bufpos - buffer;
49395cc27f0SJoerg Sonnenberger 
49495cc27f0SJoerg Sonnenberger 	if (len <= 0)
49595cc27f0SJoerg Sonnenberger 		return (0);
49695cc27f0SJoerg Sonnenberger 
49795cc27f0SJoerg Sonnenberger 	offset = ftello(f);
49895cc27f0SJoerg Sonnenberger 	if (offset == (off_t)-1) {
49995cc27f0SJoerg Sonnenberger 		set_suspended(1);
50095cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Logging suspended: ftello: %s",
50195cc27f0SJoerg Sonnenberger 		    strerror(errno));
50295cc27f0SJoerg Sonnenberger 		return (1);
50395cc27f0SJoerg Sonnenberger 	}
50495cc27f0SJoerg Sonnenberger 
50595cc27f0SJoerg Sonnenberger 	if (fwrite(buffer, len, 1, f) != 1) {
50695cc27f0SJoerg Sonnenberger 		set_suspended(1);
50795cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
50895cc27f0SJoerg Sonnenberger 		    strerror(errno));
50995cc27f0SJoerg Sonnenberger 		ftruncate(fileno(f), offset);
51095cc27f0SJoerg Sonnenberger 		return (1);
51195cc27f0SJoerg Sonnenberger 	}
51295cc27f0SJoerg Sonnenberger 
51395cc27f0SJoerg Sonnenberger 	set_suspended(0);
51495cc27f0SJoerg Sonnenberger 	bufpos = buffer;
51595cc27f0SJoerg Sonnenberger 	bufleft = buflen;
51695cc27f0SJoerg Sonnenberger 	bufpkt = 0;
51795cc27f0SJoerg Sonnenberger 
51895cc27f0SJoerg Sonnenberger 	return (0);
51995cc27f0SJoerg Sonnenberger }
52095cc27f0SJoerg Sonnenberger 
52195cc27f0SJoerg Sonnenberger void
purge_buffer(void)52295cc27f0SJoerg Sonnenberger purge_buffer(void)
52395cc27f0SJoerg Sonnenberger {
52495cc27f0SJoerg Sonnenberger 	packets_dropped += bufpkt;
52595cc27f0SJoerg Sonnenberger 
52695cc27f0SJoerg Sonnenberger 	set_suspended(0);
52795cc27f0SJoerg Sonnenberger 	bufpos = buffer;
52895cc27f0SJoerg Sonnenberger 	bufleft = buflen;
52995cc27f0SJoerg Sonnenberger 	bufpkt = 0;
53095cc27f0SJoerg Sonnenberger }
53195cc27f0SJoerg Sonnenberger 
53295cc27f0SJoerg Sonnenberger /* append packet to the buffer, flushing if necessary */
53395cc27f0SJoerg Sonnenberger void
dump_packet(u_char * user,const struct pcap_pkthdr * h,const u_char * sp)53495cc27f0SJoerg Sonnenberger dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
53595cc27f0SJoerg Sonnenberger {
53695cc27f0SJoerg Sonnenberger 	FILE *f = (FILE *)user;
5372461cb13SPeeter 	struct pcap_sf_pkthdr sh;
5382461cb13SPeeter 	size_t len = sizeof(sh) + h->caplen;
53995cc27f0SJoerg Sonnenberger 
54095cc27f0SJoerg Sonnenberger 	if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
541b58f1e66SSascha Wildner 		logmsg(LOG_NOTICE, "invalid size %zd (%u/%u), packet dropped",
54295cc27f0SJoerg Sonnenberger 		       len, cur_snaplen, snaplen);
54395cc27f0SJoerg Sonnenberger 		packets_dropped++;
54495cc27f0SJoerg Sonnenberger 		return;
54595cc27f0SJoerg Sonnenberger 	}
54695cc27f0SJoerg Sonnenberger 
54795cc27f0SJoerg Sonnenberger 	if (len <= bufleft)
54895cc27f0SJoerg Sonnenberger 		goto append;
54995cc27f0SJoerg Sonnenberger 
55095cc27f0SJoerg Sonnenberger 	if (suspended) {
55195cc27f0SJoerg Sonnenberger 		packets_dropped++;
55295cc27f0SJoerg Sonnenberger 		return;
55395cc27f0SJoerg Sonnenberger 	}
55495cc27f0SJoerg Sonnenberger 
55595cc27f0SJoerg Sonnenberger 	if (flush_buffer(f)) {
55695cc27f0SJoerg Sonnenberger 		packets_dropped++;
55795cc27f0SJoerg Sonnenberger 		return;
55895cc27f0SJoerg Sonnenberger 	}
55995cc27f0SJoerg Sonnenberger 
56095cc27f0SJoerg Sonnenberger 	if (len > bufleft) {
56195cc27f0SJoerg Sonnenberger 		dump_packet_nobuf(user, h, sp);
56295cc27f0SJoerg Sonnenberger 		return;
56395cc27f0SJoerg Sonnenberger 	}
56495cc27f0SJoerg Sonnenberger 
56595cc27f0SJoerg Sonnenberger  append:
5662461cb13SPeeter 	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
5672461cb13SPeeter 	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
5682461cb13SPeeter 	sh.caplen = h->caplen;
5692461cb13SPeeter 	sh.len = h->len;
5702461cb13SPeeter 
5712461cb13SPeeter 	memcpy(bufpos, &sh, sizeof(sh));
5722461cb13SPeeter 	memcpy(bufpos + sizeof(sh), sp, h->caplen);
57395cc27f0SJoerg Sonnenberger 
57495cc27f0SJoerg Sonnenberger 	bufpos += len;
57595cc27f0SJoerg Sonnenberger 	bufleft -= len;
57695cc27f0SJoerg Sonnenberger 	bufpkt++;
57795cc27f0SJoerg Sonnenberger 
57895cc27f0SJoerg Sonnenberger 	return;
57995cc27f0SJoerg Sonnenberger }
58095cc27f0SJoerg Sonnenberger 
581e437855fSPeeter void
log_pcap_stats(void)582e437855fSPeeter log_pcap_stats(void)
583e437855fSPeeter {
584e437855fSPeeter 	struct pcap_stat pstat;
585e437855fSPeeter 	if (pcap_stats(hpcap, &pstat) < 0)
586e437855fSPeeter 		logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
587e437855fSPeeter 	else
588e437855fSPeeter 		logmsg(LOG_NOTICE,
589e437855fSPeeter                "%u packets received, %u/%ld dropped (kernel/pflogd)",
590e437855fSPeeter                pstat.ps_recv, pstat.ps_drop, packets_dropped);
591e437855fSPeeter }
592e437855fSPeeter 
59395cc27f0SJoerg Sonnenberger int
main(int argc,char ** argv)59495cc27f0SJoerg Sonnenberger main(int argc, char **argv)
59595cc27f0SJoerg Sonnenberger {
596315a7da3SJan Lentfer 	int ch, np, ret, Xflag = 0;
59795cc27f0SJoerg Sonnenberger 	pcap_handler phandler = dump_packet;
598c929e0dfSJan Lentfer 	const char *errstr = NULL;
599d316f7c9SJohn Marino 	struct pidfh *pfh = NULL;
600315a7da3SJan Lentfer 	char *pidf = NULL;
60195cc27f0SJoerg Sonnenberger 
602a8838a5fSSascha Wildner 	ret = 0;
603a8838a5fSSascha Wildner 
60495cc27f0SJoerg Sonnenberger 	/* Neither FreeBSD nor DFly have this; Max seems to think this may
60595cc27f0SJoerg Sonnenberger 	 * be a paranoid check. Comment it out:
60695cc27f0SJoerg Sonnenberger 	closefrom(STDERR_FILENO + 1);
60795cc27f0SJoerg Sonnenberger 	 */
60895cc27f0SJoerg Sonnenberger 
609315a7da3SJan Lentfer 	while ((ch = getopt(argc, argv, "Dxd:f:i:p:s:")) != -1) {
61095cc27f0SJoerg Sonnenberger 		switch (ch) {
61195cc27f0SJoerg Sonnenberger 		case 'D':
61295cc27f0SJoerg Sonnenberger 			Debug = 1;
61395cc27f0SJoerg Sonnenberger 			break;
61495cc27f0SJoerg Sonnenberger 		case 'd':
615c929e0dfSJan Lentfer 			delay = strtonum(optarg, 5, 60*60, &errstr);
616c929e0dfSJan Lentfer 			if (errstr)
61795cc27f0SJoerg Sonnenberger 				usage();
61895cc27f0SJoerg Sonnenberger 			break;
61995cc27f0SJoerg Sonnenberger 		case 'f':
62095cc27f0SJoerg Sonnenberger 			filename = optarg;
62195cc27f0SJoerg Sonnenberger 			break;
622c929e0dfSJan Lentfer 		case 'i':
623c929e0dfSJan Lentfer 			interface = optarg;
624c929e0dfSJan Lentfer 			break;
625315a7da3SJan Lentfer 		case 'p':
626315a7da3SJan Lentfer 			pidf = optarg;
627315a7da3SJan Lentfer 			break;
62895cc27f0SJoerg Sonnenberger 		case 's':
629c929e0dfSJan Lentfer 			snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
630c929e0dfSJan Lentfer 			    &errstr);
63195cc27f0SJoerg Sonnenberger 			if (snaplen <= 0)
63295cc27f0SJoerg Sonnenberger 				snaplen = DEF_SNAPLEN;
633c929e0dfSJan Lentfer 			if (errstr)
63495cc27f0SJoerg Sonnenberger 				snaplen = PFLOGD_MAXSNAPLEN;
63595cc27f0SJoerg Sonnenberger 			break;
63695cc27f0SJoerg Sonnenberger 		case 'x':
63795cc27f0SJoerg Sonnenberger 			Xflag++;
63895cc27f0SJoerg Sonnenberger 			break;
63995cc27f0SJoerg Sonnenberger 		default:
64095cc27f0SJoerg Sonnenberger 			usage();
64195cc27f0SJoerg Sonnenberger 		}
64295cc27f0SJoerg Sonnenberger 
64395cc27f0SJoerg Sonnenberger 	}
64495cc27f0SJoerg Sonnenberger 
64595cc27f0SJoerg Sonnenberger 	log_debug = Debug;
64695cc27f0SJoerg Sonnenberger 	argc -= optind;
64795cc27f0SJoerg Sonnenberger 	argv += optind;
64895cc27f0SJoerg Sonnenberger 
649315a7da3SJan Lentfer 	/* does interface exist */
650315a7da3SJan Lentfer 	if (!if_exists(__DECONST(char *, interface))) {
651315a7da3SJan Lentfer 		warn("Failed to initialize: %s", interface);
652315a7da3SJan Lentfer 		logmsg(LOG_ERR, "Failed to initialize: %s", interface);
653315a7da3SJan Lentfer 		logmsg(LOG_ERR, "Exiting, init failure");
654315a7da3SJan Lentfer 		exit(1);
655315a7da3SJan Lentfer 	}
656315a7da3SJan Lentfer 
65795cc27f0SJoerg Sonnenberger 	if (!Debug) {
65895cc27f0SJoerg Sonnenberger 		openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
659d316f7c9SJohn Marino 		pfh = pidfile_open(pidf, 0600, NULL);
66095cc27f0SJoerg Sonnenberger 		if (daemon(0, 0)) {
66195cc27f0SJoerg Sonnenberger 			logmsg(LOG_WARNING, "Failed to become daemon: %s",
66295cc27f0SJoerg Sonnenberger 			    strerror(errno));
66395cc27f0SJoerg Sonnenberger 		}
664d316f7c9SJohn Marino 		pidfile_write(pfh);
66595cc27f0SJoerg Sonnenberger 	}
66695cc27f0SJoerg Sonnenberger 
667e437855fSPeeter 	tzset();
66871126e33SSascha Wildner 	umask(S_IRWXG | S_IRWXO);
66995cc27f0SJoerg Sonnenberger 
67095cc27f0SJoerg Sonnenberger 	/* filter will be used by the privileged process */
67195cc27f0SJoerg Sonnenberger 	if (argc) {
67295cc27f0SJoerg Sonnenberger 		filter = copy_argv(argv);
67395cc27f0SJoerg Sonnenberger 		if (filter == NULL)
67495cc27f0SJoerg Sonnenberger 			logmsg(LOG_NOTICE, "Failed to form filter expression");
67595cc27f0SJoerg Sonnenberger 	}
67695cc27f0SJoerg Sonnenberger 
67795cc27f0SJoerg Sonnenberger 	/* initialize pcap before dropping privileges */
67895cc27f0SJoerg Sonnenberger 	if (init_pcap()) {
67995cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Exiting, init failure");
68095cc27f0SJoerg Sonnenberger 		exit(1);
68195cc27f0SJoerg Sonnenberger 	}
68295cc27f0SJoerg Sonnenberger 
68395cc27f0SJoerg Sonnenberger 	/* Privilege separation begins here */
68495cc27f0SJoerg Sonnenberger 	if (priv_init()) {
68595cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "unable to privsep");
68695cc27f0SJoerg Sonnenberger 		exit(1);
68795cc27f0SJoerg Sonnenberger 	}
68895cc27f0SJoerg Sonnenberger 
68995cc27f0SJoerg Sonnenberger 	setproctitle("[initializing]");
69095cc27f0SJoerg Sonnenberger 	/* Process is now unprivileged and inside a chroot */
69195cc27f0SJoerg Sonnenberger 	signal(SIGTERM, sig_close);
69295cc27f0SJoerg Sonnenberger 	signal(SIGINT, sig_close);
69395cc27f0SJoerg Sonnenberger 	signal(SIGQUIT, sig_close);
69495cc27f0SJoerg Sonnenberger 	signal(SIGALRM, sig_alrm);
695e437855fSPeeter 	signal(SIGUSR1, sig_usr1);
69695cc27f0SJoerg Sonnenberger 	signal(SIGHUP, sig_hup);
69795cc27f0SJoerg Sonnenberger 	alarm(delay);
69895cc27f0SJoerg Sonnenberger 
69995cc27f0SJoerg Sonnenberger 	buffer = malloc(PFLOGD_BUFSIZE);
70095cc27f0SJoerg Sonnenberger 
70195cc27f0SJoerg Sonnenberger 	if (buffer == NULL) {
70295cc27f0SJoerg Sonnenberger 		logmsg(LOG_WARNING, "Failed to allocate output buffer");
70395cc27f0SJoerg Sonnenberger 		phandler = dump_packet_nobuf;
70495cc27f0SJoerg Sonnenberger 	} else {
70595cc27f0SJoerg Sonnenberger 		bufleft = buflen = PFLOGD_BUFSIZE;
70695cc27f0SJoerg Sonnenberger 		bufpos = buffer;
70795cc27f0SJoerg Sonnenberger 		bufpkt = 0;
70895cc27f0SJoerg Sonnenberger 	}
70995cc27f0SJoerg Sonnenberger 
710c929e0dfSJan Lentfer 	if (reset_dump(Xflag) < 0) {
71195cc27f0SJoerg Sonnenberger 		if (Xflag)
71295cc27f0SJoerg Sonnenberger 			return (1);
71395cc27f0SJoerg Sonnenberger 
71495cc27f0SJoerg Sonnenberger 		logmsg(LOG_ERR, "Logging suspended: open error");
71595cc27f0SJoerg Sonnenberger 		set_suspended(1);
71695cc27f0SJoerg Sonnenberger 	} else if (Xflag)
71795cc27f0SJoerg Sonnenberger 		return (0);
71895cc27f0SJoerg Sonnenberger 
71995cc27f0SJoerg Sonnenberger 	while (1) {
72095cc27f0SJoerg Sonnenberger 		np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
721c929e0dfSJan Lentfer 		    phandler, (u_char *)dpcap);
722315a7da3SJan Lentfer 		if (np < 0) {
7234bb97943SSascha Wildner 			if (!if_exists(__DECONST(char *, interface))) {
724315a7da3SJan Lentfer 				logmsg(LOG_NOTICE, "interface %s went away",
725315a7da3SJan Lentfer 				    interface);
726315a7da3SJan Lentfer 				ret = -1;
727315a7da3SJan Lentfer 				break;
728315a7da3SJan Lentfer 			}
72995cc27f0SJoerg Sonnenberger 			logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
730315a7da3SJan Lentfer 		}
73195cc27f0SJoerg Sonnenberger 
73295cc27f0SJoerg Sonnenberger 		if (gotsig_close)
73395cc27f0SJoerg Sonnenberger 			break;
73495cc27f0SJoerg Sonnenberger 		if (gotsig_hup) {
735c929e0dfSJan Lentfer 			if (reset_dump(0)) {
73695cc27f0SJoerg Sonnenberger 				logmsg(LOG_ERR,
73795cc27f0SJoerg Sonnenberger 				    "Logging suspended: open error");
73895cc27f0SJoerg Sonnenberger 				set_suspended(1);
73995cc27f0SJoerg Sonnenberger 			}
74095cc27f0SJoerg Sonnenberger 			gotsig_hup = 0;
74195cc27f0SJoerg Sonnenberger 		}
74295cc27f0SJoerg Sonnenberger 
74395cc27f0SJoerg Sonnenberger 		if (gotsig_alrm) {
74495cc27f0SJoerg Sonnenberger 			if (dpcap)
74595cc27f0SJoerg Sonnenberger 				flush_buffer(dpcap);
746c929e0dfSJan Lentfer 			else
747c929e0dfSJan Lentfer 				gotsig_hup = 1;
74895cc27f0SJoerg Sonnenberger 			gotsig_alrm = 0;
74995cc27f0SJoerg Sonnenberger 			alarm(delay);
75095cc27f0SJoerg Sonnenberger 		}
751e437855fSPeeter 
752e437855fSPeeter 		if (gotsig_usr1) {
753e437855fSPeeter 			log_pcap_stats();
754e437855fSPeeter 			gotsig_usr1 = 0;
755e437855fSPeeter 		}
75695cc27f0SJoerg Sonnenberger 	}
75795cc27f0SJoerg Sonnenberger 
75895cc27f0SJoerg Sonnenberger 	logmsg(LOG_NOTICE, "Exiting");
75995cc27f0SJoerg Sonnenberger 	if (dpcap) {
76095cc27f0SJoerg Sonnenberger 		flush_buffer(dpcap);
76195cc27f0SJoerg Sonnenberger 		fclose(dpcap);
76295cc27f0SJoerg Sonnenberger 	}
76395cc27f0SJoerg Sonnenberger 	purge_buffer();
76495cc27f0SJoerg Sonnenberger 
765e437855fSPeeter 	log_pcap_stats();
76695cc27f0SJoerg Sonnenberger 	pcap_close(hpcap);
76795cc27f0SJoerg Sonnenberger 	if (!Debug)
76895cc27f0SJoerg Sonnenberger 		closelog();
769315a7da3SJan Lentfer 	return (ret);
77095cc27f0SJoerg Sonnenberger }
771