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",