Index: ChangeLog
===================================================================
RCS file: /var/cvs/pfflowd/ChangeLog,v
retrieving revision 1.8
retrieving revision 1.15
diff -u -r1.8 -r1.15
--- ChangeLog	16 Feb 2004 03:31:32 -0000	1.8
+++ ChangeLog	6 May 2004 04:06:45 -0000	1.15
@@ -1,4 +1,19 @@
-20030216
+20040506
+ - (djm) Change license to simplified ISC license, update copyright year
+ - (djm) Tidy README
+ - (djm) Release pfflowd-0.4
+
+20040415
+ - (djm) Fix uninitialised getsockopt len
+
+20040315
+ - (djm) Clear socket errors before send(), stops pfflowd dropping packets 
+   when it receives ICMP errors
+ - (djm) Fix flow_start and flow_finish computation. These should be 
+   relative to SysUptime, not epoch. Spotted by Niels Provos
+ - (djm) Add basic filtering on state direction
+
+20040216
  - (djm) Make this work with -current pfsync
  - (djm) Add support for older pfsync (<=3.4) with -DOLD_PFSYNC flag
  - (djm) Release pfflowd-0.4
Index: README
===================================================================
RCS file: /var/cvs/pfflowd/README,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- README	16 Feb 2004 03:30:46 -0000	1.5
+++ README	6 May 2004 04:05:30 -0000	1.6
@@ -18,9 +18,9 @@
 
 PLEASE NOTE: 
 
-1. By default, pfflowd only supports OpenBSD -current as of 2004-02-16. 
-This can be changed by setting the OLD_PFSYNC flag in the Makefile, in 
-which case pfflowd will support only OpenBSD <= 3.4.
+1. By default, pfflowd only supports OpenBSD 3.5. This can be changed by 
+setting the OLD_PFSYNC flag in the Makefile, in which case pfflowd will 
+support only OpenBSD <= 3.4.
 
 2. pfflowd required kernel changes to pffsync committed after OpenBSD 3.3 
 was released. The included pfsync-bidi-3.3.diff should bring this support, 
Index: pfflowd.8
===================================================================
RCS file: /var/cvs/pfflowd/pfflowd.8,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- pfflowd.8	9 Nov 2003 00:50:54 -0000	1.4
+++ pfflowd.8	15 Mar 2004 03:35:47 -0000	1.5
@@ -1,4 +1,4 @@
-.\" $Id: pfflowd.8,v 1.4 2003/11/09 00:50:54 djm Exp $
+.\" $Id: pfflowd.8,v 1.5 2004/03/15 03:35:47 djm Exp $
 .\"
 .\" Copyright (c) 2003 Damien Miller.  All rights reserved.
 .\"
@@ -34,6 +34,7 @@
 .Op Fl i Ar interface
 .Op Fl r Ar pcap_file
 .Op Fl n Ar host:port
+.Op Fl S Ar direction
 .Op bpf_program
 .Sh DESCRIPTION
 .Nm
@@ -52,6 +53,21 @@
 .Pp
 The command-line options are as follows:
 .Bl -tag -width Ds
+.It Fl S Ar direction
+Restrict creation of flow records to states matching 
+.Ar direction,
+which may be 
+.Ar in ,
+.Ar out
+or
+.Ar any
+(default: any).
+This corresponds to the direction specified in the 
+.Xr pf 4
+rule that caused the generation of the state.
+E.g. a "pass in ... keep state" rule corresponds to a 
+.Ar in
+direction.
 .It Fl n Ar host:port
 Specify the 
 .Ar host
Index: pfflowd.c
===================================================================
RCS file: /var/cvs/pfflowd/pfflowd.c,v
retrieving revision 1.9
retrieving revision 1.15
diff -u -r1.9 -r1.15
--- pfflowd.c	16 Feb 2004 03:30:46 -0000	1.9
+++ pfflowd.c	6 May 2004 04:06:45 -0000	1.15
@@ -1,28 +1,20 @@
 /*
- * Copyright 2003 Damien Miller <djm@mindrot.org> All rights reserved.
+ * Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org>
  *
- * 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.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: pfflowd.c,v 1.9 2004/02/16 03:30:46 djm Exp $ */
+/* $Id: pfflowd.c,v 1.15 2004/05/06 04:06:45 djm Exp $ */
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -54,7 +46,7 @@
 #include <util.h>
 
 #define	PROGNAME		"pfflowd"
