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

Reply via email to