Module Name: src Committed By: christos Date: Fri Jan 6 19:20:24 UTC 2017
Modified Files: src/usr.sbin/npf/npfd: Makefile npfd.c npfd.h npfd_log.c Log Message: Add log validation To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/npf/npfd/Makefile \ src/usr.sbin/npf/npfd/npfd.h cvs rdiff -u -r1.4 -r1.5 src/usr.sbin/npf/npfd/npfd.c cvs rdiff -u -r1.5 -r1.6 src/usr.sbin/npf/npfd/npfd_log.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/npf/npfd/Makefile diff -u src/usr.sbin/npf/npfd/Makefile:1.3 src/usr.sbin/npf/npfd/Makefile:1.4 --- src/usr.sbin/npf/npfd/Makefile:1.3 Fri Dec 30 14:55:46 2016 +++ src/usr.sbin/npf/npfd/Makefile Fri Jan 6 14:20:24 2017 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.3 2016/12/30 19:55:46 christos Exp $ +# $NetBSD: Makefile,v 1.4 2017/01/06 19:20:24 christos Exp $ # # Public Domain # @@ -6,7 +6,7 @@ NOMAN= PROG= npfd -#DBG=-g +DBG=-g SRCS= npfd.c npfd_log.c CPPFLAGS+= -I${.CURDIR} Index: src/usr.sbin/npf/npfd/npfd.h diff -u src/usr.sbin/npf/npfd/npfd.h:1.3 src/usr.sbin/npf/npfd/npfd.h:1.4 --- src/usr.sbin/npf/npfd/npfd.h:1.3 Fri Dec 30 14:55:46 2016 +++ src/usr.sbin/npf/npfd/npfd.h Fri Jan 6 14:20:24 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: npfd.h,v 1.3 2016/12/30 19:55:46 christos Exp $ */ +/* $NetBSD: npfd.h,v 1.4 2017/01/06 19:20:24 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -42,7 +42,7 @@ struct npf_log; typedef struct npfd_log npfd_log_t; -npfd_log_t * npfd_log_create(const char *, const char *, int); +npfd_log_t * npfd_log_create(const char *, const char *, const char *, int); void npfd_log_destroy(npfd_log_t *); int npfd_log_getsock(npfd_log_t *); bool npfd_log_reopen(npfd_log_t *, bool); Index: src/usr.sbin/npf/npfd/npfd.c diff -u src/usr.sbin/npf/npfd/npfd.c:1.4 src/usr.sbin/npf/npfd/npfd.c:1.5 --- src/usr.sbin/npf/npfd/npfd.c:1.4 Fri Dec 30 14:55:46 2016 +++ src/usr.sbin/npf/npfd/npfd.c Fri Jan 6 14:20:24 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: npfd.c,v 1.4 2016/12/30 19:55:46 christos Exp $ */ +/* $NetBSD: npfd.c,v 1.5 2017/01/06 19:20:24 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: npfd.c,v 1.4 2016/12/30 19:55:46 christos Exp $"); +__RCSID("$NetBSD: npfd.c,v 1.5 2017/01/06 19:20:24 christos Exp $"); #include <stdio.h> #include <string.h> @@ -49,7 +49,7 @@ __RCSID("$NetBSD: npfd.c,v 1.4 2016/12/3 #include "npfd.h" -static volatile sig_atomic_t hup, stats, done; +static volatile sig_atomic_t hup, stats, done, flush; static int npfd_getctl(void) @@ -87,6 +87,9 @@ npfd_event_loop(npfd_log_t *log, int del if (stats) { stats = false; npfd_log_stats(log); + } + if (flush) { + flush = false; npfd_log_flush(log); } switch (poll(&pfd, 1, delay)) { @@ -118,9 +121,11 @@ sighandler(int sig) done = true; break; case SIGINFO: - case SIGQUIT: stats = true; break; + case SIGALRM: + flush = true; + break; default: syslog(LOG_ERR, "Unhandled signal %d", sig); break; @@ -131,7 +136,8 @@ static __dead void usage(void) { fprintf(stderr, "Usage: %s [-D] [-d <delay>] [-i <interface>]" - " [-p <pidfile>] [-s <snaplen>] expression\n", getprogname()); + " [-f <filename>] [-p <pidfile>] [-s <snaplen>] expression\n", + getprogname()); exit(EXIT_FAILURE); } @@ -165,11 +171,12 @@ main(int argc, char **argv) const char *iface = "npflog0"; int snaplen = 116; char *pidname = NULL; + char *filename = NULL; int fd = npfd_getctl(); (void)close(fd); - while ((ch = getopt(argc, argv, "Dd:i:p:s:")) != -1) { + while ((ch = getopt(argc, argv, "Dd:f:i:p:s:")) != -1) { switch (ch) { case 'D': daemon_off = true; @@ -177,6 +184,9 @@ main(int argc, char **argv) case 'd': delay = atoi(optarg) * 1000; break; + case 'f': + filename = optarg; + break; case 'i': iface = optarg; break; @@ -196,7 +206,7 @@ main(int argc, char **argv) char *filter = copyargs(argc, argv); - npfd_log_t *log = npfd_log_create(iface, filter, snaplen); + npfd_log_t *log = npfd_log_create(filename, iface, filter, snaplen); if (!daemon_off) { if (daemon(0, 0) == -1) Index: src/usr.sbin/npf/npfd/npfd_log.c diff -u src/usr.sbin/npf/npfd/npfd_log.c:1.5 src/usr.sbin/npf/npfd/npfd_log.c:1.6 --- src/usr.sbin/npf/npfd/npfd_log.c:1.5 Thu Jan 5 11:23:31 2017 +++ src/usr.sbin/npf/npfd/npfd_log.c Fri Jan 6 14:20:24 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: npfd_log.c,v 1.5 2017/01/05 16:23:31 christos Exp $ */ +/* $NetBSD: npfd_log.c,v 1.6 2017/01/06 19:20:24 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -30,10 +30,12 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: npfd_log.c,v 1.5 2017/01/05 16:23:31 christos Exp $"); +__RCSID("$NetBSD: npfd_log.c,v 1.6 2017/01/06 19:20:24 christos Exp $"); #include <sys/types.h> #include <sys/param.h> +#include <sys/stat.h> + #include <net/if.h> #include <stdio.h> @@ -69,8 +71,138 @@ npfd_log_setfilter(npfd_log_t *ctx, cons pcap_freecode(&bprog); } +static FILE * +npfd_log_gethdr(npfd_log_t *ctx, struct pcap_file_header*hdr) +{ + FILE *fp = fopen(ctx->path, "r"); + + hdr->magic = 0; + if (fp == NULL) + return NULL; + +#define TCPDUMP_MAGIC 0xa1b2c3d4 + + switch (fread(hdr, sizeof(*hdr), 1, fp)) { + case 0: + hdr->magic = 0; + fclose(fp); + return NULL; + case 1: + if (hdr->magic != TCPDUMP_MAGIC || + hdr->version_major != PCAP_VERSION_MAJOR || + hdr->version_minor != PCAP_VERSION_MINOR) + goto out; + break; + default: + goto out; + } + + return fp; +out: + fclose(fp); + hdr->magic = -1; + return NULL; +} + +static int +npfd_log_getsnaplen(npfd_log_t *ctx) +{ + struct pcap_file_header hdr; + FILE *fp = npfd_log_gethdr(ctx, &hdr); + if (fp == NULL) + return hdr.magic == (uint32_t)-1 ? -1 : 0; + fclose(fp); + return hdr.snaplen; +} + +static int +npfd_log_validate(npfd_log_t *ctx) +{ + struct pcap_file_header hdr; + FILE *fp = npfd_log_gethdr(ctx, &hdr); + size_t o, no; + + if (fp == NULL) { + if (hdr.magic == 0) + return 0; + goto rename; + } + + struct stat st; + if (fstat(fileno(fp), &st) == -1) + goto rename; + + size_t count = 0; + for (o = sizeof(hdr);; count++) { + struct { + uint32_t sec; + uint32_t usec; + uint32_t caplen; + uint32_t len; + } pkt; + switch (fread(&pkt, sizeof(pkt), 1, fp)) { + case 0: + syslog(LOG_INFO, "%zu packets read from `%s'", count, + ctx->path); + fclose(fp); + return hdr.snaplen; + case 1: + no = o + sizeof(pkt) + pkt.caplen; + if (pkt.caplen > hdr.snaplen) + goto fix; + if (no > (size_t)st.st_size) + goto fix; + if (fseeko(fp, pkt.caplen, SEEK_CUR) != 0) + goto fix; + o = no; + break; + default: + goto fix; + } + } + +fix: + fclose(fp); + no = st.st_size - o; + syslog(LOG_INFO, "%zu packets read from `%s', %zu extra bytes", + count, ctx->path, no); + if (no < 10240) { + syslog(LOG_WARNING, + "Incomplete last packet in `%s', truncating", + ctx->path); + if (truncate(ctx->path, o) == -1) { + syslog(LOG_ERR, "Cannot truncate `%s': %m", ctx->path); + goto rename; + } + } else { + syslog(LOG_ERR, "Corrupt file `%s'", ctx->path); + goto rename; + } + fclose(fp); + return hdr.snaplen; +rename: + fclose(fp); + char tmp[MAXPATHLEN]; + snprintf(tmp, sizeof(tmp), "%s.XXXXXX", ctx->path); + int fd; + if ((fd = mkstemp(tmp)) == -1) { + syslog(LOG_ERR, "Can't make temp file `%s': %m", tmp); + return -1; + } + close(fd); + if (rename(ctx->path, tmp) == -1) { + syslog(LOG_ERR, "Can't rename `%s' to `%s': %m", + ctx->path, tmp); + return -1; + } + syslog(LOG_ERR, "Renamed to `%s'", tmp); + return 0; +} + + npfd_log_t * -npfd_log_create(const char *ifname, const char *filter, int snaplen) +npfd_log_create(const char *filename, const char *ifname, const char *filter, + int snaplen) { npfd_log_t *ctx; char errbuf[PCAP_ERRBUF_SIZE]; @@ -89,6 +221,22 @@ npfd_log_create(const char *ifname, cons if (pcap_setnonblock(ctx->pcap, 1, errbuf) == -1) errx(EXIT_FAILURE, "pcap_setnonblock failed: %s", errbuf); + if (filename == NULL) + snprintf(ctx->path, sizeof(ctx->path), NPFD_LOG_PATH "/%s.pcap", + ctx->ifname); + else + snprintf(ctx->path, sizeof(ctx->path), "%s", filename); + + int sl = npfd_log_getsnaplen(ctx); + if (sl == -1) + errx(EXIT_FAILURE, "corrupt log file `%s'", ctx->path); + + if (sl != 0 && sl != snaplen) { + warnx("Overriding snaplen from %d to %d from `%s'", snaplen, + sl, filename); + snaplen = sl; + } + if (pcap_set_snaplen(ctx->pcap, snaplen) == -1) errx(EXIT_FAILURE, "pcap_set_snaplen failed: %s", pcap_geterr(ctx->pcap)); @@ -104,10 +252,8 @@ npfd_log_create(const char *ifname, cons if (filter) npfd_log_setfilter(ctx, filter); - snprintf(ctx->path, sizeof(ctx->path), NPFD_LOG_PATH "/%s.pcap", - ctx->ifname); - npfd_log_reopen(ctx, true); + npfd_log_reopen(ctx, false); return ctx; } @@ -119,10 +265,19 @@ npfd_log_reopen(npfd_log_t *ctx, bool di /* * Open a log file to write for a given interface and dump there. */ - if (access(ctx->path, F_OK) == 0) - ctx->dumper = pcap_dump_open_append(ctx->pcap, ctx->path); - else + switch (npfd_log_validate(ctx)) { + case -1: + syslog(LOG_ERR, "Giving up"); + exit(EXIT_FAILURE); + /*NOTREACHED*/ + case 0: ctx->dumper = pcap_dump_open(ctx->pcap, ctx->path); + break; + default: + ctx->dumper = pcap_dump_open_append(ctx->pcap, ctx->path); + break; + } + if (ctx->dumper == NULL) { if (die) errx(EXIT_FAILURE, "pcap_dump_open failed for `%s': %s",