-#define	PROGVER			"0.3"
+#define	PROGVER			"0.5"
 
 #ifndef PRIVDROP_USER
 # define PRIVDROP_USER		"nobody"
@@ -77,6 +69,7 @@
 static int exit_flag = 0;		/* Signal handler flags */
 static struct timeval start_time;	/* "System boot" time, for SysUptime */
 static int netflow_socket = -1;
+static int direction = 0;
 
 /*
  * This is the Cisco Netflow(tm) version 1 packet format
@@ -159,6 +152,7 @@
 	fprintf(stderr, "  -i interface    Specify interface to listen on (default %s)\n", DEFAULT_INTERFACE);
 	fprintf(stderr, "  -n host:port    Send NetFlow datagrams to host on port (mandatory)\n");
 	fprintf(stderr, "  -r pcap_file    Specify packet capture file to read\n");
+	fprintf(stderr, "  -S direction    Generation flows for \"in\" or \"out\" bound states (default any)\n");
 	fprintf(stderr, "  -d              Don't daemonise\n");
 	fprintf(stderr, "  -D              Debug mode: don't daemonise + verbosity\n");
 	fprintf(stderr, "  -h              Display this help\n");
@@ -281,7 +275,8 @@
 	u_int8_t packet[NF1_MAXPACKET_SIZE];	/* Maximum allowed packet size (24 flows) */
 	struct NF1_HEADER *hdr = NULL;
 	struct NF1_FLOW *flw = NULL;
