1139823Simp/*	$OpenBSD: pflogd.c,v 1.46 2008/10/22 08:16:49 henning Exp $	*/
217352Swollman
317352Swollman/*
417352Swollman * Copyright (c) 2001 Theo de Raadt
517352Swollman * Copyright (c) 2001 Can Erkin Acar
617352Swollman * All rights reserved.
717352Swollman *
817352Swollman * Redistribution and use in source and binary forms, with or without
917352Swollman * modification, are permitted provided that the following conditions
1017352Swollman * are met:
1117352Swollman *
1217352Swollman *    - Redistributions of source code must retain the above copyright
1317352Swollman *      notice, this list of conditions and the following disclaimer.
1417352Swollman *    - Redistributions in binary form must reproduce the above
1517352Swollman *      copyright notice, this list of conditions and the following
1617352Swollman *      disclaimer in the documentation and/or other materials provided
1717352Swollman *      with the distribution.
1817352Swollman *
1917352Swollman * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2017352Swollman * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2117352Swollman * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2217352Swollman * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2317352Swollman * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2417352Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2517352Swollman * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2617352Swollman * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2717352Swollman * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2817352Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2950477Speter * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3017352Swollman * POSSIBILITY OF SUCH DAMAGE.
3117352Swollman */
3217352Swollman
3317352Swollman#include <sys/cdefs.h>
3417352Swollman__FBSDID("$FreeBSD$");
3517352Swollman
3617352Swollman#include <sys/types.h>
3717352Swollman#include <sys/ioctl.h>
3817352Swollman#include <sys/file.h>
3917352Swollman#include <sys/stat.h>
4017352Swollman#include <sys/socket.h>
4117352Swollman#include <net/if.h>
4217871Swollman#include <stdio.h>
4317871Swollman#include <stdlib.h>
4417352Swollman#include <string.h>
4517352Swollman#include <unistd.h>
4617352Swollman#include <pcap-int.h>
4717352Swollman#include <pcap.h>
4817352Swollman#include <syslog.h>
4917352Swollman#include <signal.h>
5017352Swollman#include <err.h>
5117352Swollman#include <errno.h>
5217352Swollman#include <stdarg.h>
5317352Swollman#include <fcntl.h>
5417352Swollman#ifdef __FreeBSD__
5517352Swollman#include <ifaddrs.h>
5617352Swollman#include "pidfile.h"
57154023Sharti#else
5817352Swollman#include <util.h>
5917352Swollman#endif
6017352Swollman#include "pflogd.h"
6117352Swollman
6217352Swollmanpcap_t *hpcap;
6317352Swollmanstatic FILE *dpcap;
6417352Swollman
6517352Swollmanint Debug = 0;
6617352Swollmanstatic int snaplen = DEF_SNAPLEN;
6717352Swollmanstatic int cur_snaplen = DEF_SNAPLEN;
6817352Swollman
6917352Swollmanvolatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup, gotsig_usr1;
7017352Swollman
7117352Swollmanchar *filename = PFLOGD_LOG_FILE;
7217352Swollmanchar *interface = PFLOGD_DEFAULT_IF;
7317352Swollmanchar *filter = NULL;
7417352Swollman
7517352Swollmanchar errbuf[PCAP_ERRBUF_SIZE];
7617352Swollman
7717352Swollmanint log_debug = 0;
7817352Swollmanunsigned int delay = FLUSH_DELAY;
7917352Swollman
8017871Swollmanchar *copy_argv(char * const *);
8117871Swollmanvoid  dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
8217871Swollmanvoid  dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
8317871Swollmanvoid  log_pcap_stats(void);
8417871Swollmanint   flush_buffer(FILE *);
8517871Swollmanint   if_exists(char *);
8617871Swollmanint   init_pcap(void);
8717871Swollmanvoid  logmsg(int, const char *, ...);
8817871Swollmanvoid  purge_buffer(void);
8917871Swollmanint   reset_dump(int);
9017871Swollmanint   scan_dump(FILE *, off_t);
9117871Swollmanint   set_snaplen(int);
9217871Swollmanvoid  set_suspended(int);
9317871Swollmanvoid  sig_alrm(int);
9417871Swollmanvoid  sig_usr1(int);
9517871Swollmanvoid  sig_close(int);
9617871Swollmanvoid  sig_hup(int);
9717871Swollmanvoid  usage(void);
9817871Swollman
9917871Swollmanstatic int try_reset_dump(int);
10017871Swollman
10117871Swollman/* buffer must always be greater than snaplen */
10217871Swollmanstatic int    bufpkt = 0;	/* number of packets in buffer */
10317871Swollmanstatic int    buflen = 0;	/* allocated size of buffer */
10417871Swollmanstatic char  *buffer = NULL;	/* packet buffer */
10517871Swollmanstatic char  *bufpos = NULL;	/* position in buffer */
10617871Swollmanstatic int    bufleft = 0;	/* bytes left in buffer */
10717871Swollman
10817871Swollman/* if error, stop logging but count dropped packets */
10917871Swollmanstatic int suspended = -1;
11017871Swollmanstatic long packets_dropped = 0;
11117871Swollman
11217871Swollmanvoid
11317871Swollmanset_suspended(int s)
11417871Swollman{
11517871Swollman	if (suspended == s)
11617871Swollman		return;
11717871Swollman
11817871Swollman	suspended = s;
11917871Swollman	setproctitle("[%s] -s %d -i %s -f %s",
12017871Swollman	    suspended ? "suspended" : "running",
12117871Swollman	    cur_snaplen, interface, filename);
12217871Swollman}
12317871Swollman
12417871Swollmanchar *
12517871Swollmancopy_argv(char * const *argv)
12617871Swollman{
12717871Swollman	size_t len = 0, n;
12820653Sbde	char *buf;
12917871Swollman
13017871Swollman	if (argv == NULL)
13117871Swollman		return (NULL);
13217871Swollman
13317871Swollman	for (n = 0; argv[n]; n++)
13417871Swollman		len += strlen(argv[n])+1;
13517871Swollman	if (len == 0)
13617871Swollman		return (NULL);
13717871Swollman
13817871Swollman	buf = malloc(len);
13917871Swollman	if (buf == NULL)
14017871Swollman		return (NULL);
14117871Swollman
14217871Swollman	strlcpy(buf, argv[0], len);
14317871Swollman	for (n = 1; argv[n]; n++) {
14417871Swollman		strlcat(buf, " ", len);
14517871Swollman		strlcat(buf, argv[n], len);
14617871Swollman	}
14717871Swollman	return (buf);
14817871Swollman}
14917871Swollman
15017871Swollmanvoid
15117871Swollmanlogmsg(int pri, const char *message, ...)
15217871Swollman{
15317871Swollman	va_list ap;
15417871Swollman	va_start(ap, message);
15517871Swollman
15617871Swollman	if (log_debug) {
15717871Swollman		vfprintf(stderr, message, ap);
15817871Swollman		fprintf(stderr, "\n");
15917871Swollman	} else
16017871Swollman		vsyslog(pri, message, ap);
16117871Swollman	va_end(ap);
16217871Swollman}
16317871Swollman
16417871Swollman#ifdef __FreeBSD__
16517871Swollman__dead2 void
16617871Swollman#else
16717871Swollman__dead void
16817871Swollman#endif
16917871Swollmanusage(void)
17017871Swollman{
17117352Swollman	fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
172	fprintf(stderr, " [-i interface] [-p pidfile]\n");
173	fprintf(stderr, "              [-s snaplen] [expression]\n");
174	exit(1);
175}
176
177void
178sig_close(int sig)
179{
180	gotsig_close = 1;
181}
182
183void
184sig_hup(int sig)
185{
186	gotsig_hup = 1;
187}
188
189void
190sig_alrm(int sig)
191{
192	gotsig_alrm = 1;
193}
194
195void
196sig_usr1(int sig)
197{
198	gotsig_usr1 = 1;
199}
200
201void
202set_pcap_filter(void)
203{
204	struct bpf_program bprog;
205
206	if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
207		logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
208	else {
209		if (pcap_setfilter(hpcap, &bprog) < 0)
210			logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
211		pcap_freecode(&bprog);
212	}
213}
214
215int
216if_exists(char *ifname)
217{
218#ifdef __FreeBSD__
219	struct ifaddrs *ifdata, *mb;
220	int exists = 0;
221
222	getifaddrs(&ifdata);
223        if (ifdata == NULL)
224		return (0);
225
226	for (mb = ifdata; mb != NULL; mb = mb->ifa_next) {
227		if (mb == NULL)
228			continue;
229		if (strlen(ifname) != strlen(mb->ifa_name))
230			continue;
231		if (strncmp(ifname, mb->ifa_name, strlen(ifname)) != 0)
232			continue;
233		exists = 1;
234		break;
235	}
236	freeifaddrs(ifdata);
237
238	return (exists);
239#else
240	int s;
241	struct ifreq ifr;
242	struct if_data ifrdat;
243
244	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
245		err(1, "socket");
246	bzero(&ifr, sizeof(ifr));
247	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
248		sizeof(ifr.ifr_name))
249			errx(1, "main ifr_name: strlcpy");
250	ifr.ifr_data = (caddr_t)&ifrdat;
251	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
252		return (0);
253	if (close(s))
254		err(1, "close");
255
256	return (1);
257#endif
258}
259
260int
261init_pcap(void)
262{
263	hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
264	if (hpcap == NULL) {
265		logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
266		return (-1);
267	}
268
269	if (pcap_datalink(hpcap) != DLT_PFLOG) {
270		logmsg(LOG_ERR, "Invalid datalink type");
271		pcap_close(hpcap);
272		hpcap = NULL;
273		return (-1);
274	}
275
276	set_pcap_filter();
277
278	cur_snaplen = snaplen = pcap_snapshot(hpcap);
279
280	/* lock */
281	if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
282		logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
283		return (-1);
284	}
285
286	return (0);
287}
288
289int
290set_snaplen(int snap)
291{
292	if (priv_set_snaplen(snap))
293		return (1);
294
295	if (cur_snaplen > snap)
296		purge_buffer();
297
298	cur_snaplen = snap;
299
300	return (0);
301}
302
303int
304reset_dump(int nomove)
305{
306	int ret;
307
308	for (;;) {
309		ret = try_reset_dump(nomove);
310		if (ret <= 0)
311			break;
312	}
313
314	return (ret);
315}
316
317/*
318 * tries to (re)open log file, nomove flag is used with -x switch
319 * returns 0: success, 1: retry (log moved), -1: error
320 */
321int
322try_reset_dump(int nomove)
323{
324	struct pcap_file_header hdr;
325	struct stat st;
326	int fd;
327	FILE *fp;
328
329	if (hpcap == NULL)
330		return (-1);
331
332	if (dpcap) {
333		flush_buffer(dpcap);
334		fclose(dpcap);
335		dpcap = NULL;
336	}
337
338	/*
339	 * Basically reimplement pcap_dump_open() because it truncates
340	 * files and duplicates headers and such.
341	 */
342	fd = priv_open_log();
343	if (fd < 0)
344		return (-1);
345
346	fp = fdopen(fd, "a+");
347
348	if (fp == NULL) {
349		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
350		close(fd);
351		return (-1);
352	}
353	if (fstat(fileno(fp), &st) == -1) {
354		logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
355		fclose(fp);
356		return (-1);
357	}
358
359	/* set FILE unbuffered, we do our own buffering */
360	if (setvbuf(fp, NULL, _IONBF, 0)) {
361		logmsg(LOG_ERR, "Failed to set output buffers");
362		fclose(fp);
363		return (-1);
364	}
365
366#define TCPDUMP_MAGIC 0xa1b2c3d4
367
368	if (st.st_size == 0) {
369		if (snaplen != cur_snaplen) {
370			logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
371			if (set_snaplen(snaplen))
372				logmsg(LOG_WARNING,
373				    "Failed, using old settings");
374		}
375		hdr.magic = TCPDUMP_MAGIC;
376		hdr.version_major = PCAP_VERSION_MAJOR;
377		hdr.version_minor = PCAP_VERSION_MINOR;
378		hdr.thiszone = hpcap->tzoff;
379		hdr.snaplen = hpcap->snapshot;
380		hdr.sigfigs = 0;
381		hdr.linktype = hpcap->linktype;
382
383		if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
384			fclose(fp);
385			return (-1);
386		}
387	} else if (scan_dump(fp, st.st_size)) {
388		fclose(fp);
389		if (nomove || priv_move_log()) {
390			logmsg(LOG_ERR,
391			    "Invalid/incompatible log file, move it away");
392			return (-1);
393		}
394		return (1);
395	}
396
397	dpcap = fp;
398
399	set_suspended(0);
400	flush_buffer(fp);
401
402	return (0);
403}
404
405int
406scan_dump(FILE *fp, off_t size)
407{
408	struct pcap_file_header hdr;
409#ifdef __FreeBSD__
410	struct pcap_sf_pkthdr ph;
411#else
412	struct pcap_pkthdr ph;
413#endif
414	off_t pos;
415
416	/*
417	 * Must read the file, compare the header against our new
418	 * options (in particular, snaplen) and adjust our options so
419	 * that we generate a correct file. Furthermore, check the file
420	 * for consistency so that we can append safely.
421	 *
422	 * XXX this may take a long time for large logs.
423	 */
424	(void) fseek(fp, 0L, SEEK_SET);
425
426	if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
427		logmsg(LOG_ERR, "Short file header");
428		return (1);
429	}
430
431	if (hdr.magic != TCPDUMP_MAGIC ||
432	    hdr.version_major != PCAP_VERSION_MAJOR ||
433	    hdr.version_minor != PCAP_VERSION_MINOR ||
434	    hdr.linktype != hpcap->linktype ||
435	    hdr.snaplen > PFLOGD_MAXSNAPLEN) {
436		return (1);
437	}
438
439	pos = sizeof(hdr);
440
441	while (!feof(fp)) {
442		off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
443		if (len == 0)
444			break;
445
446		if (len != sizeof(ph))
447			goto error;
448		if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
449			goto error;
450		pos += sizeof(ph) + ph.caplen;
451		if (pos > size)
452			goto error;
453		fseek(fp, ph.caplen, SEEK_CUR);
454	}
455
456	if (pos != size)
457		goto error;
458
459	if (hdr.snaplen != cur_snaplen) {
460		logmsg(LOG_WARNING,
461		       "Existing file has different snaplen %u, using it",
462		       hdr.snaplen);
463		if (set_snaplen(hdr.snaplen)) {
464			logmsg(LOG_WARNING,
465			       "Failed, using old settings, offset %llu",
466			       (unsigned long long) size);
467		}
468	}
469
470	return (0);
471
472 error:
473	logmsg(LOG_ERR, "Corrupted log file.");
474	return (1);
475}
476
477/* dump a packet directly to the stream, which is unbuffered */
478void
479dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
480{
481	FILE *f = (FILE *)user;
482#ifdef __FreeBSD__
483	struct pcap_sf_pkthdr sh;
484#endif
485
486	if (suspended) {
487		packets_dropped++;
488		return;
489	}
490
491#ifdef __FreeBSD__
492	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
493	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
494	sh.caplen = h->caplen;
495	sh.len = h->len;
496
497	if (fwrite((char *)&sh, sizeof(sh), 1, f) != 1) {
498#else
499	if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
500#endif
501		off_t pos = ftello(f);
502
503		/* try to undo header to prevent corruption */
504#ifdef __FreeBSD__
505		if (pos < sizeof(sh) ||
506		    ftruncate(fileno(f), pos - sizeof(sh))) {
507#else
508		if (pos < sizeof(*h) ||
509		    ftruncate(fileno(f), pos - sizeof(*h))) {
510#endif
511			logmsg(LOG_ERR, "Write failed, corrupted logfile!");
512			set_suspended(1);
513			gotsig_close = 1;
514			return;
515		}
516		goto error;
517	}
518
519	if (fwrite((char *)sp, h->caplen, 1, f) != 1)
520		goto error;
521
522	return;
523
524error:
525	set_suspended(1);
526	packets_dropped ++;
527	logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
528}
529
530int
531flush_buffer(FILE *f)
532{
533	off_t offset;
534	int len = bufpos - buffer;
535
536	if (len <= 0)
537		return (0);
538
539	offset = ftello(f);
540	if (offset == (off_t)-1) {
541		set_suspended(1);
542		logmsg(LOG_ERR, "Logging suspended: ftello: %s",
543		    strerror(errno));
544		return (1);
545	}
546
547	if (fwrite(buffer, len, 1, f) != 1) {
548		set_suspended(1);
549		logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
550		    strerror(errno));
551		ftruncate(fileno(f), offset);
552		return (1);
553	}
554
555	set_suspended(0);
556	bufpos = buffer;
557	bufleft = buflen;
558	bufpkt = 0;
559
560	return (0);
561}
562
563void
564purge_buffer(void)
565{
566	packets_dropped += bufpkt;
567
568	set_suspended(0);
569	bufpos = buffer;
570	bufleft = buflen;
571	bufpkt = 0;
572}
573
574/* append packet to the buffer, flushing if necessary */
575void
576dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
577{
578	FILE *f = (FILE *)user;
579#ifdef __FreeBSD__
580	struct pcap_sf_pkthdr sh;
581	size_t len = sizeof(sh) + h->caplen;
582#else
583	size_t len = sizeof(*h) + h->caplen;
584#endif
585
586	if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
587		logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped",
588		       len, cur_snaplen, snaplen);
589		packets_dropped++;
590		return;
591	}
592
593	if (len <= bufleft)
594		goto append;
595
596	if (suspended) {
597		packets_dropped++;
598		return;
599	}
600
601	if (flush_buffer(f)) {
602		packets_dropped++;
603		return;
604	}
605
606	if (len > bufleft) {
607		dump_packet_nobuf(user, h, sp);
608		return;
609	}
610
611 append:
612#ifdef __FreeBSD__
613	sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
614	sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
615	sh.caplen = h->caplen;
616	sh.len = h->len;
617
618	memcpy(bufpos, &sh, sizeof(sh));
619	memcpy(bufpos + sizeof(sh), sp, h->caplen);
620#else
621	memcpy(bufpos, h, sizeof(*h));
622	memcpy(bufpos + sizeof(*h), sp, h->caplen);
623#endif
624
625	bufpos += len;
626	bufleft -= len;
627	bufpkt++;
628
629	return;
630}
631
632void
633log_pcap_stats(void)
634{
635	struct pcap_stat pstat;
636	if (pcap_stats(hpcap, &pstat) < 0)
637		logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
638	else
639		logmsg(LOG_NOTICE,
640			"%u packets received, %u/%u dropped (kernel/pflogd)",
641			pstat.ps_recv, pstat.ps_drop, packets_dropped);
642}
643
644int
645main(int argc, char **argv)
646{
647	int ch, np, ret, Xflag = 0;
648	pcap_handler phandler = dump_packet;
649	const char *errstr = NULL;
650	char *pidf = NULL;
651
652	ret = 0;
653
654	closefrom(STDERR_FILENO + 1);
655
656	while ((ch = getopt(argc, argv, "Dxd:f:i:p:s:")) != -1) {
657		switch (ch) {
658		case 'D':
659			Debug = 1;
660			break;
661		case 'd':
662			delay = strtonum(optarg, 5, 60*60, &errstr);
663			if (errstr)
664				usage();
665			break;
666		case 'f':
667			filename = optarg;
668			break;
669		case 'i':
670			interface = optarg;
671			break;
672		case 'p':
673			pidf = optarg;
674			break;
675		case 's':
676			snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
677			    &errstr);
678			if (snaplen <= 0)
679				snaplen = DEF_SNAPLEN;
680			if (errstr)
681				snaplen = PFLOGD_MAXSNAPLEN;
682			break;
683		case 'x':
684			Xflag++;
685			break;
686		default:
687			usage();
688		}
689
690	}
691
692	log_debug = Debug;
693	argc -= optind;
694	argv += optind;
695
696	/* does interface exist */
697	if (!if_exists(interface)) {
698		warn("Failed to initialize: %s", interface);
699		logmsg(LOG_ERR, "Failed to initialize: %s", interface);
700		logmsg(LOG_ERR, "Exiting, init failure");
701		exit(1);
702	}
703
704	if (!Debug) {
705		openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
706		if (daemon(0, 0)) {
707			logmsg(LOG_WARNING, "Failed to become daemon: %s",
708			    strerror(errno));
709		}
710		pidfile(pidf);
711	}
712
713	tzset();
714	(void)umask(S_IRWXG | S_IRWXO);
715
716	/* filter will be used by the privileged process */
717	if (argc) {
718		filter = copy_argv(argv);
719		if (filter == NULL)
720			logmsg(LOG_NOTICE, "Failed to form filter expression");
721	}
722
723	/* initialize pcap before dropping privileges */
724	if (init_pcap()) {
725		logmsg(LOG_ERR, "Exiting, init failure");
726		exit(1);
727	}
728
729	/* Privilege separation begins here */
730	if (priv_init()) {
731		logmsg(LOG_ERR, "unable to privsep");
732		exit(1);
733	}
734
735	setproctitle("[initializing]");
736	/* Process is now unprivileged and inside a chroot */
737	signal(SIGTERM, sig_close);
738	signal(SIGINT, sig_close);
739	signal(SIGQUIT, sig_close);
740	signal(SIGALRM, sig_alrm);
741	signal(SIGUSR1, sig_usr1);
742	signal(SIGHUP, sig_hup);
743	alarm(delay);
744
745	buffer = malloc(PFLOGD_BUFSIZE);
746
747	if (buffer == NULL) {
748		logmsg(LOG_WARNING, "Failed to allocate output buffer");
749		phandler = dump_packet_nobuf;
750	} else {
751		bufleft = buflen = PFLOGD_BUFSIZE;
752		bufpos = buffer;
753		bufpkt = 0;
754	}
755
756	if (reset_dump(Xflag) < 0) {
757		if (Xflag)
758			return (1);
759
760		logmsg(LOG_ERR, "Logging suspended: open error");
761		set_suspended(1);
762	} else if (Xflag)
763		return (0);
764
765	while (1) {
766		np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
767		    phandler, (u_char *)dpcap);
768		if (np < 0) {
769			if (!if_exists(interface) == -1) {
770				logmsg(LOG_NOTICE, "interface %s went away",
771				    interface);
772				ret = -1;
773				break;
774			}
775			logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
776		}
777
778		if (gotsig_close)
779			break;
780		if (gotsig_hup) {
781			if (reset_dump(0)) {
782				logmsg(LOG_ERR,
783				    "Logging suspended: open error");
784				set_suspended(1);
785			}
786			gotsig_hup = 0;
787		}
788
789		if (gotsig_alrm) {
790			if (dpcap)
791				flush_buffer(dpcap);
792			else
793				gotsig_hup = 1;
794			gotsig_alrm = 0;
795			alarm(delay);
796		}
797
798		if (gotsig_usr1) {
799			log_pcap_stats();
800			gotsig_usr1 = 0;
801		}
802	}
803
804	logmsg(LOG_NOTICE, "Exiting");
805	if (dpcap) {
806		flush_buffer(dpcap);
807		fclose(dpcap);
808	}
809	purge_buffer();
810
811	log_pcap_stats();
812	pcap_close(hpcap);
813	if (!Debug)
814		closelog();
815	return (ret);
816}
817