diff options
author | mlaier <mlaier@FreeBSD.org> | 2004-02-28 16:52:45 +0000 |
---|---|---|
committer | mlaier <mlaier@FreeBSD.org> | 2004-02-28 16:52:45 +0000 |
commit | 2135f6a83c8e1b39db8af0b470ab6d0349144be9 (patch) | |
tree | 73e1e06a1e5e925889f30ef537d21f7d3edd736d /contrib/pf/pflogd | |
download | FreeBSD-src-2135f6a83c8e1b39db8af0b470ab6d0349144be9.zip FreeBSD-src-2135f6a83c8e1b39db8af0b470ab6d0349144be9.tar.gz |
Vendor import of OpenBSD's pf userland as of OpenBSD 3.4
Approved by: bms(mentor), core(in general)
Diffstat (limited to 'contrib/pf/pflogd')
-rw-r--r-- | contrib/pf/pflogd/pflogd.8 | 179 | ||||
-rw-r--r-- | contrib/pf/pflogd/pflogd.c | 400 |
2 files changed, 579 insertions, 0 deletions
diff --git a/contrib/pf/pflogd/pflogd.8 b/contrib/pf/pflogd/pflogd.8 new file mode 100644 index 0000000..ab63259 --- /dev/null +++ b/contrib/pf/pflogd/pflogd.8 @@ -0,0 +1,179 @@ +.\" $OpenBSD: pflogd.8,v 1.22 2003/06/03 13:16:08 jmc Exp $ +.\" +.\" Copyright (c) 2001 Can Erkin Acar. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd July 9, 2001 +.Dt PFLOGD 8 +.Os +.Sh NAME +.Nm pflogd +.Nd packet filter logging daemon +.Sh SYNOPSIS +.Nm pflogd +.Op Fl D +.Op Fl d Ar delay +.Op Fl f Ar filename +.Op Fl s Ar snaplen +.Op Ar expression +.Sh DESCRIPTION +.Nm +is a background daemon which reads packets logged by +.Xr pf 4 +to the packet logging interface +.Pa pflog0 +and writes the packets to a logfile (normally +.Pa /var/log/pflog ) +in +.Xr tcpdump 8 +binary format. +These logs can be reviewed later using the +.Fl r +option of +.Xr tcpdump 8 , +hopefully offline in case there are bugs in the packet parsing code of +.Xr tcpdump 8 . +.Pp +.Nm +closes and then re-opens the log file when it receives +.Va SIGHUP , +permitting +.Xr newsyslog 8 +to rotate logfiles automatically. +.Va SIGALRM +causes +.Nm +to flush the current logfile buffers to the disk, thus making the most +recent logs available. +The buffers are also flushed every +.Ar delay +seconds. +.Pp +If the log file contains data after a restart or a +.Va SIGHUP , +new logs are appended to the existing file. +If the existing log file was created with a different snaplen, +.Nm +temporarily uses the old snaplen to keep the log file consistent. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl d Ar delay +Time in seconds to delay between automatic flushes of the file. +This may be specified with a value between 5 and 3600 seconds. +If not specified, the default is 60 seconds. +.It Fl D +Debugging mode. +.Nm +does not disassociate from the controlling terminal. +.It Fl f Ar filename +Log output filename. +Default is +.Pa /var/log/pflog . +.It Fl s Ar snaplen +Analyze at most the first +.Ar snaplen +bytes of data from each packet rather than the default of 96. +The default of 96 is adequate for IP, ICMP, TCP, and UDP headers but may +truncate protocol information for other protocols. +Other file parsers may desire a higher snaplen. +.It Ar expression +Selects which packets will be dumped, using the regular language of +.Xr tcpdump 8 . +.El +.Sh FILES +.Bl -tag -width /var/run/pflogd.pid -compact +.It Pa /var/run/pflogd.pid +Process ID of the currently running +.Nm pflogd . +.It Pa /var/log/pflog +Default log file. +.El +.Sh EXAMPLES +Log specific tcp packets to a different log file with a large snaplen +(useful with a log-all rule to dump complete sessions) +.Bd -literal -offset indent +# pflogd -s 1600 -f suspicious.log port 80 and host evilhost +.Ed +.Pp +Display binary logs: +.Bd -literal -offset indent +# tcpdump -n -e -ttt -r /var/log/pflog +.Ed +.Pp +Display the logs in real time (this does not interfere with the +operation of pflogd): +.Bd -literal -offset indent +# tcpdump -n -e -ttt -i pflog0 +.Ed +.Pp +Tcpdump has been extended to be able to filter on the pfloghdr +structure defined in +.Aq Ar net/if_pflog.h . +Tcpdump can restrict the output +to packets logged on a specified interface, a rule number, a reason, +a direction, an ip family or an action. +.Pp +.Bl -tag -width "reason match " -compact +.It ip +Address family equals IPv4. +.It ip6 +Address family equals IPv6. +.It ifname kue0 +Interface name equals "kue0" +.It on kue0 +Interface name equals "kue0" +.It rulenum 10 +Rule number equals 10. +.It reason match +Reason equals match. +Also accepts "bad-offset", "fragment", "short", "normalize" and "memory". +.It action pass +Action equals pass. +Also accepts "block". +.It inbound +The direction was inbound. +.It outbound +The direction was outbound. +.El +.Pp +Display the logs in real time of inbound packets that were blocked on +the wi0 interface: +.Bd -literal -offset indent +# tcpdump -n -e -ttt -i pflog0 inbound and action block and on wi0 +.Ed +.Sh SEE ALSO +.Xr pcap 3 , +.Xr pf 4 , +.Xr pflog 4 , +.Xr pf.conf 5 , +.Xr newsyslog 8 , +.Xr tcpdump 8 +.Sh HISTORY +The +.Nm +command appeared in +.Ox 3.0 . +.Sh AUTHORS +Can Erkin Acar diff --git a/contrib/pf/pflogd/pflogd.c b/contrib/pf/pflogd/pflogd.c new file mode 100644 index 0000000..9777f15 --- /dev/null +++ b/contrib/pf/pflogd/pflogd.c @@ -0,0 +1,400 @@ +/* $OpenBSD: pflogd.c,v 1.21 2003/08/22 21:50:34 david Exp $ */ + +/* + * Copyright (c) 2001 Theo de Raadt + * Copyright (c) 2001 Can Erkin Acar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <pcap-int.h> +#include <pcap.h> +#include <syslog.h> +#include <signal.h> +#include <errno.h> +#include <stdarg.h> +#include <fcntl.h> +#include <util.h> + +#define DEF_SNAPLEN 116 /* default plus allow for larger header of pflog */ +#define PCAP_TO_MS 500 /* pcap read timeout (ms) */ +#define PCAP_NUM_PKTS 1000 /* max number of packets to process at each loop */ +#define PCAP_OPT_FIL 0 /* filter optimization */ +#define FLUSH_DELAY 60 /* flush delay */ + +#define PFLOGD_LOG_FILE "/var/log/pflog" +#define PFLOGD_DEFAULT_IF "pflog0" + +pcap_t *hpcap; +pcap_dumper_t *dpcap; + +int Debug = 0; +int snaplen = DEF_SNAPLEN; + +volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup; + +char *filename = PFLOGD_LOG_FILE; +char *interface = PFLOGD_DEFAULT_IF; +char *filter = NULL; + +char errbuf[PCAP_ERRBUF_SIZE]; + +int log_debug = 0; +unsigned int delay = FLUSH_DELAY; + +char *copy_argv(char * const *argv); +int init_pcap(void); +void logmsg(int priority, const char *message, ...); +int reset_dump(void); +void sig_alrm(int); +void sig_close(int); +void sig_hup(int); +void usage(void); + + +char * +copy_argv(char * const *argv) +{ + size_t len = 0, n; + char *buf; + + if (argv == NULL) + return (NULL); + + for (n = 0; argv[n]; n++) + len += strlen(argv[n])+1; + if (len == 0) + return (NULL); + + buf = malloc(len); + if (buf == NULL) + return (NULL); + + strlcpy(buf, argv[0], len); + for (n = 1; argv[n]; n++) { + strlcat(buf, " ", len); + strlcat(buf, argv[n], len); + } + return (buf); +} + +void +logmsg(int pri, const char *message, ...) +{ + va_list ap; + va_start(ap, message); + + if (log_debug) { + vfprintf(stderr, message, ap); + fprintf(stderr, "\n"); + } else + vsyslog(pri, message, ap); + va_end(ap); +} + +__dead void +usage(void) +{ + fprintf(stderr, "usage: pflogd [-D] [-d delay] [-f filename] "); + fprintf(stderr, "[-s snaplen] [expression]\n"); + exit(1); +} + +void +sig_close(int sig) +{ + gotsig_close = 1; +} + +void +sig_hup(int sig) +{ + gotsig_hup = 1; +} + +void +sig_alrm(int sig) +{ + gotsig_alrm = 1; +} + +int +init_pcap(void) +{ + struct bpf_program bprog; + pcap_t *oldhpcap = hpcap; + + hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf); + if (hpcap == NULL) { + logmsg(LOG_ERR, "Failed to initialize: %s", errbuf); + hpcap = oldhpcap; + return (-1); + } + + if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0) + logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap)); + else if (pcap_setfilter(hpcap, &bprog) < 0) + logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap)); + if (filter != NULL) + free(filter); + + if (pcap_datalink(hpcap) != DLT_PFLOG) { + logmsg(LOG_ERR, "Invalid datalink type"); + pcap_close(hpcap); + hpcap = oldhpcap; + return (-1); + } + + if (oldhpcap) + pcap_close(oldhpcap); + + snaplen = pcap_snapshot(hpcap); + return (0); +} + +int +reset_dump(void) +{ + struct pcap_file_header hdr; + struct stat st; + int tmpsnap; + FILE *fp; + + if (hpcap == NULL) + return (1); + if (dpcap) { + pcap_dump_close(dpcap); + dpcap = 0; + } + + /* + * Basically reimplement pcap_dump_open() because it truncates + * files and duplicates headers and such. + */ + fp = fopen(filename, "a+"); + if (fp == NULL) { + snprintf(hpcap->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + filename, pcap_strerror(errno)); + logmsg(LOG_ERR, "Error: %s", pcap_geterr(hpcap)); + return (1); + } + if (fstat(fileno(fp), &st) == -1) { + snprintf(hpcap->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + filename, pcap_strerror(errno)); + logmsg(LOG_ERR, "Error: %s", pcap_geterr(hpcap)); + return (1); + } + + dpcap = (pcap_dumper_t *)fp; + +#define TCPDUMP_MAGIC 0xa1b2c3d4 + + if (st.st_size == 0) { + if (snaplen != pcap_snapshot(hpcap)) { + logmsg(LOG_NOTICE, "Using snaplen %d", snaplen); + if (init_pcap()) { + logmsg(LOG_ERR, "Failed to initialize"); + if (hpcap == NULL) return (-1); + logmsg(LOG_NOTICE, "Using old settings"); + } + } + hdr.magic = TCPDUMP_MAGIC; + hdr.version_major = PCAP_VERSION_MAJOR; + hdr.version_minor = PCAP_VERSION_MINOR; + hdr.thiszone = hpcap->tzoff; + hdr.snaplen = hpcap->snapshot; + hdr.sigfigs = 0; + hdr.linktype = hpcap->linktype; + + if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) { + dpcap = NULL; + fclose(fp); + return (-1); + } + return (0); + } + + /* + * XXX Must read the file, compare the header against our new + * options (in particular, snaplen) and adjust our options so + * that we generate a correct file. + */ + (void) fseek(fp, 0L, SEEK_SET); + if (fread((char *)&hdr, sizeof(hdr), 1, fp) == 1) { + if (hdr.magic != TCPDUMP_MAGIC || + hdr.version_major != PCAP_VERSION_MAJOR || + hdr.version_minor != PCAP_VERSION_MINOR || + hdr.linktype != hpcap->linktype) { + logmsg(LOG_ERR, + "Invalid/incompatible log file, move it away"); + fclose(fp); + return (1); + } + if (hdr.snaplen != snaplen) { + logmsg(LOG_WARNING, + "Existing file specifies a snaplen of %u, using it", + hdr.snaplen); + tmpsnap = snaplen; + snaplen = hdr.snaplen; + if (init_pcap()) { + logmsg(LOG_ERR, "Failed to re-initialize"); + if (hpcap == 0) + return (-1); + logmsg(LOG_NOTICE, + "Using old settings, offset: %llu", + (unsigned long long)st.st_size); + } + snaplen = tmpsnap; + } + } + + (void) fseek(fp, 0L, SEEK_END); + return (0); +} + +int +main(int argc, char **argv) +{ + struct pcap_stat pstat; + int ch, np; + + while ((ch = getopt(argc, argv, "Dd:s:f:")) != -1) { + switch (ch) { + case 'D': + Debug = 1; + break; + case 'd': + delay = atoi(optarg); + if (delay < 5 || delay > 60*60) + usage(); + break; + case 'f': + filename = optarg; + break; + case 's': + snaplen = atoi(optarg); + if (snaplen <= 0) + snaplen = DEF_SNAPLEN; + break; + default: + usage(); + } + + } + + log_debug = Debug; + argc -= optind; + argv += optind; + + if (!Debug) { + openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON); + if (daemon(0, 0)) { + logmsg(LOG_WARNING, "Failed to become daemon: %s", + strerror(errno)); + } + pidfile(NULL); + } + + (void)umask(S_IRWXG | S_IRWXO); + + signal(SIGTERM, sig_close); + signal(SIGINT, sig_close); + signal(SIGQUIT, sig_close); + signal(SIGALRM, sig_alrm); + signal(SIGHUP, sig_hup); + alarm(delay); + + if (argc) { + filter = copy_argv(argv); + if (filter == NULL) + logmsg(LOG_NOTICE, "Failed to form filter expression"); + } + + if (init_pcap()) { + logmsg(LOG_ERR, "Exiting, init failure"); + exit(1); + } + + if (reset_dump()) { + logmsg(LOG_ERR, "Failed to open log file %s", filename); + pcap_close(hpcap); + exit(1); + } + + while (1) { + np = pcap_dispatch(hpcap, PCAP_NUM_PKTS, pcap_dump, (u_char *)dpcap); + if (np < 0) + logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap)); + + if (gotsig_close) + break; + if (gotsig_hup) { + if (reset_dump()) { + logmsg(LOG_ERR, "Failed to open log file!"); + break; + } + logmsg(LOG_NOTICE, "Reopened logfile"); + gotsig_hup = 0; + } + + if (gotsig_alrm) { + /* XXX pcap_dumper is an incomplete type which libpcap + * casts to a FILE* currently. For now it is safe to + * make the same assumption, however this may change + * in the future. + */ + if (dpcap) { + if (fflush((FILE *)dpcap) == EOF) { + break; + } + } + gotsig_alrm = 0; + alarm(delay); + } + } + + logmsg(LOG_NOTICE, "Exiting due to signal"); + if (dpcap) + pcap_dump_close(dpcap); + + if (pcap_stats(hpcap, &pstat) < 0) + logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap)); + else + logmsg(LOG_NOTICE, "%u packets received, %u dropped", + pstat.ps_recv, pstat.ps_drop); + + pcap_close(hpcap); + if (!Debug) + closelog(); + return (0); +} |