-	int j, offset, num_packets;
+	int j, offset, num_packets, err;
+	socklen_t errsz;
 
 	if (phdr->caplen < PFSYNC_HDRLEN) {
 		syslog(LOG_WARNING, "Runt pfsync packet header");
@@ -315,10 +310,10 @@
 		struct pf_state_host src, dst;
 		u_int32_t bytes_in, bytes_out;
 		u_int32_t packets_in, packets_out;
-		char src_s[64], dst_s[64], pbuf[16], creation_s[64];
-		time_t creation;
+		char src_s[64], dst_s[64], rt_s[64], pbuf[16], creation_s[64];
+		time_t creation_tt;
+		u_int32_t creation;
 		struct tm creation_tm;
-		struct timeval creation_tv;
 
 		off = sizeof(*ph) + (sizeof(*st) * i);
 		if (off + sizeof(*st) > phdr->caplen) {
@@ -330,8 +325,14 @@
 			if (verbose_flag)
 				syslog(LOG_DEBUG, "Sending flow packet len = %d", offset);
 			hdr->flows = htons(hdr->flows);
-			if (send(netflow_socket, packet, (size_t)offset, 0) == -1)
-				return;
+			errsz = sizeof(err);
+			getsockopt(netflow_socket, SOL_SOCKET, SO_ERROR,
+			    &err, &errsz); /* Clear ICMP errors */
+			if (send(netflow_socket, packet,
+			    (size_t)offset, 0) == -1) {
+				syslog(LOG_DEBUG, "send: %s", strerror(errno));
+				return;	
+			}
 			j = 0;
 			num_packets++;
 		}
@@ -349,11 +350,12 @@
 		st = (const struct _PFSYNC_STATE *)(pkt + off);
 		if (st->af != AF_INET)
 			continue; /* XXX IPv6 support */
-
+		if (direction != 0 && st->direction != direction)
+			continue;
 		/* Copy/convert only what we can eat */
-		creation = now - ntohl(st->creation);
-		creation_tv.tv_sec = creation;
-		creation_tv.tv_usec = 0;
+		creation = ntohl(st->creation) * 1000;
+		if (creation > uptime_ms)
+			creation = uptime_ms; /* Avoid u_int wrap */
 
 		if (st->direction == PF_OUT) {
 			memcpy(&src, &st->lan, sizeof(src));
@@ -372,8 +374,8 @@
 			flw->dest_port = dst.port;
 			flw->flow_packets = st->packets[0];
 			flw->flow_octets = st->bytes[0];
-			flw->flow_start = htonl(timeval_sub_ms(&creation_tv, &start_time));
-			flw->flow_finish = htonl(timeval_sub_ms(&now_tv, &start_time));
+			flw->flow_start = htonl(uptime_ms - creation);
+			flw->flow_finish = htonl(uptime_ms);
 			flw->protocol = st->proto;
 			flw->tcp_flags = 0;
 			offset += sizeof(*flw);
@@ -388,8 +390,8 @@
 			flw->dest_port = src.port;
 			flw->flow_packets = st->packets[1];
 			flw->flow_octets = st->bytes[1];
-			flw->flow_start = htonl(timeval_sub_ms(&creation_tv, &start_time));
-			flw->flow_finish = htonl(timeval_sub_ms(&now_tv, &start_time));
+			flw->flow_start = htonl(uptime_ms - creation);
+			flw->flow_finish = htonl(uptime_ms);
 			flw->protocol = st->proto;
 			flw->tcp_flags = 0;
 			offset += sizeof(*flw);
@@ -404,12 +406,14 @@
 			bytes_out = ntohl(st->bytes[0]);
 			bytes_in = ntohl(st->bytes[1]);
 
-			localtime_r(&creation, &creation_tm);
+			creation_tt = now - (creation / 1000);
+			localtime_r(&creation_tt, &creation_tm);
 			strftime(creation_s, sizeof(creation_s), 
 			    "%Y-%m-%dT%H:%M:%S", &creation_tm);
 
 			format_pf_host(src_s, sizeof(src_s), &src, st->af);
 			format_pf_host(dst_s, sizeof(dst_s), &dst, st->af);
+			inet_ntop(st->af, &st->rt_addr, rt_s, sizeof(rt_s));
 
 			if (st->proto == IPPROTO_TCP || 
 			    st->proto == IPPROTO_UDP) {
@@ -421,10 +425,13 @@
 				strlcat(dst_s, pbuf, sizeof(dst_s));
 			}
 
+			syslog(LOG_DEBUG, "IFACE %s\n", st->ifname); 
+			syslog(LOG_DEBUG, "GWY %s\n", rt_s); 
 			syslog(LOG_DEBUG, "FLOW proto %d direction %d", 
 			    st->proto, st->direction);
-			syslog(LOG_DEBUG, "\tstart %s finish %s",
-			    creation_s, now_s);
+			syslog(LOG_DEBUG, "\tstart %s(%u) finish %s(%u)",
+			    creation_s, uptime_ms - creation, 
+			    now_s, uptime_ms);
 			syslog(LOG_DEBUG, "\t%s -> %s %d bytes %d packets",
 			    src_s, dst_s, bytes_out, packets_out);
 			syslog(LOG_DEBUG, "\t%s -> %s %d bytes %d packets",
@@ -436,8 +443,13 @@
 		if (verbose_flag)
 			syslog(LOG_DEBUG, "Sending flow packet len = %d", offset);
 		hdr->flows = htons(hdr->flows);
-		if (send(netflow_socket, packet, (size_t)offset, 0) == -1)
-			return;
+		errsz = sizeof(err);
+		getsockopt(netflow_socket, SOL_SOCKET, SO_ERROR,
+		    &err, &errsz); /* Clear ICMP errors */
+		if (send(netflow_socket, packet, (size_t)offset, 0) == -1) {
+			syslog(LOG_DEBUG, "send: %s", strerror(errno));
+			return;	
+		}
 		num_packets++;
 	}
 
@@ -540,9 +552,24 @@
 	dev = capfile = NULL;
 	dontfork_flag = 0;
 	memset(&netflow_dest, '\0', sizeof(netflow_dest));
-	while ((ch = getopt(argc, argv, "hdDi:n:r:")) != -1) {
+	while ((ch = getopt(argc, argv, "hdDi:n:r:S:")) != -1) {
 		switch (ch) {
 		case 'h':
+			usage();
+			return (0);
+		case 'S':
+			if (strcasecmp(optarg, "any") == 0) {
+				direction = 0;
+				break;
+			}
+			if (strcasecmp(optarg, "in") == 0) {
+				direction = PF_IN;
+				break;
+			}
+			if (strcasecmp(optarg, "out") == 0) {
+				direction = PF_OUT;
+				break;
+			}
 			usage();
 			return (0);
 		case 'D':
