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 All rights reserved. + * Copyright (c) 2003,2004 Damien Miller * - * 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 #include @@ -54,7 +46,7 @@ #include #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':