1 /* $OpenBSD: pflogd.c,v 1.46 2008/10/22 08:16:49 henning Exp $ */
2
3 /*
4 * Copyright (c) 2001 Theo de Raadt
5 * Copyright (c) 2001 Can Erkin Acar
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * - Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <sys/file.h>
36 #include <sys/stat.h>
37 #include <sys/socket.h>
38 #include <net/if.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <pcap-int.h>
44 #include <pcap.h>
45 #include <syslog.h>
46 #include <signal.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <stdarg.h>
50 #include <fcntl.h>
51 #ifdef __FreeBSD__
52 #include <ifaddrs.h>
53 #include "pidfile.h"
54 #else
55 #include <util.h>
56 #endif
57 #include "pflogd.h"
58
59 pcap_t *hpcap;
60 static FILE *dpcap;
61
62 int Debug = 0;
63 static int snaplen = DEF_SNAPLEN;
64 static int cur_snaplen = DEF_SNAPLEN;
65
66 volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup, gotsig_usr1;
67
68 char *filename = PFLOGD_LOG_FILE;
69 char *interface = PFLOGD_DEFAULT_IF;
70 char *filter = NULL;
71
72 char errbuf[PCAP_ERRBUF_SIZE];
73
74 int log_debug = 0;
75 unsigned int delay = FLUSH_DELAY;
76
77 struct pcap_timeval {
78 bpf_u_int32 tv_sec; /* seconds */
79 bpf_u_int32 tv_usec; /* microseconds */
80 };
81
82 struct pcap_sf_pkthdr {
83 struct pcap_timeval ts; /* time stamp */
84 bpf_u_int32 caplen; /* length of portion present */
85 bpf_u_int32 len; /* length of this packet (off wire) */
86 };
87
88 char *copy_argv(char * const *);
89 void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
90 void dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
91 void log_pcap_stats(void);
92 int flush_buffer(FILE *);
93 int if_exists(char *);
94 int init_pcap(void);
95 void logmsg(int, const char *, ...);
96 void purge_buffer(void);
97 int reset_dump(int);
98 int scan_dump(FILE *, off_t);
99 int set_snaplen(int);
100 void set_suspended(int);
101 void sig_alrm(int);
102 void sig_usr1(int);
103 void sig_close(int);
104 void sig_hup(int);
105 void usage(void);
106
107 static int try_reset_dump(int);
108
109 /* buffer must always be greater than snaplen */
110 static int bufpkt = 0; /* number of packets in buffer */
111 static int buflen = 0; /* allocated size of buffer */
112 static char *buffer = NULL; /* packet buffer */
113 static char *bufpos = NULL; /* position in buffer */
114 static int bufleft = 0; /* bytes left in buffer */
115
116 /* if error, stop logging but count dropped packets */
117 static int suspended = -1;
118 static long packets_dropped = 0;
119
120 void
set_suspended(int s)121 set_suspended(int s)
122 {
123 if (suspended == s)
124 return;
125
126 suspended = s;
127 setproctitle("[%s] -s %d -i %s -f %s",
128 suspended ? "suspended" : "running",
129 cur_snaplen, interface, filename);
130 }
131
132 char *
copy_argv(char * const * argv)133 copy_argv(char * const *argv)
134 {
135 size_t len = 0, n;
136 char *buf;
137
138 if (argv == NULL)
139 return (NULL);
140
141 for (n = 0; argv[n]; n++)
142 len += strlen(argv[n])+1;
143 if (len == 0)
144 return (NULL);
145
146 buf = malloc(len);
147 if (buf == NULL)
148 return (NULL);
149
150 strlcpy(buf, argv[0], len);
151 for (n = 1; argv[n]; n++) {
152 strlcat(buf, " ", len);
153 strlcat(buf, argv[n], len);
154 }
155 return (buf);
156 }
157
158 void
logmsg(int pri,const char * message,...)159 logmsg(int pri, const char *message, ...)
160 {
161 va_list ap;
162 va_start(ap, message);
163
164 if (log_debug) {
165 vfprintf(stderr, message, ap);
166 fprintf(stderr, "\n");
167 } else
168 vsyslog(pri, message, ap);
169 va_end(ap);
170 }
171
172 #ifdef __FreeBSD__
173 __dead2 void
174 #else
175 __dead void
176 #endif
usage(void)177 usage(void)
178 {
179 fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
180 fprintf(stderr, " [-i interface] [-p pidfile]\n");
181 fprintf(stderr, " [-s snaplen] [expression]\n");
182 exit(1);
183 }
184
185 void
sig_close(int sig)186 sig_close(int sig)
187 {
188 gotsig_close = 1;
189 }
190
191 void
sig_hup(int sig)192 sig_hup(int sig)
193 {
194 gotsig_hup = 1;
195 }
196
197 void
sig_alrm(int sig)198 sig_alrm(int sig)
199 {
200 gotsig_alrm = 1;
201 }
202
203 void
sig_usr1(int sig)204 sig_usr1(int sig)
205 {
206 gotsig_usr1 = 1;
207 }
208
209 void
set_pcap_filter(void)210 set_pcap_filter(void)
211 {
212 struct bpf_program bprog;
213
214 if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
215 logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
216 else {
217 if (pcap_setfilter(hpcap, &bprog) < 0)
218 logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
219 pcap_freecode(&bprog);
220 }
221 }
222
223 int
if_exists(char * ifname)224 if_exists(char *ifname)
225 {
226 #ifdef __FreeBSD__
227 struct ifaddrs *ifdata, *mb;
228 int exists = 0;
229
230 getifaddrs(&ifdata);
231 if (ifdata == NULL)
232 return (0);
233
234 for (mb = ifdata; mb != NULL; mb = mb->ifa_next) {
235 if (mb == NULL)
236 continue;
237 if (strlen(ifname) != strlen(mb->ifa_name))
238 continue;
239 if (strncmp(ifname, mb->ifa_name, strlen(ifname)) != 0)
240 continue;
241 exists = 1;
242 break;
243 }
244 freeifaddrs(ifdata);
245
246 return (exists);
247 #else
248 int s;
249 struct ifreq ifr;
250 struct if_data ifrdat;
251
252 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
253 err(1, "socket");
254 bzero(&ifr, sizeof(ifr));
255 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
256 sizeof(ifr.ifr_name))
257 errx(1, "main ifr_name: strlcpy");
258 ifr.ifr_data = (caddr_t)&ifrdat;
259 if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
260 return (0);
261 if (close(s))
262 err(1, "close");
263
264 return (1);
265 #endif
266 }
267
268 int
init_pcap(void)269 init_pcap(void)
270 {
271 hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
272 if (hpcap == NULL) {
273 logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
274 return (-1);
275 }
276
277 if (pcap_datalink(hpcap) != DLT_PFLOG) {
278 logmsg(LOG_ERR, "Invalid datalink type");
279 pcap_close(hpcap);
280 hpcap = NULL;
281 return (-1);
282 }
283
284 set_pcap_filter();
285
286 cur_snaplen = snaplen = pcap_snapshot(hpcap);
287
288 /* lock */
289 if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
290 logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
291 return (-1);
292 }
293
294 return (0);
295 }
296
297 int
set_snaplen(int snap)298 set_snaplen(int snap)
299 {
300 if (priv_set_snaplen(snap))
301 return (1);
302
303 if (cur_snaplen > snap)
304 purge_buffer();
305
306 cur_snaplen = snap;
307
308 return (0);
309 }
310
311 int
reset_dump(int nomove)312 reset_dump(int nomove)
313 {
314 int ret;
315
316 for (;;) {
317 ret = try_reset_dump(nomove);
318 if (ret <= 0)
319 break;
320 }
321
322 return (ret);
323 }
324
325 /*
326 * tries to (re)open log file, nomove flag is used with -x switch
327 * returns 0: success, 1: retry (log moved), -1: error
328 */
329 int
try_reset_dump(int nomove)330 try_reset_dump(int nomove)
331 {
332 struct pcap_file_header hdr;
333 struct stat st;
334 int fd;
335 FILE *fp;
336
337 if (hpcap == NULL)
338 return (-1);
339
340 if (dpcap) {
341 flush_buffer(dpcap);
342 fclose(dpcap);
343 dpcap = NULL;
344 }
345
346 /*
347 * Basically reimplement pcap_dump_open() because it truncates
348 * files and duplicates headers and such.
349 */
350 fd = priv_open_log();
351 if (fd < 0)
352 return (-1);
353
354 fp = fdopen(fd, "a+");
355
356 if (fp == NULL) {
357 logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
358 close(fd);
359 return (-1);
360 }
361 if (fstat(fileno(fp), &st) == -1) {
362 logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
363 fclose(fp);
364 return (-1);
365 }
366
367 /* set FILE unbuffered, we do our own buffering */
368 if (setvbuf(fp, NULL, _IONBF, 0)) {
369 logmsg(LOG_ERR, "Failed to set output buffers");
370 fclose(fp);
371 return (-1);
372 }
373
374 #define TCPDUMP_MAGIC 0xa1b2c3d4
375
376 if (st.st_size == 0) {
377 if (snaplen != cur_snaplen) {
378 logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
379 if (set_snaplen(snaplen))
380 logmsg(LOG_WARNING,
381 "Failed, using old settings");
382 }
383 hdr.magic = TCPDUMP_MAGIC;
384 hdr.version_major = PCAP_VERSION_MAJOR;
385 hdr.version_minor = PCAP_VERSION_MINOR;
386 hdr.thiszone = 0;
387 hdr.snaplen = hpcap->snapshot;
388 hdr.sigfigs = 0;
389 hdr.linktype = hpcap->linktype;
390
391 if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
392 fclose(fp);
393 return (-1);
394 }
395 } else if (scan_dump(fp, st.st_size)) {
396 fclose(fp);
397 if (nomove || priv_move_log()) {
398 logmsg(LOG_ERR,
399 "Invalid/incompatible log file, move it away");
400 return (-1);
401 }
402 return (1);
403 }
404
405 dpcap = fp;
406
407 set_suspended(0);
408 flush_buffer(fp);
409
410 return (0);
411 }
412
413 int
scan_dump(FILE * fp,off_t size)414 scan_dump(FILE *fp, off_t size)
415 {
416 struct pcap_file_header hdr;
417 #ifdef __FreeBSD__
418 struct pcap_sf_pkthdr ph;
419 #else
420 struct pcap_pkthdr ph;
421 #endif
422 off_t pos;
423
424 /*
425 * Must read the file, compare the header against our new
426 * options (in particular, snaplen) and adjust our options so
427 * that we generate a correct file. Furthermore, check the file
428 * for consistency so that we can append safely.
429 *
430 * XXX this may take a long time for large logs.
431 */
432 (void) fseek(fp, 0L, SEEK_SET);
433
434 if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
435 logmsg(LOG_ERR, "Short file header");
436 return (1);
437 }
438
439 if (hdr.magic != TCPDUMP_MAGIC ||
440 hdr.version_major != PCAP_VERSION_MAJOR ||
441 hdr.version_minor != PCAP_VERSION_MINOR ||
442 hdr.linktype != hpcap->linktype ||
443 hdr.snaplen > PFLOGD_MAXSNAPLEN) {
444 return (1);
445 }
446
447 pos = sizeof(hdr);
448
449 while (!feof(fp)) {
450 off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
451 if (len == 0)
452 break;
453
454 if (len != sizeof(ph))
455 goto error;
456 if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
457 goto error;
458 pos += sizeof(ph) + ph.caplen;
459 if (pos > size)
460 goto error;
461 fseek(fp, ph.caplen, SEEK_CUR);
462 }
463
464 if (pos != size)
465 goto error;
466
467 if (hdr.snaplen != cur_snaplen) {
468 logmsg(LOG_WARNING,
469 "Existing file has different snaplen %u, using it",
470 hdr.snaplen);
471 if (set_snaplen(hdr.snaplen)) {
472 logmsg(LOG_WARNING,
473 "Failed, using old settings, offset %llu",
474 (unsigned long long) size);
475 }
476 }
477
478 return (0);
479
480 error:
481 logmsg(LOG_ERR, "Corrupted log file.");
482 return (1);
483 }
484
485 /* dump a packet directly to the stream, which is unbuffered */
486 void
dump_packet_nobuf(u_char * user,const struct pcap_pkthdr * h,const u_char * sp)487 dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
488 {
489 FILE *f = (FILE *)user;
490 #ifdef __FreeBSD__
491 struct pcap_sf_pkthdr sh;
492 #endif
493
494 if (suspended) {
495 packets_dropped++;
496 return;
497 }
498
499 #ifdef __FreeBSD__
500 sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
501 sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
502 sh.caplen = h->caplen;
503 sh.len = h->len;
504
505 if (fwrite((char *)&sh, sizeof(sh), 1, f) != 1) {
506 #else
507 if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
508 #endif
509 off_t pos = ftello(f);
510
511 /* try to undo header to prevent corruption */
512 #ifdef __FreeBSD__
513 if (pos < sizeof(sh) ||
514 ftruncate(fileno(f), pos - sizeof(sh))) {
515 #else
516 if (pos < sizeof(*h) ||
517 ftruncate(fileno(f), pos - sizeof(*h))) {
518 #endif
519 logmsg(LOG_ERR, "Write failed, corrupted logfile!");
520 set_suspended(1);
521 gotsig_close = 1;
522 return;
523 }
524 goto error;
525 }
526
527 if (fwrite((char *)sp, h->caplen, 1, f) != 1)
528 goto error;
529
530 return;
531
532 error:
533 set_suspended(1);
534 packets_dropped ++;
535 logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
536 }
537
538 int
539 flush_buffer(FILE *f)
540 {
541 off_t offset;
542 int len = bufpos - buffer;
543
544 if (len <= 0)
545 return (0);
546
547 offset = ftello(f);
548 if (offset == (off_t)-1) {
549 set_suspended(1);
550 logmsg(LOG_ERR, "Logging suspended: ftello: %s",
551 strerror(errno));
552 return (1);
553 }
554
555 if (fwrite(buffer, len, 1, f) != 1) {
556 set_suspended(1);
557 logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
558 strerror(errno));
559 ftruncate(fileno(f), offset);
560 return (1);
561 }
562
563 set_suspended(0);
564 bufpos = buffer;
565 bufleft = buflen;
566 bufpkt = 0;
567
568 return (0);
569 }
570
571 void
572 purge_buffer(void)
573 {
574 packets_dropped += bufpkt;
575
576 set_suspended(0);
577 bufpos = buffer;
578 bufleft = buflen;
579 bufpkt = 0;
580 }
581
582 /* append packet to the buffer, flushing if necessary */
583 void
584 dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
585 {
586 FILE *f = (FILE *)user;
587 #ifdef __FreeBSD__
588 struct pcap_sf_pkthdr sh;
589 size_t len = sizeof(sh) + h->caplen;
590 #else
591 size_t len = sizeof(*h) + h->caplen;
592 #endif
593
594 if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
595 logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped",
596 len, cur_snaplen, snaplen);
597 packets_dropped++;
598 return;
599 }
600
601 if (len <= bufleft)
602 goto append;
603
604 if (suspended) {
605 packets_dropped++;
606 return;
607 }
608
609 if (flush_buffer(f)) {
610 packets_dropped++;
611 return;
612 }
613
614 if (len > bufleft) {
615 dump_packet_nobuf(user, h, sp);
616 return;
617 }
618
619 append:
620 #ifdef __FreeBSD__
621 sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
622 sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
623 sh.caplen = h->caplen;
624 sh.len = h->len;
625
626 memcpy(bufpos, &sh, sizeof(sh));
627 memcpy(bufpos + sizeof(sh), sp, h->caplen);
628 #else
629 memcpy(bufpos, h, sizeof(*h));
630 memcpy(bufpos + sizeof(*h), sp, h->caplen);
631 #endif
632
633 bufpos += len;
634 bufleft -= len;
635 bufpkt++;
636
637 return;
638 }
639
640 void
641 log_pcap_stats(void)
642 {
643 struct pcap_stat pstat;
644 if (pcap_stats(hpcap, &pstat) < 0)
645 logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
646 else
647 logmsg(LOG_NOTICE,
648 "%u packets received, %u/%u dropped (kernel/pflogd)",
649 pstat.ps_recv, pstat.ps_drop, packets_dropped);
650 }
651
652 int
653 main(int argc, char **argv)
654 {
655 int ch, np, ret, Xflag = 0;
656 pcap_handler phandler = dump_packet;
657 const char *errstr = NULL;
658 char *pidf = NULL;
659
660 ret = 0;
661
662 closefrom(STDERR_FILENO + 1);
663
664 while ((ch = getopt(argc, argv, "Dxd:f:i:p:s:")) != -1) {
665 switch (ch) {
666 case 'D':
667 Debug = 1;
668 break;
669 case 'd':
670 delay = strtonum(optarg, 5, 60*60, &errstr);
671 if (errstr)
672 usage();
673 break;
674 case 'f':
675 filename = optarg;
676 break;
677 case 'i':
678 interface = optarg;
679 break;
680 case 'p':
681 pidf = optarg;
682 break;
683 case 's':
684 snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
685 &errstr);
686 if (snaplen <= 0)
687 snaplen = DEF_SNAPLEN;
688 if (errstr)
689 snaplen = PFLOGD_MAXSNAPLEN;
690 break;
691 case 'x':
692 Xflag++;
693 break;
694 default:
695 usage();
696 }
697
698 }
699
700 log_debug = Debug;
701 argc -= optind;
702 argv += optind;
703
704 /* does interface exist */
705 if (!if_exists(interface)) {
706 warn("Failed to initialize: %s", interface);
707 logmsg(LOG_ERR, "Failed to initialize: %s", interface);
708 logmsg(LOG_ERR, "Exiting, init failure");
709 exit(1);
710 }
711
712 if (!Debug) {
713 openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
714 if (daemon(0, 0)) {
715 logmsg(LOG_WARNING, "Failed to become daemon: %s",
716 strerror(errno));
717 }
718 pidfile(pidf);
719 }
720
721 tzset();
722 (void)umask(S_IRWXG | S_IRWXO);
723
724 /* filter will be used by the privileged process */
725 if (argc) {
726 filter = copy_argv(argv);
727 if (filter == NULL)
728 logmsg(LOG_NOTICE, "Failed to form filter expression");
729 }
730
731 /* initialize pcap before dropping privileges */
732 if (init_pcap()) {
733 logmsg(LOG_ERR, "Exiting, init failure");
734 exit(1);
735 }
736
737 /* Privilege separation begins here */
738 if (priv_init()) {
739 logmsg(LOG_ERR, "unable to privsep");
740 exit(1);
741 }
742
743 setproctitle("[initializing]");
744 /* Process is now unprivileged and inside a chroot */
745 signal(SIGTERM, sig_close);
746 signal(SIGINT, sig_close);
747 signal(SIGQUIT, sig_close);
748 signal(SIGALRM, sig_alrm);
749 signal(SIGUSR1, sig_usr1);
750 signal(SIGHUP, sig_hup);
751 alarm(delay);
752
753 buffer = malloc(PFLOGD_BUFSIZE);
754
755 if (buffer == NULL) {
756 logmsg(LOG_WARNING, "Failed to allocate output buffer");
757 phandler = dump_packet_nobuf;
758 } else {
759 bufleft = buflen = PFLOGD_BUFSIZE;
760 bufpos = buffer;
761 bufpkt = 0;
762 }
763
764 if (reset_dump(Xflag) < 0) {
765 if (Xflag)
766 return (1);
767
768 logmsg(LOG_ERR, "Logging suspended: open error");
769 set_suspended(1);
770 } else if (Xflag)
771 return (0);
772
773 while (1) {
774 np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
775 phandler, (u_char *)dpcap);
776 if (np < 0) {
777 if (!if_exists(interface)) {
778 logmsg(LOG_NOTICE, "interface %s went away",
779 interface);
780 ret = -1;
781 break;
782 }
783 logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
784 }
785
786 if (gotsig_close)
787 break;
788 if (gotsig_hup) {
789 if (reset_dump(0)) {
790 logmsg(LOG_ERR,
791 "Logging suspended: open error");
792 set_suspended(1);
793 }
794 gotsig_hup = 0;
795 }
796
797 if (gotsig_alrm) {
798 if (dpcap)
799 flush_buffer(dpcap);
800 else
801 gotsig_hup = 1;
802 gotsig_alrm = 0;
803 alarm(delay);
804 }
805
806 if (gotsig_usr1) {
807 log_pcap_stats();
808 gotsig_usr1 = 0;
809 }
810 }
811
812 logmsg(LOG_NOTICE, "Exiting");
813 if (dpcap) {
814 flush_buffer(dpcap);
815 fclose(dpcap);
816 }
817 purge_buffer();
818
819 log_pcap_stats();
820 pcap_close(hpcap);
821 if (!Debug)
822 closelog();
823 return (ret);
824 }
825