Deleted Added
full compact
pflogd.c (130617) pflogd.c (134578)
1/* $OpenBSD: pflogd.c,v 1.27 2004/02/13 19:01:57 otto 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/cdefs.h>
1/* $OpenBSD: pflogd.c,v 1.27 2004/02/13 19:01:57 otto 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/cdefs.h>
34__FBSDID("$FreeBSD: head/contrib/pf/pflogd/pflogd.c 130617 2004-06-16 23:39:33Z mlaier $");
34__FBSDID("$FreeBSD: head/contrib/pf/pflogd/pflogd.c 134578 2004-08-31 18:04:34Z mlaier $");
35
36#include <sys/types.h>
37#include <sys/ioctl.h>
38#include <sys/file.h>
39#include <sys/stat.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44#include <pcap-int.h>
45#include <pcap.h>
46#include <syslog.h>
47#include <signal.h>
48#include <errno.h>
49#include <stdarg.h>
50#include <fcntl.h>
51#ifdef __FreeBSD__
52#include "pidfile.h"
53#else
54#include <util.h>
55#endif
56
57#include "pflogd.h"
58
59pcap_t *hpcap;
60static FILE *dpcap;
61
62int Debug = 0;
63static int snaplen = DEF_SNAPLEN;
64static int cur_snaplen = DEF_SNAPLEN;
65
66volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup;
67
68char *filename = PFLOGD_LOG_FILE;
69char *interface = PFLOGD_DEFAULT_IF;
70char *filter = NULL;
71
72char errbuf[PCAP_ERRBUF_SIZE];
73
74int log_debug = 0;
75unsigned int delay = FLUSH_DELAY;
76
77char *copy_argv(char * const *);
78void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
79void dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
80int flush_buffer(FILE *);
81int init_pcap(void);
82void logmsg(int, const char *, ...);
83void purge_buffer(void);
84int reset_dump(void);
85int scan_dump(FILE *, off_t);
86int set_snaplen(int);
87void set_suspended(int);
88void sig_alrm(int);
89void sig_close(int);
90void sig_hup(int);
91void usage(void);
92
93/* buffer must always be greater than snaplen */
94static int bufpkt = 0; /* number of packets in buffer */
95static int buflen = 0; /* allocated size of buffer */
96static char *buffer = NULL; /* packet buffer */
97static char *bufpos = NULL; /* position in buffer */
98static int bufleft = 0; /* bytes left in buffer */
99
100/* if error, stop logging but count dropped packets */
101static int suspended = -1;
102static long packets_dropped = 0;
103
104void
105set_suspended(int s)
106{
107 if (suspended == s)
108 return;
109
110 suspended = s;
111 setproctitle("[%s] -s %d -f %s",
112 suspended ? "suspended" : "running", cur_snaplen, filename);
113}
114
115char *
116copy_argv(char * const *argv)
117{
118 size_t len = 0, n;
119 char *buf;
120
121 if (argv == NULL)
122 return (NULL);
123
124 for (n = 0; argv[n]; n++)
125 len += strlen(argv[n])+1;
126 if (len == 0)
127 return (NULL);
128
129 buf = malloc(len);
130 if (buf == NULL)
131 return (NULL);
132
133 strlcpy(buf, argv[0], len);
134 for (n = 1; argv[n]; n++) {
135 strlcat(buf, " ", len);
136 strlcat(buf, argv[n], len);
137 }
138 return (buf);
139}
140
141void
142logmsg(int pri, const char *message, ...)
143{
144 va_list ap;
145 va_start(ap, message);
146
147 if (log_debug) {
148 vfprintf(stderr, message, ap);
149 fprintf(stderr, "\n");
150 } else
151 vsyslog(pri, message, ap);
152 va_end(ap);
153}
154
155#ifdef __FreeBSD__
156__dead2 void
157#else
158__dead void
159#endif
160usage(void)
161{
162 fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename] ");
163 fprintf(stderr, "[-s snaplen] [expression]\n");
164 exit(1);
165}
166
167void
168sig_close(int sig)
169{
170 gotsig_close = 1;
171}
172
173void
174sig_hup(int sig)
175{
176 gotsig_hup = 1;
177}
178
179void
180sig_alrm(int sig)
181{
182 gotsig_alrm = 1;
183}
184
185void
186set_pcap_filter(void)
187{
188 struct bpf_program bprog;
189
190 if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
191 logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
192 else {
193 if (pcap_setfilter(hpcap, &bprog) < 0)
194 logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
195 pcap_freecode(&bprog);
196 }
197}
198
199int
200init_pcap(void)
201{
202 hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
203 if (hpcap == NULL) {
204 logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
205 return (-1);
206 }
207
208 if (pcap_datalink(hpcap) != DLT_PFLOG) {
209 logmsg(LOG_ERR, "Invalid datalink type");
210 pcap_close(hpcap);
211 hpcap = NULL;
212 return (-1);
213 }
214
215 set_pcap_filter();
216
217 cur_snaplen = snaplen = pcap_snapshot(hpcap);
218
219#ifdef __FreeBSD__
220 /* We can not lock bpf devices ... yet */
221#else
222 /* lock */
223 if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
224 logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
225 return (-1);
226 }
227#endif
228
229 return (0);
230}
231
232int
233set_snaplen(int snap)
234{
235 if (priv_set_snaplen(snap))
236 return (1);
237
238 if (cur_snaplen > snap)
239 purge_buffer();
240
241 cur_snaplen = snap;
242
243 return (0);
244}
245
246int
247reset_dump(void)
248{
249 struct pcap_file_header hdr;
250 struct stat st;
251 int fd;
252 FILE *fp;
253
254 if (hpcap == NULL)
255 return (-1);
256
257 if (dpcap) {
258 flush_buffer(dpcap);
259 fclose(dpcap);
260 dpcap = NULL;
261 }
262
263 /*
264 * Basically reimplement pcap_dump_open() because it truncates
265 * files and duplicates headers and such.
266 */
267 fd = priv_open_log();
268 if (fd < 0)
269 return (1);
270
271 fp = fdopen(fd, "a+");
272
273 if (fp == NULL) {
274 logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
275 return (1);
276 }
277 if (fstat(fileno(fp), &st) == -1) {
278 logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
279 return (1);
280 }
281
282 /* set FILE unbuffered, we do our own buffering */
283 if (setvbuf(fp, NULL, _IONBF, 0)) {
284 logmsg(LOG_ERR, "Failed to set output buffers");
285 return (1);
286 }
287
288#define TCPDUMP_MAGIC 0xa1b2c3d4
289
290 if (st.st_size == 0) {
291 if (snaplen != cur_snaplen) {
292 logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
293 if (set_snaplen(snaplen)) {
294 logmsg(LOG_WARNING,
295 "Failed, using old settings");
296 }
297 }
298 hdr.magic = TCPDUMP_MAGIC;
299 hdr.version_major = PCAP_VERSION_MAJOR;
300 hdr.version_minor = PCAP_VERSION_MINOR;
301 hdr.thiszone = hpcap->tzoff;
302 hdr.snaplen = hpcap->snapshot;
303 hdr.sigfigs = 0;
304 hdr.linktype = hpcap->linktype;
305
306 if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
307 fclose(fp);
308 return (1);
309 }
310 } else if (scan_dump(fp, st.st_size)) {
311 /* XXX move file and continue? */
312 fclose(fp);
313 return (1);
314 }
315
316 dpcap = fp;
317
318 set_suspended(0);
319 flush_buffer(fp);
320
321 return (0);
322}
323
324int
325scan_dump(FILE *fp, off_t size)
326{
327 struct pcap_file_header hdr;
35
36#include <sys/types.h>
37#include <sys/ioctl.h>
38#include <sys/file.h>
39#include <sys/stat.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44#include <pcap-int.h>
45#include <pcap.h>
46#include <syslog.h>
47#include <signal.h>
48#include <errno.h>
49#include <stdarg.h>
50#include <fcntl.h>
51#ifdef __FreeBSD__
52#include "pidfile.h"
53#else
54#include <util.h>
55#endif
56
57#include "pflogd.h"
58
59pcap_t *hpcap;
60static FILE *dpcap;
61
62int Debug = 0;
63static int snaplen = DEF_SNAPLEN;
64static int cur_snaplen = DEF_SNAPLEN;
65
66volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup;
67
68char *filename = PFLOGD_LOG_FILE;
69char *interface = PFLOGD_DEFAULT_IF;
70char *filter = NULL;
71
72char errbuf[PCAP_ERRBUF_SIZE];
73
74int log_debug = 0;
75unsigned int delay = FLUSH_DELAY;
76
77char *copy_argv(char * const *);
78void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
79void dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
80int flush_buffer(FILE *);
81int init_pcap(void);
82void logmsg(int, const char *, ...);
83void purge_buffer(void);
84int reset_dump(void);
85int scan_dump(FILE *, off_t);
86int set_snaplen(int);
87void set_suspended(int);
88void sig_alrm(int);
89void sig_close(int);
90void sig_hup(int);
91void usage(void);
92
93/* buffer must always be greater than snaplen */
94static int bufpkt = 0; /* number of packets in buffer */
95static int buflen = 0; /* allocated size of buffer */
96static char *buffer = NULL; /* packet buffer */
97static char *bufpos = NULL; /* position in buffer */
98static int bufleft = 0; /* bytes left in buffer */
99
100/* if error, stop logging but count dropped packets */
101static int suspended = -1;
102static long packets_dropped = 0;
103
104void
105set_suspended(int s)
106{
107 if (suspended == s)
108 return;
109
110 suspended = s;
111 setproctitle("[%s] -s %d -f %s",
112 suspended ? "suspended" : "running", cur_snaplen, filename);
113}
114
115char *
116copy_argv(char * const *argv)
117{
118 size_t len = 0, n;
119 char *buf;
120
121 if (argv == NULL)
122 return (NULL);
123
124 for (n = 0; argv[n]; n++)
125 len += strlen(argv[n])+1;
126 if (len == 0)
127 return (NULL);
128
129 buf = malloc(len);
130 if (buf == NULL)
131 return (NULL);
132
133 strlcpy(buf, argv[0], len);
134 for (n = 1; argv[n]; n++) {
135 strlcat(buf, " ", len);
136 strlcat(buf, argv[n], len);
137 }
138 return (buf);
139}
140
141void
142logmsg(int pri, const char *message, ...)
143{
144 va_list ap;
145 va_start(ap, message);
146
147 if (log_debug) {
148 vfprintf(stderr, message, ap);
149 fprintf(stderr, "\n");
150 } else
151 vsyslog(pri, message, ap);
152 va_end(ap);
153}
154
155#ifdef __FreeBSD__
156__dead2 void
157#else
158__dead void
159#endif
160usage(void)
161{
162 fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename] ");
163 fprintf(stderr, "[-s snaplen] [expression]\n");
164 exit(1);
165}
166
167void
168sig_close(int sig)
169{
170 gotsig_close = 1;
171}
172
173void
174sig_hup(int sig)
175{
176 gotsig_hup = 1;
177}
178
179void
180sig_alrm(int sig)
181{
182 gotsig_alrm = 1;
183}
184
185void
186set_pcap_filter(void)
187{
188 struct bpf_program bprog;
189
190 if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
191 logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
192 else {
193 if (pcap_setfilter(hpcap, &bprog) < 0)
194 logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
195 pcap_freecode(&bprog);
196 }
197}
198
199int
200init_pcap(void)
201{
202 hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
203 if (hpcap == NULL) {
204 logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
205 return (-1);
206 }
207
208 if (pcap_datalink(hpcap) != DLT_PFLOG) {
209 logmsg(LOG_ERR, "Invalid datalink type");
210 pcap_close(hpcap);
211 hpcap = NULL;
212 return (-1);
213 }
214
215 set_pcap_filter();
216
217 cur_snaplen = snaplen = pcap_snapshot(hpcap);
218
219#ifdef __FreeBSD__
220 /* We can not lock bpf devices ... yet */
221#else
222 /* lock */
223 if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
224 logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
225 return (-1);
226 }
227#endif
228
229 return (0);
230}
231
232int
233set_snaplen(int snap)
234{
235 if (priv_set_snaplen(snap))
236 return (1);
237
238 if (cur_snaplen > snap)
239 purge_buffer();
240
241 cur_snaplen = snap;
242
243 return (0);
244}
245
246int
247reset_dump(void)
248{
249 struct pcap_file_header hdr;
250 struct stat st;
251 int fd;
252 FILE *fp;
253
254 if (hpcap == NULL)
255 return (-1);
256
257 if (dpcap) {
258 flush_buffer(dpcap);
259 fclose(dpcap);
260 dpcap = NULL;
261 }
262
263 /*
264 * Basically reimplement pcap_dump_open() because it truncates
265 * files and duplicates headers and such.
266 */
267 fd = priv_open_log();
268 if (fd < 0)
269 return (1);
270
271 fp = fdopen(fd, "a+");
272
273 if (fp == NULL) {
274 logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
275 return (1);
276 }
277 if (fstat(fileno(fp), &st) == -1) {
278 logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
279 return (1);
280 }
281
282 /* set FILE unbuffered, we do our own buffering */
283 if (setvbuf(fp, NULL, _IONBF, 0)) {
284 logmsg(LOG_ERR, "Failed to set output buffers");
285 return (1);
286 }
287
288#define TCPDUMP_MAGIC 0xa1b2c3d4
289
290 if (st.st_size == 0) {
291 if (snaplen != cur_snaplen) {
292 logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
293 if (set_snaplen(snaplen)) {
294 logmsg(LOG_WARNING,
295 "Failed, using old settings");
296 }
297 }
298 hdr.magic = TCPDUMP_MAGIC;
299 hdr.version_major = PCAP_VERSION_MAJOR;
300 hdr.version_minor = PCAP_VERSION_MINOR;
301 hdr.thiszone = hpcap->tzoff;
302 hdr.snaplen = hpcap->snapshot;
303 hdr.sigfigs = 0;
304 hdr.linktype = hpcap->linktype;
305
306 if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
307 fclose(fp);
308 return (1);
309 }
310 } else if (scan_dump(fp, st.st_size)) {
311 /* XXX move file and continue? */
312 fclose(fp);
313 return (1);
314 }
315
316 dpcap = fp;
317
318 set_suspended(0);
319 flush_buffer(fp);
320
321 return (0);
322}
323
324int
325scan_dump(FILE *fp, off_t size)
326{
327 struct pcap_file_header hdr;
328#ifdef __FreeBSD__
329 struct pcap_sf_pkthdr ph;
330#else
328 struct pcap_pkthdr ph;
331 struct pcap_pkthdr ph;
332#endif
329 off_t pos;
330
331 /*
332 * Must read the file, compare the header against our new
333 * options (in particular, snaplen) and adjust our options so
334 * that we generate a correct file. Furthermore, check the file
335 * for consistency so that we can append safely.
336 *
337 * XXX this may take a long time for large logs.
338 */
339 (void) fseek(fp, 0L, SEEK_SET);
340
341 if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
342 logmsg(LOG_ERR, "Short file header");
343 return (1);
344 }
345
346 if (hdr.magic != TCPDUMP_MAGIC ||
347 hdr.version_major != PCAP_VERSION_MAJOR ||
348 hdr.version_minor != PCAP_VERSION_MINOR ||
349 hdr.linktype != hpcap->linktype ||
350 hdr.snaplen > PFLOGD_MAXSNAPLEN) {
351 logmsg(LOG_ERR, "Invalid/incompatible log file, move it away");
352 return (1);
353 }
354
355 pos = sizeof(hdr);
356
357 while (!feof(fp)) {
358 off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
359 if (len == 0)
360 break;
361
362 if (len != sizeof(ph))
363 goto error;
364 if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
365 goto error;
366 pos += sizeof(ph) + ph.caplen;
367 if (pos > size)
368 goto error;
369 fseek(fp, ph.caplen, SEEK_CUR);
370 }
371
372 if (pos != size)
373 goto error;
374
375 if (hdr.snaplen != cur_snaplen) {
376 logmsg(LOG_WARNING,
377 "Existing file has different snaplen %u, using it",
378 hdr.snaplen);
379 if (set_snaplen(hdr.snaplen)) {
380 logmsg(LOG_WARNING,
381 "Failed, using old settings, offset %llu",
382 (unsigned long long) size);
383 }
384 }
385
386 return (0);
387
388 error:
389 logmsg(LOG_ERR, "Corrupted log file.");
390 return (1);
391}
392
393/* dump a packet directly to the stream, which is unbuffered */
394void
395dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
396{
397 FILE *f = (FILE *)user;
333 off_t pos;
334
335 /*
336 * Must read the file, compare the header against our new
337 * options (in particular, snaplen) and adjust our options so
338 * that we generate a correct file. Furthermore, check the file
339 * for consistency so that we can append safely.
340 *
341 * XXX this may take a long time for large logs.
342 */
343 (void) fseek(fp, 0L, SEEK_SET);
344
345 if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
346 logmsg(LOG_ERR, "Short file header");
347 return (1);
348 }
349
350 if (hdr.magic != TCPDUMP_MAGIC ||
351 hdr.version_major != PCAP_VERSION_MAJOR ||
352 hdr.version_minor != PCAP_VERSION_MINOR ||
353 hdr.linktype != hpcap->linktype ||
354 hdr.snaplen > PFLOGD_MAXSNAPLEN) {
355 logmsg(LOG_ERR, "Invalid/incompatible log file, move it away");
356 return (1);
357 }
358
359 pos = sizeof(hdr);
360
361 while (!feof(fp)) {
362 off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
363 if (len == 0)
364 break;
365
366 if (len != sizeof(ph))
367 goto error;
368 if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
369 goto error;
370 pos += sizeof(ph) + ph.caplen;
371 if (pos > size)
372 goto error;
373 fseek(fp, ph.caplen, SEEK_CUR);
374 }
375
376 if (pos != size)
377 goto error;
378
379 if (hdr.snaplen != cur_snaplen) {
380 logmsg(LOG_WARNING,
381 "Existing file has different snaplen %u, using it",
382 hdr.snaplen);
383 if (set_snaplen(hdr.snaplen)) {
384 logmsg(LOG_WARNING,
385 "Failed, using old settings, offset %llu",
386 (unsigned long long) size);
387 }
388 }
389
390 return (0);
391
392 error:
393 logmsg(LOG_ERR, "Corrupted log file.");
394 return (1);
395}
396
397/* dump a packet directly to the stream, which is unbuffered */
398void
399dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
400{
401 FILE *f = (FILE *)user;
402#ifdef __FreeBSD__
403 struct pcap_sf_pkthdr sh;
404#endif
398
399 if (suspended) {
400 packets_dropped++;
401 return;
402 }
403
405
406 if (suspended) {
407 packets_dropped++;
408 return;
409 }
410
411#ifdef __FreeBSD__
412 sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
413 sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
414 sh.caplen = h->caplen;
415 sh.len = h->len;
416
417 if (fwrite((char *)&sh, sizeof(sh), 1, f) != 1) {
418#else
404 if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
419 if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
420#endif
405 /* try to undo header to prevent corruption */
406 off_t pos = ftello(f);
421 /* try to undo header to prevent corruption */
422 off_t pos = ftello(f);
423#ifdef __FreeBSD__
424 if (pos < sizeof(sh) ||
425 ftruncate(fileno(f), pos - sizeof(sh))) {
426#else
407 if (pos < sizeof(*h) ||
408 ftruncate(fileno(f), pos - sizeof(*h))) {
427 if (pos < sizeof(*h) ||
428 ftruncate(fileno(f), pos - sizeof(*h))) {
429#endif
409 logmsg(LOG_ERR, "Write failed, corrupted logfile!");
410 set_suspended(1);
411 gotsig_close = 1;
412 return;
413 }
414 goto error;
415 }
416
417 if (fwrite((char *)sp, h->caplen, 1, f) != 1)
418 goto error;
419
420 return;
421
422error:
423 set_suspended(1);
424 packets_dropped ++;
425 logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
426}
427
428int
429flush_buffer(FILE *f)
430{
431 off_t offset;
432 int len = bufpos - buffer;
433
434 if (len <= 0)
435 return (0);
436
437 offset = ftello(f);
438 if (offset == (off_t)-1) {
439 set_suspended(1);
440 logmsg(LOG_ERR, "Logging suspended: ftello: %s",
441 strerror(errno));
442 return (1);
443 }
444
445 if (fwrite(buffer, len, 1, f) != 1) {
446 set_suspended(1);
447 logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
448 strerror(errno));
449 ftruncate(fileno(f), offset);
450 return (1);
451 }
452
453 set_suspended(0);
454 bufpos = buffer;
455 bufleft = buflen;
456 bufpkt = 0;
457
458 return (0);
459}
460
461void
462purge_buffer(void)
463{
464 packets_dropped += bufpkt;
465
466 set_suspended(0);
467 bufpos = buffer;
468 bufleft = buflen;
469 bufpkt = 0;
470}
471
472/* append packet to the buffer, flushing if necessary */
473void
474dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
475{
476 FILE *f = (FILE *)user;
430 logmsg(LOG_ERR, "Write failed, corrupted logfile!");
431 set_suspended(1);
432 gotsig_close = 1;
433 return;
434 }
435 goto error;
436 }
437
438 if (fwrite((char *)sp, h->caplen, 1, f) != 1)
439 goto error;
440
441 return;
442
443error:
444 set_suspended(1);
445 packets_dropped ++;
446 logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
447}
448
449int
450flush_buffer(FILE *f)
451{
452 off_t offset;
453 int len = bufpos - buffer;
454
455 if (len <= 0)
456 return (0);
457
458 offset = ftello(f);
459 if (offset == (off_t)-1) {
460 set_suspended(1);
461 logmsg(LOG_ERR, "Logging suspended: ftello: %s",
462 strerror(errno));
463 return (1);
464 }
465
466 if (fwrite(buffer, len, 1, f) != 1) {
467 set_suspended(1);
468 logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
469 strerror(errno));
470 ftruncate(fileno(f), offset);
471 return (1);
472 }
473
474 set_suspended(0);
475 bufpos = buffer;
476 bufleft = buflen;
477 bufpkt = 0;
478
479 return (0);
480}
481
482void
483purge_buffer(void)
484{
485 packets_dropped += bufpkt;
486
487 set_suspended(0);
488 bufpos = buffer;
489 bufleft = buflen;
490 bufpkt = 0;
491}
492
493/* append packet to the buffer, flushing if necessary */
494void
495dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
496{
497 FILE *f = (FILE *)user;
498#ifdef __FreeBSD__
499 struct pcap_sf_pkthdr sh;
500 size_t len = sizeof(sh) + h->caplen;
501#else
477 size_t len = sizeof(*h) + h->caplen;
502 size_t len = sizeof(*h) + h->caplen;
503#endif
478
479 if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
480 logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped",
481 len, cur_snaplen, snaplen);
482 packets_dropped++;
483 return;
484 }
485
486 if (len <= bufleft)
487 goto append;
488
489 if (suspended) {
490 packets_dropped++;
491 return;
492 }
493
494 if (flush_buffer(f)) {
495 packets_dropped++;
496 return;
497 }
498
499 if (len > bufleft) {
500 dump_packet_nobuf(user, h, sp);
501 return;
502 }
503
504 append:
504
505 if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
506 logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped",
507 len, cur_snaplen, snaplen);
508 packets_dropped++;
509 return;
510 }
511
512 if (len <= bufleft)
513 goto append;
514
515 if (suspended) {
516 packets_dropped++;
517 return;
518 }
519
520 if (flush_buffer(f)) {
521 packets_dropped++;
522 return;
523 }
524
525 if (len > bufleft) {
526 dump_packet_nobuf(user, h, sp);
527 return;
528 }
529
530 append:
531#ifdef __FreeBSD__
532 sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
533 sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
534 sh.caplen = h->caplen;
535 sh.len = h->len;
536
537 memcpy(bufpos, &sh, sizeof(sh));
538 memcpy(bufpos + sizeof(sh), sp, h->caplen);
539#else
505 memcpy(bufpos, h, sizeof(*h));
506 memcpy(bufpos + sizeof(*h), sp, h->caplen);
540 memcpy(bufpos, h, sizeof(*h));
541 memcpy(bufpos + sizeof(*h), sp, h->caplen);
542#endif
507
508 bufpos += len;
509 bufleft -= len;
510 bufpkt++;
511
512 return;
513}
514
515int
516main(int argc, char **argv)
517{
518 struct pcap_stat pstat;
519 int ch, np, Xflag = 0;
520 pcap_handler phandler = dump_packet;
521
522#ifdef __FreeBSD__
523 /* another ?paranoid? safety measure we do not have */
524#else
525 closefrom(STDERR_FILENO + 1);
526#endif
527
528 while ((ch = getopt(argc, argv, "Dxd:s:f:")) != -1) {
529 switch (ch) {
530 case 'D':
531 Debug = 1;
532 break;
533 case 'd':
534 delay = atoi(optarg);
535 if (delay < 5 || delay > 60*60)
536 usage();
537 break;
538 case 'f':
539 filename = optarg;
540 break;
541 case 's':
542 snaplen = atoi(optarg);
543 if (snaplen <= 0)
544 snaplen = DEF_SNAPLEN;
545 if (snaplen > PFLOGD_MAXSNAPLEN)
546 snaplen = PFLOGD_MAXSNAPLEN;
547 break;
548 case 'x':
549 Xflag++;
550 break;
551 default:
552 usage();
553 }
554
555 }
556
557 log_debug = Debug;
558 argc -= optind;
559 argv += optind;
560
561 if (!Debug) {
562 openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
563 if (daemon(0, 0)) {
564 logmsg(LOG_WARNING, "Failed to become daemon: %s",
565 strerror(errno));
566 }
567 pidfile(NULL);
568 }
569
570 (void)umask(S_IRWXG | S_IRWXO);
571
572 /* filter will be used by the privileged process */
573 if (argc) {
574 filter = copy_argv(argv);
575 if (filter == NULL)
576 logmsg(LOG_NOTICE, "Failed to form filter expression");
577 }
578
579 /* initialize pcap before dropping privileges */
580 if (init_pcap()) {
581 logmsg(LOG_ERR, "Exiting, init failure");
582 exit(1);
583 }
584
585 /* Privilege separation begins here */
586 if (priv_init()) {
587 logmsg(LOG_ERR, "unable to privsep");
588 exit(1);
589 }
590
591 setproctitle("[initializing]");
592 /* Process is now unprivileged and inside a chroot */
593 signal(SIGTERM, sig_close);
594 signal(SIGINT, sig_close);
595 signal(SIGQUIT, sig_close);
596 signal(SIGALRM, sig_alrm);
597 signal(SIGHUP, sig_hup);
598 alarm(delay);
599
600 buffer = malloc(PFLOGD_BUFSIZE);
601
602 if (buffer == NULL) {
603 logmsg(LOG_WARNING, "Failed to allocate output buffer");
604 phandler = dump_packet_nobuf;
605 } else {
606 bufleft = buflen = PFLOGD_BUFSIZE;
607 bufpos = buffer;
608 bufpkt = 0;
609 }
610
611 if (reset_dump()) {
612 if (Xflag)
613 return (1);
614
615 logmsg(LOG_ERR, "Logging suspended: open error");
616 set_suspended(1);
617 } else if (Xflag)
618 return (0);
619
620 while (1) {
621 np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
622 dump_packet, (u_char *)dpcap);
623 if (np < 0)
624 logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
625
626 if (gotsig_close)
627 break;
628 if (gotsig_hup) {
629 if (reset_dump()) {
630 logmsg(LOG_ERR,
631 "Logging suspended: open error");
632 set_suspended(1);
633 }
634 gotsig_hup = 0;
635 }
636
637 if (gotsig_alrm) {
638 if (dpcap)
639 flush_buffer(dpcap);
640 gotsig_alrm = 0;
641 alarm(delay);
642 }
643 }
644
645 logmsg(LOG_NOTICE, "Exiting");
646 if (dpcap) {
647 flush_buffer(dpcap);
648 fclose(dpcap);
649 }
650 purge_buffer();
651
652 if (pcap_stats(hpcap, &pstat) < 0)
653 logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
654 else
655 logmsg(LOG_NOTICE,
656 "%u packets received, %u/%u dropped (kernel/pflogd)",
657 pstat.ps_recv, pstat.ps_drop, packets_dropped);
658
659 pcap_close(hpcap);
660 if (!Debug)
661 closelog();
662 return (0);
663}
543
544 bufpos += len;
545 bufleft -= len;
546 bufpkt++;
547
548 return;
549}
550
551int
552main(int argc, char **argv)
553{
554 struct pcap_stat pstat;
555 int ch, np, Xflag = 0;
556 pcap_handler phandler = dump_packet;
557
558#ifdef __FreeBSD__
559 /* another ?paranoid? safety measure we do not have */
560#else
561 closefrom(STDERR_FILENO + 1);
562#endif
563
564 while ((ch = getopt(argc, argv, "Dxd:s:f:")) != -1) {
565 switch (ch) {
566 case 'D':
567 Debug = 1;
568 break;
569 case 'd':
570 delay = atoi(optarg);
571 if (delay < 5 || delay > 60*60)
572 usage();
573 break;
574 case 'f':
575 filename = optarg;
576 break;
577 case 's':
578 snaplen = atoi(optarg);
579 if (snaplen <= 0)
580 snaplen = DEF_SNAPLEN;
581 if (snaplen > PFLOGD_MAXSNAPLEN)
582 snaplen = PFLOGD_MAXSNAPLEN;
583 break;
584 case 'x':
585 Xflag++;
586 break;
587 default:
588 usage();
589 }
590
591 }
592
593 log_debug = Debug;
594 argc -= optind;
595 argv += optind;
596
597 if (!Debug) {
598 openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
599 if (daemon(0, 0)) {
600 logmsg(LOG_WARNING, "Failed to become daemon: %s",
601 strerror(errno));
602 }
603 pidfile(NULL);
604 }
605
606 (void)umask(S_IRWXG | S_IRWXO);
607
608 /* filter will be used by the privileged process */
609 if (argc) {
610 filter = copy_argv(argv);
611 if (filter == NULL)
612 logmsg(LOG_NOTICE, "Failed to form filter expression");
613 }
614
615 /* initialize pcap before dropping privileges */
616 if (init_pcap()) {
617 logmsg(LOG_ERR, "Exiting, init failure");
618 exit(1);
619 }
620
621 /* Privilege separation begins here */
622 if (priv_init()) {
623 logmsg(LOG_ERR, "unable to privsep");
624 exit(1);
625 }
626
627 setproctitle("[initializing]");
628 /* Process is now unprivileged and inside a chroot */
629 signal(SIGTERM, sig_close);
630 signal(SIGINT, sig_close);
631 signal(SIGQUIT, sig_close);
632 signal(SIGALRM, sig_alrm);
633 signal(SIGHUP, sig_hup);
634 alarm(delay);
635
636 buffer = malloc(PFLOGD_BUFSIZE);
637
638 if (buffer == NULL) {
639 logmsg(LOG_WARNING, "Failed to allocate output buffer");
640 phandler = dump_packet_nobuf;
641 } else {
642 bufleft = buflen = PFLOGD_BUFSIZE;
643 bufpos = buffer;
644 bufpkt = 0;
645 }
646
647 if (reset_dump()) {
648 if (Xflag)
649 return (1);
650
651 logmsg(LOG_ERR, "Logging suspended: open error");
652 set_suspended(1);
653 } else if (Xflag)
654 return (0);
655
656 while (1) {
657 np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
658 dump_packet, (u_char *)dpcap);
659 if (np < 0)
660 logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
661
662 if (gotsig_close)
663 break;
664 if (gotsig_hup) {
665 if (reset_dump()) {
666 logmsg(LOG_ERR,
667 "Logging suspended: open error");
668 set_suspended(1);
669 }
670 gotsig_hup = 0;
671 }
672
673 if (gotsig_alrm) {
674 if (dpcap)
675 flush_buffer(dpcap);
676 gotsig_alrm = 0;
677 alarm(delay);
678 }
679 }
680
681 logmsg(LOG_NOTICE, "Exiting");
682 if (dpcap) {
683 flush_buffer(dpcap);
684 fclose(dpcap);
685 }
686 purge_buffer();
687
688 if (pcap_stats(hpcap, &pstat) < 0)
689 logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
690 else
691 logmsg(LOG_NOTICE,
692 "%u packets received, %u/%u dropped (kernel/pflogd)",
693 pstat.ps_recv, pstat.ps_drop, packets_dropped);
694
695 pcap_close(hpcap);
696 if (!Debug)
697 closelog();
698 return (0);
699}