Browse Source

Import upstream version 0.9.8

Christoph Biedl 11 years ago
commit
12845c26e9
34 changed files with 15753 additions and 0 deletions
  1. 238 0
      ChangeLog
  2. 146 0
      LICENSE
  3. 59 0
      Makefile.in
  4. 67 0
      README
  5. 104 0
      TODO
  6. 1 0
      aclocal.m4
  7. 100 0
      closefrom.c
  8. 279 0
      collector.pl
  9. 169 0
      common.h
  10. 163 0
      config.h.in
  11. 9163 0
      configure
  12. 170 0
      configure.ac
  13. 89 0
      convtime.c
  14. 50 0
      convtime.h
  15. 81 0
      daemon.c
  16. 251 0
      install-sh
  17. 59 0
      log.c
  18. 33 0
      log.h
  19. 40 0
      mkinstalldirs
  20. 168 0
      netflow1.c
  21. 170 0
      netflow5.c
  22. 377 0
      netflow9.c
  23. 95 0
      softflowctl.8
  24. 114 0
      softflowctl.c
  25. 402 0
      softflowd.8
  26. 1934 0
      softflowd.c
  27. 210 0
      softflowd.h
  28. 68 0
      softflowd.init
  29. 50 0
      softflowd.spec
  30. 10 0
      softflowd.sysconfig
  31. 68 0
      strlcat.c
  32. 65 0
      strlcpy.c
  33. 677 0
      sys-tree.h
  34. 83 0
      treetype.h

+ 238 - 0
ChangeLog

@@ -0,0 +1,238 @@
+20061101
+ - (djm) Collect licenses into LICENSE file
+ - (djm) malloc(x*y) -> calloc(x, y)
+ - (djm) Sync sys-tree.h
+ - (djm) Release 0.9.8
+
+20060315
+ - (djm) Add "send-template" softflowctl command to resend a NetFlow 9
+   template record immediately
+
+20060315
+ - (djm) Fix DLT_RAW support, from jhanna AT shaw.ca 
+ - (djm) Support ${DESTDIR} in Makefile install target, from
+   ssnodgra AT pheran.com
+ - (djm) Encode ICMP type and code into port numbers (apparently this is
+   what Cisco exporters do), patch from ssnodgra AT pheran.com slightly
+   tweaked by me
+ - (djm) Crank version number to 0.9.8
+ - (djm) Add RPM packaging files from ssnodgra AT pheran.com
+
+20060214
+ - (djm) Add missing getopt() bit for flowtrack mode
+
+20060211
+ - (djm) Add option to ignore port and protocol information from flows,
+   allowing flows from the same IP addresses to be automatically
+   coalesced
+
+20060126
+ - (djm) Correctly expire quiescent flows when they hit maximum_lifetime; 
+   bug noticed and patch tested by andreas.brillisauer AT hetzner.de
+
+20051206
+ - (djm) Make sure installation directories exist, spotted by
+   alshu AT tut.by
+
+20051118
+ - (djm) Some extra paranoia and verbosity on malloc failures
+ - (djm) Support Linux "cooked socket" datalink type, from Tony Lewis 
+   gnutered AT yahoo.com.au
+
+20051001
+ - (djm) Fix typo, from rbreathe AT brookes.ac.uk
+
+20050505
+ - (djm) Fix time printing bug in debug mode
+ - (djm) Fix reversed NetFlow v.9 first_switched and last_switched times
+
+20050505
+ - (djm) Fix bug in sequence number generation. Reported by 
+   b.ghita AT jack.see.plymouth.ac.uk and mwlucas AT blackhelicopters.org
+ - (djm) Report pcap stats in statistics display
+
+20050114
+ - (djm) Release 0.9.7
+
+20050110
+ - (djm) Fix endianness problem in NetFlow v.9 port number export. Found and 
+   fixed by paolo.lucente AT ic.cnr.it
+ - (djm) Add option to set hoplimit/TTL in support of multicast export support
+ - (djm) Document multicast export
+
+20041109
+ - (djm) Test for struct ip6_ext in autoconf and define a replacement if 
+   missing, some systems lack it
+
+20040930
+ - (djm) Increase caplen a little for IPv6
+ - (djm) Remove unused debugging code from NetFlow v.9 support
+ - (djm) Add a timeout to cluster expiry expiry events, so we get more flows 
+    per packet. Default is to check for expiries every 60s
+ - (djm) Allow timouts to be disabled (by setting them to 0)
+ - (djm) Include IP_PROTOCOL_VERSION field in NetFlow v.9 packets
+ - (djm) Don't bother tracking IPv6 flows if NetFlow export version 
+   doesn't support it
+ - (djm) Don't crank up pcap snaplen unless we are interested in IPv6 either
+ - (djm) Unbreak v6 flow export
+ - (djm) Unbreak compilation on non-OpenBSD
+ - (djm) Update README with recent changes (NetFlow v.9, v6 flows)
+ - (djm) Release 0.9.6
+
+20040929
+ - (djm) Improve IPv6 code: track flowlables bidirectionally (but don't key on 
+   them for now), print addresses:port tuples unambiguously and apply correct 
+   timeout for ICMPv6 flows
+ - (djm) Remove NetFlow v.1 types from NetFlow v.5 code
+ - (djm) NetFlow v.9 support
+ 
+20040913
+ - (djm) Split out netflow send functions into separate files
+ - (djm) Switch to a table of netflow exporter functions in preparation for 
+   additional export protocols
+ - (djm) Collect netflow export target information together in a struct, in 
+   preparation for more export protocols and support for multiple export targets
+ - (djm) Optimise the datalink_check function, by caching the last datalink type
+   used.
+
+20040909
+ - (djm) Implement IPv6 flow tracking. Currently no export functionality.
+ - (djm) Portability fixes for Linux, add closefrom()
+ - (djm) Use strlcat/strlcpy instead of strn* functions
+ - (djm) Comment out dump_packet (uncomment when debugging)
+
+20040909
+ - (djm) inline is unnecessary
+ - (djm) Rework datalink processing, in preparation of IPv6 support
+ - (djm) Next step in preparation of IPv6 support: make flow structure and
+   lookup function support both IPv4 and IPv6 addresses (v6 addrs aren't yet
+   used)
+ - (djm) Another step on the road: factor out transport-layer protocol parsing
+   from IPv4 parsing code
+ - (djm) Be more careful about putting flows into canonical format
+ - (djm) Prepare for IPv6 packet to flow conversion routine
+
+20040901
+ - (djm) Fix a tiny, stupid bug that prevents flow export
+ - (djm) Release version 0.9.2
+
+20040827
+ - (djm) NetFlow v.5 supports 30 flows per packet
+ - (djm) Use struct sockaddr in arguments (not sockaddr_storage), properly 
+   check length
+ - (djm) Mention NetFlow v.5 support in manpage
+ - (djm) Release version 0.9.1
+
+20040716
+ - (djm) Fix collector.pl when no address family specified on commandline
+   spotted by pgennai AT netstarnetworks.com
+
+20040710
+ - (djm) Tidy up code: remove some debugging gunk, kill a global
+ - (djm) Add support for NetFlow v.5 export format to softflowd
+ - (djm) Add support for NetFlow v.5 export format to collector.pl
+
+20040430
+ - (djm) Release version 0.9
+
+20040417
+ - (djm) Fix invalid packet bug
+
+20040417
+ - (djm) Eliminate periodic expiry scans, wait in poll() only until the next 
+   scheduled expiry event
+ - (djm) Separate timeout for ICMP traffic, generic timeout is too long
+
+20040416
+ - (djm) A bunch of changes necessary to support building on Solaris 9 (though
+   the resultant binary doesn't seem to work properly):
+        - Use getaddrinfo instead of inet_aton to parse host/port for export
+        - Use setreuid if setresuid isn't around (ditto for gid)
+        - Add replacement daemon() function from OpenBSD
+        - Provide our own logit() function, because Solaris syslog() doesn't 
+          support LOG_PERROR
+        - A heap of configure and common.h additions and fixes
+ - (djm) Fix busted preprocessor
+ - (djm) Support "[host]:port" syntax to specify numeric IPv6 export target
+ - (djm) Fix connect() for IPv6 export targets
+ - (djm) IPv6 listen support for collector.pl
+ - (djm) Allow v4 operation of collector.pl if v6 modules aren't present
+ - (djm) More flow export fixes
+ - (djm) Tidy manpage and mention v6 export syntax
+ - (djm) Unbreak Solaris, pass socklen around instead of using sa_len
+ - (djm) Unbreak "make install"
+
+20040415
+ - (djm) Clear socket errors before UDP send; from pfflowd
+ - (djm) Print flow start and finish times in collector.pl
+ - (djm) Linux needs grp.h for setgroups()
+ - (djm) Never endprotoent()
+ - (djm) Use autoconf to detect various things; in preparation of more 
+   portability
+ - (djm) Detect int and define standard int types in configure
+
+20031111
+ - (djm) Remove -Werror from CFLAGS, it causes problems in released software
+
+20031109
+ - (djm) Give compile-time choice over flow and expiry event tree type
+   default is splay tree for flows and red-black tree for expiry events
+   (limited benchmarking indicates that this is the fastest)
+ - (djm) Lock the BPF device to prevent changes should the unpriv child
+   be compromised (only OpenBSD supports this ioctl for now)
+
+20031001
+ - (djm) Realloc audit
+ - (djm) Chroot to /var/empty and drop privileges on daemonisation
+ - (djm) More things TODO
+
+20030620
+ - (djm) Fixup collector timestamp printing
+ - (djm) Rework TODO, add section on planned fragment handling
+ - (djm) Add "strip" target to Makefile
+ - (djm) Add "help" keyword to recognised softflowctl responses
+ - (djm) Fix fragment handling bug: we would try to look into fragmented
+   payload on later fragments. This could cause random tcp/udp  port numbers
+   to be recorded.
+ - (djm) Fix malicious fragment handling bug: deliberately tiny fragments 
+   (e.g. http://citeseer.nj.nec.com/ptacek98insertion.html) would be ignored
+   and would not create flow entries.
+ - (djm) Count fragments that we have seen
+ - (djm) Release version 0.8.1
+
+20030307
+ - (djm) Add basic perl netflow collector
+
+20021110
+ - (djm) Refactor, dramatically shrink mainloop
+
+20021105
+ - (djm) Don't exit on failure to lookup net/mask. From Alejandro Roman 
+   <aroman@uyr.com.ar>
+
+20021031
+ - (djm) Add some examples to the manpage
+
+20021030
+ - (djm) New user-friendly time specification code from OpenSSH/Kevin Steves
+ - (djm) Always use local sys-tree.h (for older OpenBSD's)
+
+20021029
+ - (djm) Multiple fixes and improvements from Octavian Cerna <tavy@ylabs.com>
+    - softflowd.c (connsock): Fix arguments to `connect': addr is a pointer, 
+	not a structure.
+      (flow_update_expiry): Properly compute the flow lifetime.
+      (send_netflow_v1): Count the leftover packet.
+	Send flow_start, flow_finish and uptime_ms as Cisco equipment 
+	does: milliseconds since system boot.
+      (timeval_sub_ms): New function.
+      (main): Changed POLL_WAIT to be (EXPIRY_WAIT/2) as stated in the 
+	comment above `poll': twice per recheck.
+	`poll' takes the last argument in milliseconds.
+	Initialize system_boot_time as the time at the start of capture
+	(fixme: how does this affect reading from capture files?)
+
+20021024
+ - (djm) Release softflowd-0.7.1
+
+$Id: ChangeLog,v 1.87 2006/11/02 06:36:16 djm Exp $

+ 146 - 0
LICENSE

@@ -0,0 +1,146 @@
+Original code is licensed under the following BSD-style license:
+
+/*
+ * Copyright 2002-2006 Damien Miller <djm@mindrot.org> All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+closefrom.c:
+
+/*
+ * Copyright (c) 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+convtime.c:
+
+/*
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+daemon.c:
+
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+strlcat.c, strlcpy.c:
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+sys-tree.h:
+
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+

+ 59 - 0
Makefile.in

@@ -0,0 +1,59 @@
+# $Id: Makefile.in,v 1.9 2006/03/14 22:55:41 djm Exp $
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+libexecdir=@libexecdir@
+datadir=@datadir@
+mandir=@mandir@
+sysconfdir=@sysconfdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+VPATH=@srcdir@
+CC=@CC@
+LDFLAGS=@LDFLAGS@
+CFLAGS=@CFLAGS@
+CPPFLAGS=-I$(srcdir) @CPPFLAGS@
+LIBS=@LIBS@
+EXEEXT=@EXEEXT@
+INSTALL=@INSTALL@
+
+#CFLAGS+=-DFLOW_RB		# Use red-black tree for flows
+CFLAGS+=-DFLOW_SPLAY		# Use splay tree for flows
+CFLAGS+=-DEXPIRY_RB		# Use red-black tree for expiry events
+#CFLAGS+=-DEXPIRY_SPLAY		# Use splay tree for expiry events
+
+TARGETS=softflowd${EXEEXT} softflowctl${EXEEXT}
+
+COMMON=convtime.o strlcpy.o strlcat.o closefrom.o daemon.o
+
+all: $(TARGETS)
+
+softflowd${EXEEXT}: log.o softflowd.o netflow1.o netflow5.o netflow9.o $(COMMON)
+	$(CC) $(LDFLAGS) -o $@ log.o netflow1.o netflow5.o netflow9.o softflowd.o $(COMMON) $(LIBS)
+
+softflowctl${EXEEXT}: softflowctl.o $(COMMON)
+	$(CC) $(LDFLAGS) -o $@ softflowctl.o $(COMMON) $(LIBS)
+
+clean:
+	rm -f $(TARGETS) *.o core *.core
+
+realclean: clean
+	rm -rf autom4te.cache Makefile config.log config.status
+
+distclean: realclean
+	rm -f config.h* configure
+
+strip:
+	strip $(TARGETS)
+
+install:
+	[ -d $(DESTDIR)$(sbindir) ] || \
+	    $(srcdir)/mkinstalldirs $(DESTDIR)$(sbindir)
+	[ -d $(DESTDIR)$(mandir)/man8 ] || \
+	    $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/man8
+	$(INSTALL) -m 0755 -s softflowd $(DESTDIR)$(sbindir)/softflowd
+	$(INSTALL) -m 0755 -s softflowctl $(DESTDIR)$(sbindir)/softflowctl
+	$(INSTALL) -m 0644 softflowd.8 $(DESTDIR)$(mandir)/man8/softflowd.8
+	$(INSTALL) -m 0644 softflowctl.8 $(DESTDIR)$(mandir)/man8/softflowctl.8

+ 67 - 0
README

@@ -0,0 +1,67 @@
+Welcome to softflowd, a flow-based network monitor.
+
+Introduction
+------------
+
+softflowd listens promiscuously on a network interface and semi-statefully
+tracks network flows. These flows can be reported using NetFlow version 1, 5 
+or 9 datagrams. softflowd is fully IPv6 capable: it can track IPv6 flows and 
+export to IPv6 hosts.
+
+More details about softflowd's function and usage may be found in the
+supplied manpages, which you can view prior to installation using
+
+/usr/bin/nroff -c -mandoc softflowd.8 | less
+/usr/bin/nroff -c -mandoc softflowctl.8 | less
+
+If you are in need of a NetFlow collector, you may be interested in 
+softflowd's companion project "flowd" (http://www.mindrot.org/flowd.html). 
+flowd is a NetFlow collector that is maintained in parallel with
+softflowd and includes a few handy features, such as the ability
+to filter flows it receives as well as Perl and Python APIs to its
+storage format. NB. You don't have to use flowd: any NetFlow compatible 
+collector should work with softflowd. An example Perl collector is included 
+for testing purposes as collector.pl, but it doesn't yet support NetFlow v.9
+
+Installing
+----------
+
+Building softflowd should be as simple as typing:
+
+./configure
+make
+make install
+
+Unfortunately some systems like to make life complicated. Things work
+fine on the systems that I develop and test on (OpenBSD and Linux).
+There is peliminary support for Solaris 9 (i.e. it compiled), but no
+testing on this platform has been performed.
+
+Licensing
+---------
+
+Softflowd is licensed under a two-term BSD license (see the source
+files for details). The code in sys-tree.h is Copyright Niels Provos
+<provos@citi.umich.edu> and comes straight from OpenBSD CVS, convtime.c
+comes is Copyright Kevin Steves and comes from OpenSSH (misc.c). Both
+of these files are licensed under two-term BSD licenses too. strlcpy.c,
+strlcat.c and closefrom.c also come from OpenBSD CVS and are Copyright
+Todd C. Miller. Please refer to the LICENSE file for full details.
+
+Reporting Bugs
+--------------
+
+Please report bugs in softflowd to http://bugzilla.mindrot.org/ If you
+find a security bug, please report it directly by email. If you have any
+feedback or questions, please email me:
+
+Contributing
+------------
+
+Softflowd has an extensive TODO list of interesting features, large and
+small, that are waiting to be implemented. If you are interested in
+helping, please contact me.
+
+Damien Miller <djm@mindrot.org>
+
+$Id: README,v 1.7 2006/11/02 06:34:18 djm Exp $

+ 104 - 0
TODO

@@ -0,0 +1,104 @@
+Things yet to do:
+
+softflowd
+---------
+
+ - Use strtonum()
+
+ Flow tracking engine
+  - Verify checksums (maybe. perhaps bad for accounting, good for flow tracking)
+  - Fragment processing
+    - We don't handle fragments right
+      - This shouldn't be too hard or too memory intensive. We just need to 
+	keep a tree of fragment entries. Each entry would need to contain 
+	enough information to reconstruct the flow (source/dest addr, etc), 
+	but also fragment related info: IP id, list of fragment offsets. etc.
+      - When we receive a new fragment, we add an entry to this tree (keyed 
+	by source IP, protocol, IP id)
+      - Each new fragment matched in the tree gets its offset added to the 
+	list, until all fragments have been seen
+      - Must be careful, as later fragments may arrive before inital one
+      - When does accounting occur? 
+	- Upon receipt of inital fragment? (and thus for ever frag thereafter)
+	- When we have seen all fragments? (what if we don't?)
+      - Must limit size of tree
+      - Must have fragment timeout (what happens then, apart from removal?)
+   - Timeouts
+    - Timeout for unanswered TCP connection
+    - Ditto orphaned connections (one packet in one direction only)
+    - Track ICMP generated by TCP/UDP session (painful, probably unecessary)
+    - More datalink types
+    - Improve fast-expiry of TCP session by tracking FIN sequence numbers
+  - Multiple interface support
+    - Requires some way to avoid duplicate recording of flows (IP ID)
+  - Track IPsec SPIs
+  - Track ToS / DSCP
+  - Make counters 64 bits
+    - We can report these directly for NetFlow v.9
+    - For older NetFlow, report by sending multiple flows until counter < 2^32
+
+ Misc features
+  - Ability to open more than one interface (maybe)
+  - Ability to read more than one pcap file (maybe)
+  - Fork for ctlsock actions? (don't block mainloop)
+  - Remote control over network (requires SSL)
+
+ Performance
+  - Profile and see where the hot spots are
+  - Fast "new flow" test using a bloom filter
+  - See if we can reduce per-packet overhead more
+    - Cost of expiry remove and re-add per packet
+  - Stop run-time malloc (maybe)
+    - Preallocate a pool of expiry events and flow entries
+      - keep a queue, pick/push first from head
+
+ Exporter features
+  - sflow support (www.sflow.org)
+    - Needs XDR encoding
+  - Ability to export to multiple hosts
+    - Partly done, just need to keep a list of targets instead of a single one
+  - Ability to directly write to file (maybe. If so, reuse flowd store code)
+  - NetFlow v.9 field selection
+
+ Statistics code
+  - Collect more statistics (maybe)
+    - Advanced packet analysis: store hash of packet payload, keep 
+      statistics on traffic similarity
+       - Bloom filter?
+    - Option to record histograms of
+      - Flow lifetime and size, packet size
+    - Flow bandwidth
+    - Per well-known-port
+      - How to do this quicky? Memory efficiently?
+    - Per IP address/range
+      - How to do this quicky? Memory efficiently?
+    - Moving averages
+  - Track traffic over lifetime of flow
+    - Maintain linked list traffic counts, keyed by time interval
+    - E.g. key by (now / 300)
+      - Or (now - start_time) / 300 (better)
+    - When new packet comes in:
+      - If timestamp of HEAD of list == (now / xxx), then counter += octets
+      - Otherwise create new traffic counter at HEAD and update it
+        - Then trim tail if the list length is too big
+    - Maybe store "hunks" of data, rather than individual counts in the 
+      list, as storing a single int is a huge waste of space
+    - Maybe a rrdtool-like heirarchy of timespans
+      - 300 seconds (5 minutes)       (2400 bytes)
+      - 360 1-minute blocks (6 hours) (2880 bytes)
+      - 288 10-minute blocks (2 days) (2304 bytes)
+      - 336 1-hour blocks (2 weeks)   (2688 bytes)
+        - Total 10kb worst-case per-flow (scary, probably overkill)
+
+softflowctl
+-----------
+
+  - Extend interface
+    - Query for specific flows (e.g. by address)
+      - Do this in softflowd or softflowctl?
+    - Expire/delete specific flows (maybe)
+  - Runtime respecify timeouts
+  - Real-time binary dump of flowtable (shm/mmap fd pass?)
+    - ntop like view
+    - Spiffy GUI (separate tool)
+

+ 1 - 0
aclocal.m4

@@ -0,0 +1 @@
+dnl Nothing here

+ 100 - 0
closefrom.c

@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include "common.h"
+
+#ifndef HAVE_CLOSEFROM
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stddef.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#ifndef OPEN_MAX
+# define OPEN_MAX	256
+#endif
+
+RCSID("$Id: closefrom.c,v 1.1 2004/09/10 09:08:08 djm Exp $");
+
+#ifndef lint
+static const char rcsid[] = "$Sudo: closefrom.c,v 1.6 2004/06/01 20:51:56 millert Exp $";
+#endif /* lint */
+
+/*
+ * Close all file descriptors greater than or equal to lowfd.
+ */
+void
+closefrom(int lowfd)
+{
+    long fd, maxfd;
+#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
+    char fdpath[PATH_MAX], *endp;
+    struct dirent *dent;
+    DIR *dirp;
+    int len;
+
+    /* Check for a /proc/$$/fd directory. */
+    len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
+    if (len != -1 && len <= sizeof(fdpath) && (dirp = opendir(fdpath))) {
+	while ((dent = readdir(dirp)) != NULL) {
+	    fd = strtol(dent->d_name, &endp, 10);
+	    if (dent->d_name != endp && *endp == '\0' &&
+		fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
+		(void) close((int) fd);
+	}
+	(void) closedir(dirp);
+    } else
+#endif
+    {
+	/*
+	 * Fall back on sysconf() or getdtablesize().  We avoid checking
+	 * resource limits since it is possible to open a file descriptor
+	 * and then drop the rlimit such that it is below the open fd.
+	 */
+#ifdef HAVE_SYSCONF
+	maxfd = sysconf(_SC_OPEN_MAX);
+#else
+	maxfd = getdtablesize();
+#endif /* HAVE_SYSCONF */
+	if (maxfd < 0)
+	    maxfd = OPEN_MAX;
+
+	for (fd = lowfd; fd < maxfd; fd++)
+	    (void) close((int) fd);
+    }
+}
+
+#endif /* HAVE_CLOSEFROM */
+

+ 279 - 0
collector.pl

@@ -0,0 +1,279 @@
+#!/usr/bin/perl -w
+
+# This is a Cisco NetFlow datagram collector
+
+# Netflow protocol reference:
+# http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_0/nfc_ug/nfcform.htm
+
+# XXX Doesn't support NetFlow 9
+
+my $af;
+
+BEGIN {
+	use strict;
+	use warnings;
+	use IO qw(Socket);
+	use Socket;
+	use Carp;
+	use POSIX qw(strftime);
+	use Getopt::Long;
+	eval "use IO::Socket::INET6;";
+	eval "use Socket6;";
+}
+
+############################################################################
+
+sub timestamp()
+{
+	return strftime "%Y-%m-%dT%H:%M:%S", localtime;
+}
+
+sub fuptime($)
+{
+	my $t = shift;
+	my $r = "";
+	my $tmp;
+	
+	# Milliseconds
+	$tmp = $t % 1000;
+	$r = sprintf ".%03u%s", $tmp, $r;
+
+	# Seconds
+	$t = int($t / 1000);
+	$tmp = $t % 60;
+	$r = "${tmp}s${r}";
+
+	# Minutes
+	$t = int($t / 60);
+	$tmp = $t % 60;
+	$r = "${tmp}m${r}" if $tmp;
+
+	# Hours
+	$t = int($t / 60);
+	$tmp = $t % 24;
+	$r = "${tmp}h${r}" if $tmp;
+
+	# Days
+	$t = int($t / 24);
+	$tmp = $t % 7;
+	$r = "${tmp}d${r}" if $tmp;
+
+	# Weeks
+	$t = int($t / 7);
+	$tmp = $t % 52;
+	$r = "${tmp}w${r}" if $tmp;
+
+	# Years
+	$t = int($t / 52);
+	$r = "${tmp}y${r}" if $tmp;
+
+	return $r;
+}
+
+sub do_listen($$)
+{
+	my $port = shift
+		or confess "No UDP port specified";
+
+        my $socket;
+
+	if ($af == 4) {
+		$socket = IO::Socket::INET->new(Proto=>'udp', LocalPort=>$port)
+			or croak "Couldn't open UDP socket: $!";
+	} elsif ($af == 6) {
+		$socket = IO::Socket::INET6->new(Proto=>'udp', LocalPort=>$port)
+			or croak "Couldn't open UDP socket: $!";
+ 	} else {
+		croak "Unsupported AF";
+	}
+
+	return $socket;
+}
+
+sub process_nf_v1($$)
+{
+	my $sender = shift;
+	my $pkt = shift;
+	my %header;
+	my %flow;
+	my $sender_s;
+
+	%header = qw();
+
+	$sender_s = inet_ntoa($sender) if $af == 4;
+	$sender_s = inet_ntop(AF_INET6, $sender) if $af == 6;
+
+	($header{ver}, $header{flows}, $header{uptime}, $header{secs}, 
+	 $header{nsecs}) = unpack("nnNNN", $pkt);
+
+	if (length($pkt) < (16 + (48 * $header{flows}))) {
+		printf STDERR timestamp()." Short Netflow v.1 packet: %d < %d\n",
+		    length($pkt), 16 + (48 * $header{flows});
+		return;
+	}
+
+	printf timestamp() . " HEADER v.%u (%u flow%s)\n", $header{ver},
+	    $header{flows}, $header{flows} == 1 ? "" : "s";
+
+	for(my $i = 0; $i < $header{flows}; $i++) {
+		my $off = 16 + (48 * $i);
+		my $ptr = substr($pkt, $off, 52);
+
+		%flow = qw();
+
+		(my $src1, my $src2, my $src3, my $src4,
+		 my $dst1, my $dst2, my $dst3, my $dst4, 
+		 my $nxt1, my $nxt2, my $nxt3, my $nxt4, 
+		 $flow{in_ndx}, $flow{out_ndx}, $flow{pkts}, $flow{bytes}, 
+		 $flow{start}, $flow{finish}, $flow{src_port}, $flow{dst_port}, 
+		 my $pad1, $flow{protocol}, $flow{tos}, $flow{tcp_flags}) =
+		    unpack("CCCCCCCCCCCCnnNNNNnnnCCC", $ptr);
+
+		$flow{src} = sprintf "%u.%u.%u.%u", $src1, $src2, $src3, $src4;
+		$flow{dst} = sprintf "%u.%u.%u.%u", $dst1, $dst2, $dst3, $dst4;
+		$flow{nxt} = sprintf "%u.%u.%u.%u", $nxt1, $nxt2, $nxt3, $nxt4;
+
+		printf timestamp() . " " .
+		    "from %s started %s finish %s proto %u %s:%u > %s:%u %u " . 
+		    "packets %u octets\n",
+		    $sender_s,
+		    fuptime($flow{start}), fuptime($flow{finish}), 
+		    $flow{protocol}, 
+		    $flow{src}, $flow{src_port}, $flow{dst}, $flow{dst_port}, 
+		    $flow{pkts}, $flow{bytes};
+	}
+}
+
+sub process_nf_v5($$)
+{
+	my $sender = shift;
+	my $pkt = shift;
+	my %header;
+	my %flow;
+	my $sender_s;
+
+	%header = qw();
+
+	$sender_s = inet_ntoa($sender) if $af == 4;
+	$sender_s = inet_ntop(AF_INET6, $sender) if $af == 6;
+
+	($header{ver}, $header{flows}, $header{uptime}, $header{secs}, 
+	 $header{nsecs}, $header{flow_seq}, ) = unpack("nnNNNN", $pkt);
+
+	if (length($pkt) < (24 + (48 * $header{flows}))) {
+		printf STDERR timestamp()." Short Netflow v.1 packet: %d < %d\n",
+		    length($pkt), 24 + (48 * $header{flows});
+		return;
+	}
+
+	printf timestamp() . " HEADER v.%u (%u flow%s) seq %u\n", $header{ver},
+	    $header{flows}, $header{flows} == 1 ? "" : "s", $header{flow_seq};
+
+	for(my $i = 0; $i < $header{flows}; $i++) {
+		my $off = 24 + (48 * $i);
+		my $ptr = substr($pkt, $off, 52);
+
+		%flow = qw();
+
+		(my $src1, my $src2, my $src3, my $src4,
+		 my $dst1, my $dst2, my $dst3, my $dst4, 
+		 my $nxt1, my $nxt2, my $nxt3, my $nxt4, 
+		 $flow{in_ndx}, $flow{out_ndx}, $flow{pkts}, $flow{bytes}, 
+		 $flow{start}, $flow{finish}, $flow{src_port}, $flow{dst_port}, 
+		 my $pad1, $flow{tcp_flags}, $flow{protocol}, $flow{tos},
+		 $flow{src_as}, $flow{dst_as},
+		 $flow{src_mask}, $flow{dst_mask}) =
+		    unpack("CCCCCCCCCCCCnnNNNNnnCCCCnnCC", $ptr);
+
+		$flow{src} = sprintf "%u.%u.%u.%u", $src1, $src2, $src3, $src4;
+		$flow{dst} = sprintf "%u.%u.%u.%u", $dst1, $dst2, $dst3, $dst4;
+		$flow{nxt} = sprintf "%u.%u.%u.%u", $nxt1, $nxt2, $nxt3, $nxt4;
+
+		printf timestamp() . " " .
+		    "from %s started %s finish %s proto %u %s:%u > %s:%u %u " . 
+		    "packets %u octets\n",
+		    $sender_s,
+		    fuptime($flow{start}), fuptime($flow{finish}), 
+		    $flow{protocol}, 
+		    $flow{src}, $flow{src_port}, $flow{dst}, $flow{dst_port}, 
+		    $flow{pkts}, $flow{bytes};
+	}
+}
+
+############################################################################
+
+# Commandline options
+my $debug = 0;
+my $af4 = 0;
+my $af6 = 0;
+my $port;
+
+#		Long option		Short option
+GetOptions(	'debug+' => \$debug,	'd+' => \$debug,
+					'4+' => \$af4,
+					'6+' => \$af6,
+		'port=i' => \$port,	'p=i' => \$port);
+
+# Unbuffer output
+$| = 1;
+
+die "The -4 and -6 are mutually exclusive\n" if $af4 && $af6;
+die "You must specify a port (collector.pl -p XXX).\n" unless $port;
+
+$af4 = $af = 4 if $af4 || (!$af4 && !$af6);
+$af6 = $af = 6 if $af6;
+
+# These modules aren't standard everywhere, so load them only if necessary
+
+# Main loop - receive and process a packet
+for (;;) {
+	my $socket;
+	my $from;
+	my $payload;
+	my $ver;
+	my $failcount = 0;
+	my $netflow;
+	my $junk;
+	my $sender;
+
+	# Open the listening port if we haven't already
+	$socket = do_listen($port, $af) unless defined $socket;
+
+	# Fetch a packet
+	$from = $socket->recv($payload, 8192, 0);
+	
+	($junk, $sender) = unpack_sockaddr_in($from) if $af4;
+	($junk, $sender) = unpack_sockaddr_in6($from) if $af6;
+
+	# Reopen listening socket on error
+	if (!defined $from) {
+		$socket->close;
+		undef $socket;
+
+		$failcount++;
+		die "Couldn't recv: $!\n" if ($failcount > 5);
+		next; # Socket will be reopened at start of loop
+	}
+	
+	if (length($payload) < 16) {
+		printf STDERR timestamp()." Short packet recevied: %d < 16\n",
+		    length($payload);
+		next;
+	}
+
+	# The version is always the first 16 bits of the packet
+	($ver) = unpack("n", $payload);
+
+	if	($ver == 1)	{ process_nf_v1($sender, $payload); }
+	elsif	($ver == 5)	{ process_nf_v5($sender, $payload); }
+	else {
+		printf STDERR timestamp()." Unsupported netflow version %d\n",
+		    $ver;
+		next;
+	}
+	
+	undef $payload;
+	next;	
+}
+
+exit 0;

+ 169 - 0
common.h

@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2002 Damien Miller.  All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _SFD_COMMON_H
+#define _SFD_COMMON_H
+
+#include "config.h"
+
+#define _BSD_SOURCE /* Needed for BSD-style struct ip,tcp,udp on Linux */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <arpa/inet.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <netdb.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#if defined(HAVE_NET_BPF_H)
+#include <net/bpf.h>
+#elif defined(HAVE_PCAP_BPF_H)
+#include <pcap-bpf.h>
+#endif
+#if defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+
+/* The name of the program */
+#define PROGNAME		"softflowd"
+
+/* The name of the program */
+#define PROGVER			"0.9.8"
+
+/* Default pidfile */
+#define DEFAULT_PIDFILE		"/var/run/" PROGNAME ".pid"
+
+/* Default control socket */
+#define DEFAULT_CTLSOCK		"/var/run/" PROGNAME ".ctl"
+
+#define RCSID(msg) \
+	static /**/const char *const flowd_rcsid[] =		\
+	    { (const char *)flowd_rcsid, "\100(#)" msg }	\
+
+#ifndef IP_OFFMASK
+# define IP_OFFMASK		0x1fff	/* mask for fragmenting bits */
+#endif
+#ifndef IPV6_VERSION
+#define IPV6_VERSION		0x60
+#endif
+#ifndef IPV6_VERSION_MASK
+#define IPV6_VERSION_MASK	0xf0
+#endif
+#ifndef IPV6_FLOWINFO_MASK
+#define IPV6_FLOWINFO_MASK	ntohl(0x0fffffff)
+#endif
+#ifndef IPV6_FLOWLABEL_MASK
+#define IPV6_FLOWLABEL_MASK	ntohl(0x000fffff)
+#endif
+
+#ifndef _PATH_DEVNULL
+# define _PATH_DEVNULL		"/dev/null"
+#endif
+
+#ifndef MIN
+# define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef MAX
+# define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+#ifndef offsetof
+# define offsetof(type, member) ((size_t) &((type *)0)->member)
+#endif
+
+#if defined(__GNUC__)
+# ifndef __dead
+#  define __dead                __attribute__((__noreturn__))
+# endif
+# ifndef __packed
+#  define __packed              __attribute__((__packed__))
+# endif
+#endif
+
+#if !defined(HAVE_INT8_T) && defined(OUR_CFG_INT8_T)
+typedef OUR_CFG_INT8_T int8_t;
+#endif
+#if !defined(HAVE_INT16_T) && defined(OUR_CFG_INT16_T)
+typedef OUR_CFG_INT16_T int16_t;
+#endif
+#if !defined(HAVE_INT32_T) && defined(OUR_CFG_INT32_T)
+typedef OUR_CFG_INT32_T int32_t;
+#endif
+#if !defined(HAVE_INT64_T) && defined(OUR_CFG_INT64_T)
+typedef OUR_CFG_INT64_T int64_t;
+#endif
+#if !defined(HAVE_U_INT8_T) && defined(OUR_CFG_U_INT8_T)
+typedef OUR_CFG_U_INT8_T u_int8_t;
+#endif
+#if !defined(HAVE_U_INT16_T) && defined(OUR_CFG_U_INT16_T)
+typedef OUR_CFG_U_INT16_T u_int16_t;
+#endif
+#if !defined(HAVE_U_INT32_T) && defined(OUR_CFG_U_INT32_T)
+typedef OUR_CFG_U_INT32_T u_int32_t;
+#endif
+#if !defined(HAVE_U_INT64_T) && defined(OUR_CFG_U_INT64_T)
+typedef OUR_CFG_U_INT64_T u_int64_t;
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, const char *src, size_t siz);
+#endif
+#ifndef HAVE_CLOSEFROM
+void closefrom(int lowfd);
+#endif
+
+#ifndef HAVE_STRUCT_IP6_EXT
+struct ip6_ext {
+	u_int8_t ip6e_nxt;
+	u_int8_t ip6e_len;
+} __packed;
+#endif
+
+#endif /* _SFD_COMMON_H */

+ 163 - 0
config.h.in

@@ -0,0 +1,163 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the `closefrom' function. */
+#undef HAVE_CLOSEFROM
+
+/* Define to 1 if you have the `daemon' function. */
+#undef HAVE_DAEMON
+
+/* Define to 1 if the system has the type `int16_t'. */
+#undef HAVE_INT16_T
+
+/* Define to 1 if the system has the type `int32_t'. */
+#undef HAVE_INT32_T
+
+/* Define to 1 if the system has the type `int64_t'. */
+#undef HAVE_INT64_T
+
+/* Define to 1 if the system has the type `int8_t'. */
+#undef HAVE_INT8_T
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `pcap' library (-lpcap). */
+#undef HAVE_LIBPCAP
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <net/bpf.h> header file. */
+#undef HAVE_NET_BPF_H
+
+/* Define to 1 if you have the <pcap-bpf.h> header file. */
+#undef HAVE_PCAP_BPF_H
+
+/* Define to 1 if you have the <pcap.h> header file. */
+#undef HAVE_PCAP_H
+
+/* Define to 1 if you have the `setgid' function. */
+#undef HAVE_SETGID
+
+/* Define to 1 if you have the `setresgid' function. */
+#undef HAVE_SETRESGID
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Define to 1 if you have the `setreuid' function. */
+#undef HAVE_SETREUID
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* struct ip6_ext.ip6e_nxt exists */
+#undef HAVE_STRUCT_IP6_EXT
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#undef HAVE_UINT16_T
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#undef HAVE_UINT32_T
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#undef HAVE_UINT64_T
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#undef HAVE_UINT8_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if the system has the type `u_int16_t'. */
+#undef HAVE_U_INT16_T
+
+/* Define to 1 if the system has the type `u_int32_t'. */
+#undef HAVE_U_INT32_T
+
+/* Define to 1 if the system has the type `u_int64_t'. */
+#undef HAVE_U_INT64_T
+
+/* Define to 1 if the system has the type `u_int8_t'. */
+#undef HAVE_U_INT8_T
+
+/* 16-bit signed int */
+#undef OUR_CFG_INT16_T
+
+/* 32-bit signed int */
+#undef OUR_CFG_INT32_T
+
+/* 64-bit signed int */
+#undef OUR_CFG_INT64_T
+
+/* 8-bit signed int */
+#undef OUR_CFG_INT8_T
+
+/* 16-bit unsigned int */
+#undef OUR_CFG_U_INT16_T
+
+/* 32-bit unsigned int */
+#undef OUR_CFG_U_INT32_T
+
+/* 64-bit unsigned int */
+#undef OUR_CFG_U_INT64_T
+
+/* 8-bit unsigned int */
+#undef OUR_CFG_U_INT8_T
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long int', as computed by sizeof. */
+#undef SIZEOF_LONG_INT
+
+/* The size of `long long int', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG_INT
+
+/* The size of `short int', as computed by sizeof. */
+#undef SIZEOF_SHORT_INT
+
+/* struct sockaddr contains length */
+#undef SOCK_HAS_LEN
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS

File diff suppressed because it is too large
+ 9163 - 0
configure


+ 170 - 0
configure.ac

@@ -0,0 +1,170 @@
+# $Id: configure.ac,v 1.5 2004/11/08 23:03:28 djm Exp $
+#
+# Copyright (c) 2004 Damien Miller
+#
+# 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.
+#
+# 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.
+
+AC_INIT
+AC_CONFIG_SRCDIR([softflowd.c])
+
+AC_CONFIG_HEADER(config.h)
+AC_PROG_CC
+AC_PROG_INSTALL
+
+# Optional verbose warnings for gcc, see below
+WFLAGS="-Wall -Waggregate-return -Wcast-align -Wcast-qual"
+WFLAGS="$WFLAGS -Wmissing-declarations -Wmissing-prototypes"
+WFLAGS="$WFLAGS -Wno-conversion -Wpointer-arith -Wshadow"
+WFLAGS="$WFLAGS -Wuninitialized -Wcast-align -Wcast-qual"
+WFLAGS="$WFLAGS -WformatC=2 -Wformat-nonliteral -Wwrite-strings" 
+
+# Process flag arguments early, so they are available for tests later
+AC_ARG_ENABLE(gcc-warnings,
+	[  --enable-gcc-warnings   Enable verbose warnings (only for gcc)],
+	[ if test "x$enableval" = "xyes" ; then CFLAGS="$CFLAGS $WFLAGS"; fi ]
+)
+AC_ARG_WITH(cflags,
+	[  --with-cflags           Specify additional compiler flags],
+	[ if test "x$withval" != "xno" ; then CFLAGS="$CFLAGS $withval"; fi ]	
+)
+AC_ARG_WITH(cppflags,
+	[  --with-cppflags         Specify additional preprocessor flags] ,
+	[ if test "x$withval" != "xno"; then CPPFLAGS="$CPPFLAGS $withval"; fi ]
+)
+AC_ARG_WITH(ldflags,
+	[  --with-ldflags          Specify additional linker flags],
+	[ if test "x$withval" != "xno" ; then LDFLAGS="$LDFLAGS $withval"; fi ]	
+)
+AC_ARG_WITH(libs,
+	[  --with-libs             Specify additional libraries to link with],
+	[ if test "x$withval" != "xno" ; then LIBS="$LIBS $withval"; fi ]	
+)
+
+AC_CHECK_HEADERS(net/bpf.h pcap.h pcap-bpf.h)
+
+dnl AC_CHECK_HEADERS(netinet/in_systm.h netinet/tcp.h netinet/udp.h)
+dnl 
+dnl # This ugliness is because of autoconf's stupid default include list
+dnl AC_CHECK_HEADERS([netinet/ip.h], 
+dnl 	[AC_DEFINE([HAVE_HAVE_NETINET_IP_H], 1, [has netinet/ip.h])], [], 
+dnl 	[
+dnl #include <sys/types.h>
+dnl #include <netinet/in.h>
+dnl #if HAVE_NETINET_IN_SYSTM_H
+dnl #include <netinet/in_systm.h>
+dnl #endif
+dnl 	])
+
+AC_CHECK_MEMBER([struct sockaddr.sa_len], 
+	[AC_DEFINE([SOCK_HAS_LEN], 1, [struct sockaddr contains length])], ,
+	[#include <sys/types.h>
+	 #include <sys/socket.h>])
+
+AC_CHECK_MEMBER(struct ip6_ext.ip6e_nxt,
+	[AC_DEFINE([HAVE_STRUCT_IP6_EXT], 1, [struct ip6_ext.ip6e_nxt exists])],
+	[],
+	[
+		#include <sys/types.h>
+		#include <sys/socket.h>
+		#include <netinet/in.h>
+		#include <netinet/ip6.h>
+	])
+
+AC_SEARCH_LIBS(daemon, bsd)
+AC_SEARCH_LIBS(gethostbyname, nsl)
+AC_SEARCH_LIBS(socket, socket)
+AC_CHECK_LIB(pcap, pcap_open_live)
+
+AC_CHECK_FUNCS(closefrom daemon setresuid setreuid setresgid setgid strlcpy strlcat)
+
+AC_CHECK_TYPES([u_int64_t, int64_t, uint64_t, u_int32_t, int32_t, uint32_t])
+AC_CHECK_TYPES([u_int16_t, int16_t, uint16_t, u_int8_t, int8_t, uint8_t])
+AC_CHECK_SIZEOF(char, 1)
+AC_CHECK_SIZEOF(short int, 2)
+AC_CHECK_SIZEOF(int, 4)
+AC_CHECK_SIZEOF(long int, 4)
+AC_CHECK_SIZEOF(long long int, 8)
+
+if test "x$ac_cv_type_uint8_t" = "xyes" ; then
+	AC_DEFINE([OUR_CFG_U_INT8_T], [uint8_t], [8-bit unsigned int])
+elif test "x$ac_cv_sizeof_char" = "x1" ; then
+	AC_DEFINE([OUR_CFG_U_INT8_T], [unsigned char], [8-bit unsigned int])
+else
+	AC_MSG_ERROR([No 8-bit unsigned int type found])
+fi
+if test "x$ac_cv_sizeof_char" = "x1" ; then
+	AC_DEFINE([OUR_CFG_INT8_T], [signed char], [8-bit signed int])
+else
+	AC_MSG_ERROR([No 8-bit signed int type found])
+fi
+
+if test "x$ac_cv_type_uint16_t" = "xyes" ; then
+	AC_DEFINE([OUR_CFG_U_INT16_T], [uint16_t], [16-bit unsigned int])
+elif test "x$ac_cv_sizeof_short_int" = "x2" ; then
+	AC_DEFINE([OUR_CFG_U_INT16_T], [unsigned short int], [16-bit unsigned int])
+else
+	AC_MSG_ERROR([No 16-bit unsigned int type found])
+fi
+if test "x$ac_cv_sizeof_short_int" = "x2" ; then
+	AC_DEFINE([OUR_CFG_INT16_T], [short int], [16-bit signed int])
+else
+	AC_MSG_ERROR([No 16-bit signed int type found])
+fi
+
+if test "x$ac_cv_type_uint32_t" = "xyes" ; then
+	AC_DEFINE([OUR_CFG_U_INT32_T], [uint32_t], [32-bit unsigned int])
+elif test "x$ac_cv_sizeof_int" = "x4" ; then
+	AC_DEFINE([OUR_CFG_U_INT32_T], [unsigned int], [32-bit unsigned int])
+else
+	AC_MSG_ERROR([No 32-bit unsigned int type found])
+fi
+if test "x$ac_cv_sizeof_int" = "x4" ; then
+	AC_DEFINE([OUR_CFG_INT32_T], [int], [32-bit signed int])
+else
+	AC_MSG_ERROR([No 32-bit signed int type found])
+fi
+
+if test "x$ac_cv_type_uint64_t" = "xyes" ; then
+	AC_DEFINE([OUR_CFG_U_INT64_T], [uint64_t], [64-bit unsigned int])
+elif test "x$ac_cv_sizeof_long_int" = "x8" ; then
+	AC_DEFINE([OUR_CFG_U_INT64_T], [unsigned long int], [64-bit unsigned int])
+elif test "x$ac_cv_sizeof_long_long_int" = "x8" ; then
+	AC_DEFINE([OUR_CFG_U_INT64_T], [unsigned long long int], [64-bit unsigned int])
+else
+	AC_MSG_ERROR([No 64-bit unsigned int type found])
+fi
+if test "x$ac_cv_sizeof_long_int" = "x8" ; then
+	AC_DEFINE([OUR_CFG_INT64_T], [long int], [64-bit signed int])
+elif test "x$ac_cv_sizeof_long_long_int" = "x8" ; then
+	AC_DEFINE([OUR_CFG_INT64_T], [long long int], [64-bit signed int])
+else
+	AC_MSG_ERROR([No 64-bit signed int type found])
+fi
+
+if test "x$ac_cv_header_pcap_bpf_h" != "xyes" && \
+   test "x$ac_cv_header_net_bpf_h" != "xyes" ; then
+	AC_MSG_ERROR([No BPF header found])
+fi
+if test "x$ac_cv_header_pcap_h" != "xyes" ; then
+	AC_MSG_ERROR([No pcap.h header found])
+fi
+if test "x$ac_cv_lib_pcap_pcap_open_live" != "xyes" ; then
+	AC_MSG_ERROR([libpcap not found])
+fi
+
+
+
+AC_EXEEXT
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+

+ 89 - 0
convtime.c

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include "common.h"
+#include "convtime.h"
+
+RCSID("$Id: convtime.c,v 1.2 2004/09/10 09:08:08 djm Exp $");
+
+#define SECONDS		1
+#define MINUTES		(SECONDS * 60)
+#define HOURS		(MINUTES * 60)
+#define DAYS		(HOURS * 24)
+#define WEEKS		(DAYS * 7)
+
+long int
+convtime(const char *s)
+{
+	long total, secs;
+	const char *p;
+	char *endp;
+
+	errno = 0;
+	total = 0;
+	p = s;
+
+	if (p == NULL || *p == '\0')
+		return -1;
+
+	while (*p) {
+		secs = strtol(p, &endp, 10);
+		if (p == endp ||
+		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
+		    secs < 0)
+			return -1;
+
+		switch (*endp++) {
+		case '\0':
+			endp--;
+		case 's':
+		case 'S':
+			break;
+		case 'm':
+		case 'M':
+			secs *= MINUTES;
+			break;
+		case 'h':
+		case 'H':
+			secs *= HOURS;
+			break;
+		case 'd':
+		case 'D':
+			secs *= DAYS;
+			break;
+		case 'w':
+		case 'W':
+			secs *= WEEKS;
+			break;
+		default:
+			return -1;
+		}
+		total += secs;
+		if (total < 0)
+			return -1;
+		p = endp;
+	}
+
+	return total;
+}

+ 50 - 0
convtime.h

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _SFD_CONVTIME_H
+
+/*
+ * Convert a time string into seconds; format is
+ * a sequence of:
+ *      time[qualifier]
+ *
+ * Valid time qualifiers are:
+ *      <none>  seconds
+ *      s|S     seconds
+ *      m|M     minutes
+ *      h|H     hours
+ *      d|D     days
+ *      w|W     weeks
+ *
+ * Examples:
+ *      90m     90 minutes
+ *      1h30m   90 minutes
+ *      2d      2 days
+ *      1w      1 week
+ *
+ * Return -1 if time string is invalid.
+ */
+long int convtime(const char *s);
+
+#endif /* _SFD_CONVTIME_H */

+ 81 - 0
daemon.c

@@ -0,0 +1,81 @@
+/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */
+
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include "common.h"
+
+#ifndef HAVE_DAEMON
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: daemon.c,v 1.5 2003/07/15 17:32:41 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+int
+daemon(int nochdir, int noclose)
+{
+	int fd;
+
+	switch (fork()) {
+	case -1:
+		return (-1);
+	case 0:
+#ifdef HAVE_CYGWIN
+		register_9x_service();
+#endif
+		break;
+	default:
+#ifdef HAVE_CYGWIN
+		/*
+		 * This sleep avoids a race condition which kills the
+		 * child process if parent is started by a NT/W2K service.
+		 */
+		sleep(1);
+#endif
+		_exit(0);
+	}
+
+	if (setsid() == -1)
+		return (-1);
+
+	if (!nochdir)
+		(void)chdir("/");
+
+	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+		(void)dup2(fd, STDIN_FILENO);
+		(void)dup2(fd, STDOUT_FILENO);
+		(void)dup2(fd, STDERR_FILENO);
+		if (fd > 2)
+			(void)close (fd);
+	}
+	return (0);
+}
+
+#endif /* !HAVE_DAEMON */
+

+ 251 - 0
install-sh

@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+		chmodcmd=""
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+	then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ]
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename |
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ]
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0

+ 59 - 0
log.c

@@ -0,0 +1,59 @@
+/*
+ * Copyright 2004 Damien Miller <djm@mindrot.org> All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/* $Id: log.c,v 1.2 2004/09/10 09:08:08 djm Exp $ */
+
+#include "common.h"
+#include "log.h"
+#include <stdarg.h>
+
+RCSID("$Id: log.c,v 1.2 2004/09/10 09:08:08 djm Exp $");
+
+static int logstderr = 0;
+
+void
+loginit(const char *ident, int to_stderr)
+{
+	if (to_stderr)
+		logstderr = 1;
+	else
+		openlog(PROGNAME, LOG_PID, LOG_DAEMON);
+}
+
+void
+logit(int level, const char *fmt,...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+
+	if (logstderr) {
+		vfprintf(stderr, fmt, args);
+		fputs("\n", stderr);
+	} else
+		vsyslog(level, fmt, args);
+
+	va_end(args);
+}
+

+ 33 - 0
log.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright 2004 Damien Miller <djm@mindrot.org> All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/* $Id: log.h,v 1.1 2004/04/16 01:51:51 djm Exp $ */
+
+#ifndef _LOG_H
+#define _LOG_H
+
+void loginit(const char *ident, int to_stderr);
+void logit(int level, const char *fmt,...);
+
+#endif /* _LOG_H */

+ 40 - 0
mkinstalldirs

@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1 2005/12/22 02:23:41 djm Exp $
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+	echo "mkdir $pathcomp"
+
+	mkdir "$pathcomp" || lasterr=$?
+
+	if test ! -d "$pathcomp"; then
+	  errstatus=$lasterr
+	fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here

+ 168 - 0
netflow1.c

@@ -0,0 +1,168 @@
+/*
+ * Copyright 2002 Damien Miller <djm@mindrot.org> All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/* $Id: netflow1.c,v 1.2 2005/05/05 03:31:42 djm Exp $ */
+
+#include "common.h"
+#include "log.h"
+#include "treetype.h"
+#include "softflowd.h"
+
+RCSID("$Id: netflow1.c,v 1.2 2005/05/05 03:31:42 djm Exp $");
+
+/*
+ * This is the Cisco Netflow(tm) version 1 packet format
+ * Based on:
+ * http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_0/nfc_ug/nfcform.htm
+ */
+struct NF1_HEADER {
+	u_int16_t version, flows;
+	u_int32_t uptime_ms, time_sec, time_nanosec;
+};
+struct NF1_FLOW {
+	u_int32_t src_ip, dest_ip, nexthop_ip;
+	u_int16_t if_index_in, if_index_out;
+	u_int32_t flow_packets, flow_octets;
+	u_int32_t flow_start, flow_finish;
+	u_int16_t src_port, dest_port;
+	u_int16_t pad1;
+	u_int8_t protocol, tos, tcp_flags;
+	u_int8_t pad2, pad3, pad4;
+	u_int32_t reserved1;
+#if 0
+ 	u_int8_t reserved2; /* XXX: no longer used */
+#endif
+};
+/* Maximum of 24 flows per packet */
+#define NF1_MAXFLOWS		24
+#define NF1_MAXPACKET_SIZE	(sizeof(struct NF1_HEADER) + \
+				 (NF1_MAXFLOWS * sizeof(struct NF1_FLOW)))
+
+/*
+ * Given an array of expired flows, send netflow v1 report packets
+ * Returns number of packets sent or -1 on error
+ */
+int
+send_netflow_v1(struct FLOW **flows, int num_flows, int nfsock,
+    u_int64_t *flows_exported, struct timeval *system_boot_time, 
+    int verbose_flag)
+{
+	struct timeval now;
+	u_int32_t uptime_ms;
+	u_int8_t packet[NF1_MAXPACKET_SIZE];	/* Maximum allowed packet size (24 flows) */
+	struct NF1_HEADER *hdr = NULL;
+	struct NF1_FLOW *flw = NULL;
+	int i, j, offset, num_packets, err;
+	socklen_t errsz;
+	
+	gettimeofday(&now, NULL);
+	uptime_ms = timeval_sub_ms(&now, system_boot_time);
+
+	hdr = (struct NF1_HEADER *)packet;
+	for(num_packets = offset = j = i = 0; i < num_flows; i++) {
+		if (j >= NF1_MAXFLOWS - 1) {
+			if (verbose_flag)
+				logit(LOG_DEBUG, "Sending flow packet len = %d", offset);
+			hdr->flows = htons(hdr->flows);
+			errsz = sizeof(err);
+			getsockopt(nfsock, SOL_SOCKET, SO_ERROR,
+			    &err, &errsz); /* Clear ICMP errors */
+			if (send(nfsock, packet, (size_t)offset, 0) == -1)
+				return (-1);
+			*flows_exported += j;
+			j = 0;
+			num_packets++;
+		}
+		if (j == 0) {
+			memset(&packet, '\0', sizeof(packet));
+			hdr->version = htons(1);
+			hdr->flows = 0; /* Filled in as we go */
+			hdr->uptime_ms = htonl(uptime_ms);
+			hdr->time_sec = htonl(now.tv_sec);
+			hdr->time_nanosec = htonl(now.tv_usec * 1000);
+			offset = sizeof(*hdr);
+		}		
+		flw = (struct NF1_FLOW *)(packet + offset);
+		
+		/* NetFlow v.1 doesn't do IPv6 */
+		if (flows[i]->af != AF_INET)
+			continue;
+		if (flows[i]->octets[0] > 0) {
+			flw->src_ip = flows[i]->addr[0].v4.s_addr;
+			flw->dest_ip = flows[i]->addr[1].v4.s_addr;
+			flw->src_port = flows[i]->port[0];
+			flw->dest_port = flows[i]->port[1];
+			flw->flow_packets = htonl(flows[i]->packets[0]);
+			flw->flow_octets = htonl(flows[i]->octets[0]);
+			flw->flow_start =
+			    htonl(timeval_sub_ms(&flows[i]->flow_start,
+			    system_boot_time));
+			flw->flow_finish = 
+			    htonl(timeval_sub_ms(&flows[i]->flow_last,
+			    system_boot_time));
+			flw->protocol = flows[i]->protocol;
+			flw->tcp_flags = flows[i]->tcp_flags[0];
+			offset += sizeof(*flw);
+			j++;
+			hdr->flows++;
+		}
+		flw = (struct NF1_FLOW *)(packet + offset);
+
+		if (flows[i]->octets[1] > 0) {
+			flw->src_ip = flows[i]->addr[1].v4.s_addr;
+			flw->dest_ip = flows[i]->addr[0].v4.s_addr;
+			flw->src_port = flows[i]->port[1];
+			flw->dest_port = flows[i]->port[0];
+			flw->flow_packets = htonl(flows[i]->packets[1]);
+			flw->flow_octets = htonl(flows[i]->octets[1]);
+			flw->flow_start =
+			    htonl(timeval_sub_ms(&flows[i]->flow_start,
+			    system_boot_time));
+			flw->flow_finish =
+			    htonl(timeval_sub_ms(&flows[i]->flow_last,
+			    system_boot_time));
+			flw->protocol = flows[i]->protocol;
+			flw->tcp_flags = flows[i]->tcp_flags[1];
+			offset += sizeof(*flw);
+			j++;
+			hdr->flows++;
+		}
+	}
+
+	/* Send any leftovers */
+	if (j != 0) {
+		if (verbose_flag)
+			logit(LOG_DEBUG, "Sending flow packet len = %d", offset);
+		hdr->flows = htons(hdr->flows);
+		errsz = sizeof(err);
+		getsockopt(nfsock, SOL_SOCKET, SO_ERROR,
+		    &err, &errsz); /* Clear ICMP errors */
+		if (send(nfsock, packet, (size_t)offset, 0) == -1)
+			return (-1);
+		num_packets++;
+	}
+
+	*flows_exported += j;
+	return (num_packets);
+}

+ 170 - 0
netflow5.c

@@ -0,0 +1,170 @@
+/*
+ * Copyright 2002 Damien Miller <djm@mindrot.org> All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/* $Id: netflow5.c,v 1.3 2005/05/05 03:31:42 djm Exp $ */
+
+#include "common.h"
+#include "log.h"
+#include "treetype.h"
+#include "softflowd.h"
+
+RCSID("$Id: netflow5.c,v 1.3 2005/05/05 03:31:42 djm Exp $");
+
+/*
+ * This is the Cisco Netflow(tm) version 5 packet format
+ * Based on:
+ * http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_0/nfc_ug/nfcform.htm
+ */
+struct NF5_HEADER {
+	u_int16_t version, flows;
+	u_int32_t uptime_ms, time_sec, time_nanosec, flow_sequence;
+	u_int8_t engine_type, engine_id, reserved1, reserved2;
+};
+struct NF5_FLOW {
+	u_int32_t src_ip, dest_ip, nexthop_ip;
+	u_int16_t if_index_in, if_index_out;
+	u_int32_t flow_packets, flow_octets;
+	u_int32_t flow_start, flow_finish;
+	u_int16_t src_port, dest_port;
+	u_int8_t pad1;
+	u_int8_t tcp_flags, protocol, tos;
+	u_int16_t src_as, dest_as;
+	u_int8_t src_mask, dst_mask;
+	u_int16_t pad2;
+};
+#define NF5_MAXFLOWS		30
+#define NF5_MAXPACKET_SIZE	(sizeof(struct NF5_HEADER) + \
+				 (NF5_MAXFLOWS * sizeof(struct NF5_FLOW)))
+
+/*
+ * Given an array of expired flows, send netflow v5 report packets
+ * Returns number of packets sent or -1 on error
+ */
+int
+send_netflow_v5(struct FLOW **flows, int num_flows, int nfsock,
+    u_int64_t *flows_exported, struct timeval *system_boot_time,
+    int verbose_flag)
+{
+	struct timeval now;
+	u_int32_t uptime_ms;
+	u_int8_t packet[NF5_MAXPACKET_SIZE];	/* Maximum allowed packet size (24 flows) */
+	struct NF5_HEADER *hdr = NULL;
+	struct NF5_FLOW *flw = NULL;
+	int i, j, offset, num_packets, err;
+	socklen_t errsz;
+	
+	gettimeofday(&now, NULL);
+	uptime_ms = timeval_sub_ms(&now, system_boot_time);
+
+	hdr = (struct NF5_HEADER *)packet;
+	for (num_packets = offset = j = i = 0; i < num_flows; i++) {
+		if (j >= NF5_MAXFLOWS - 1) {
+			if (verbose_flag)
+				logit(LOG_DEBUG, "Sending flow packet len = %d", offset);
+			hdr->flows = htons(hdr->flows);
+			errsz = sizeof(err);
+			getsockopt(nfsock, SOL_SOCKET, SO_ERROR,
+			    &err, &errsz); /* Clear ICMP errors */
+			if (send(nfsock, packet, (size_t)offset, 0) == -1)
+				return (-1);
+			*flows_exported += j;
+			j = 0;
+			num_packets++;
+		}
+		if (j == 0) {
+			memset(&packet, '\0', sizeof(packet));
+			hdr->version = htons(5);
+			hdr->flows = 0; /* Filled in as we go */
+			hdr->uptime_ms = htonl(uptime_ms);
+			hdr->time_sec = htonl(now.tv_sec);
+			hdr->time_nanosec = htonl(now.tv_usec * 1000);
+			hdr->flow_sequence = htonl(*flows_exported);
+			/* Other fields are left zero */
+			offset = sizeof(*hdr);
+		}		
+		flw = (struct NF5_FLOW *)(packet + offset);
+
+		/* NetFlow v.5 doesn't do IPv6 */
+		if (flows[i]->af != AF_INET)
+			continue;
+		if (flows[i]->octets[0] > 0) {
+			flw->src_ip = flows[i]->addr[0].v4.s_addr;
+			flw->dest_ip = flows[i]->addr[1].v4.s_addr;
+			flw->src_port = flows[i]->port[0];
+			flw->dest_port = flows[i]->port[1];
+			flw->flow_packets = htonl(flows[i]->packets[0]);
+			flw->flow_octets = htonl(flows[i]->octets[0]);
+			flw->flow_start =
+			    htonl(timeval_sub_ms(&flows[i]->flow_start,
+			    system_boot_time));
+			flw->flow_finish =
+			    htonl(timeval_sub_ms(&flows[i]->flow_last,
+			    system_boot_time));
+			flw->tcp_flags = flows[i]->tcp_flags[0];
+			flw->protocol = flows[i]->protocol;
+			offset += sizeof(*flw);
+			j++;
+			hdr->flows++;
+		}
+		flw = (struct NF5_FLOW *)(packet + offset);
+
+		if (flows[i]->octets[1] > 0) {
+			flw->src_ip = flows[i]->addr[1].v4.s_addr;
+			flw->dest_ip = flows[i]->addr[0].v4.s_addr;
+			flw->src_port = flows[i]->port[1];
+			flw->dest_port = flows[i]->port[0];
+			flw->flow_packets = htonl(flows[i]->packets[1]);
+			flw->flow_octets = htonl(flows[i]->octets[1]);
+			flw->flow_start =
+			    htonl(timeval_sub_ms(&flows[i]->flow_start,
+			    system_boot_time));
+			flw->flow_finish =
+			    htonl(timeval_sub_ms(&flows[i]->flow_last,
+			    system_boot_time));
+			flw->tcp_flags = flows[i]->tcp_flags[1];
+			flw->protocol = flows[i]->protocol;
+			offset += sizeof(*flw);
+			j++;
+			hdr->flows++;
+		}
+	}
+
+	/* Send any leftovers */
+	if (j != 0) {
+		if (verbose_flag)
+			logit(LOG_DEBUG, "Sending v5 flow packet len = %d",
+			    offset);
+		hdr->flows = htons(hdr->flows);
+		errsz = sizeof(err);
+		getsockopt(nfsock, SOL_SOCKET, SO_ERROR,
+		    &err, &errsz); /* Clear ICMP errors */
+		if (send(nfsock, packet, (size_t)offset, 0) == -1)
+			return (-1);
+		num_packets++;
+	}
+
+	*flows_exported += j;
+	return (num_packets);
+}
+

+ 377 - 0
netflow9.c

@@ -0,0 +1,377 @@
+/*
+ * Copyright 2002 Damien Miller <djm@mindrot.org> All rights reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/* $Id: netflow9.c,v 1.9 2006/03/16 08:23:13 djm Exp $ */
+
+#include "common.h"
+#include "log.h"
+#include "treetype.h"
+#include "softflowd.h"
+
+RCSID("$Id: netflow9.c,v 1.9 2006/03/16 08:23:13 djm Exp $");
+
+/* Netflow v.9 */
+struct NF9_HEADER {
+	u_int16_t version, flows;
+	u_int32_t uptime_ms, time_sec;
+	u_int32_t package_sequence, source_id;
+} __packed;
+struct NF9_FLOWSET_HEADER_COMMON {
+	u_int16_t flowset_id, length;
+} __packed;
+struct NF9_TEMPLATE_FLOWSET_HEADER {
+	struct NF9_FLOWSET_HEADER_COMMON c;
+	u_int16_t template_id, count;
+} __packed;
+struct NF9_TEMPLATE_FLOWSET_RECORD {
+	u_int16_t type, length;
+} __packed;
+struct NF9_DATA_FLOWSET_HEADER {
+	struct NF9_FLOWSET_HEADER_COMMON c;
+} __packed;
+#define NF9_TEMPLATE_FLOWSET_ID		0
+#define NF9_OPTIONS_FLOWSET_ID		1
+#define NF9_MIN_RECORD_FLOWSET_ID	256
+
+/* Flowset record types the we care about */
+#define NF9_IN_BYTES			1
+#define NF9_IN_PACKETS			2
+/* ... */
+#define NF9_IN_PROTOCOL			4
+/* ... */
+#define NF9_TCP_FLAGS			6
+#define NF9_L4_SRC_PORT			7
+#define NF9_IPV4_SRC_ADDR		8
+/* ... */
+#define NF9_L4_DST_PORT			11
+#define NF9_IPV4_DST_ADDR		12
+/* ... */
+#define NF9_LAST_SWITCHED		21
+#define NF9_FIRST_SWITCHED		22
+/* ... */
+#define NF9_IPV6_SRC_ADDR		27
+#define NF9_IPV6_DST_ADDR		28
+/* ... */
+#define NF9_IP_PROTOCOL_VERSION		60
+
+/* Stuff pertaining to the templates that softflowd uses */
+#define NF9_SOFTFLOWD_TEMPLATE_NRECORDS	11
+struct NF9_SOFTFLOWD_TEMPLATE {
+	struct NF9_TEMPLATE_FLOWSET_HEADER h;
+	struct NF9_TEMPLATE_FLOWSET_RECORD r[NF9_SOFTFLOWD_TEMPLATE_NRECORDS];
+} __packed;
+
+/* softflowd data flowset types */
+struct NF9_SOFTFLOWD_DATA_COMMON {
+	u_int32_t first_switched, last_switched;
+	u_int32_t bytes, packets;
+	u_int16_t src_port, dst_port;
+	u_int8_t protocol, tcp_flags, ipproto;
+} __packed;
+
+struct NF9_SOFTFLOWD_DATA_V4 {
+	u_int32_t src_addr, dst_addr;
+	struct NF9_SOFTFLOWD_DATA_COMMON c;
+} __packed;
+
+struct NF9_SOFTFLOWD_DATA_V6 {
+	u_int8_t src_addr[16], dst_addr[16];
+	struct NF9_SOFTFLOWD_DATA_COMMON c;
+} __packed;
+
+/* Local data: templates and counters */
+#define NF9_SOFTFLOWD_MAX_PACKET_SIZE	512
+#define NF9_SOFTFLOWD_V4_TEMPLATE_ID	1024
+#define NF9_SOFTFLOWD_V6_TEMPLATE_ID	2048
+
+#define NF9_DEFAULT_TEMPLATE_INTERVAL	16
+
+static struct NF9_SOFTFLOWD_TEMPLATE v4_template;
+static struct NF9_SOFTFLOWD_TEMPLATE v6_template;
+static int nf9_pkts_until_template = -1;
+
+static void
+nf9_init_template(void)
+{
+	bzero(&v4_template, sizeof(v4_template));
+	v4_template.h.c.flowset_id = htons(0);
+	v4_template.h.c.length = htons(sizeof(v4_template));
+	v4_template.h.template_id = htons(NF9_SOFTFLOWD_V4_TEMPLATE_ID);
+	v4_template.h.count = htons(NF9_SOFTFLOWD_TEMPLATE_NRECORDS);
+	v4_template.r[0].type = htons(NF9_IPV4_SRC_ADDR);
+	v4_template.r[0].length = htons(4);
+	v4_template.r[1].type = htons(NF9_IPV4_DST_ADDR);
+	v4_template.r[1].length = htons(4);
+	v4_template.r[2].type = htons(NF9_LAST_SWITCHED);
+	v4_template.r[2].length = htons(4);
+	v4_template.r[3].type = htons(NF9_FIRST_SWITCHED);
+	v4_template.r[3].length = htons(4);
+	v4_template.r[4].type = htons(NF9_IN_BYTES);
+	v4_template.r[4].length = htons(4);
+	v4_template.r[5].type = htons(NF9_IN_PACKETS);
+	v4_template.r[5].length = htons(4);
+	v4_template.r[6].type = htons(NF9_L4_SRC_PORT);
+	v4_template.r[6].length = htons(2);
+	v4_template.r[7].type = htons(NF9_L4_DST_PORT);
+	v4_template.r[7].length = htons(2);
+	v4_template.r[8].type = htons(NF9_IN_PROTOCOL);
+	v4_template.r[8].length = htons(1);
+	v4_template.r[9].type = htons(NF9_TCP_FLAGS);
+	v4_template.r[9].length = htons(1);
+	v4_template.r[10].type = htons(NF9_IP_PROTOCOL_VERSION);
+	v4_template.r[10].length = htons(1);
+
+	bzero(&v6_template, sizeof(v6_template));
+	v6_template.h.c.flowset_id = htons(0);
+	v6_template.h.c.length = htons(sizeof(v6_template));
+	v6_template.h.template_id = htons(NF9_SOFTFLOWD_V6_TEMPLATE_ID);
+	v6_template.h.count = htons(NF9_SOFTFLOWD_TEMPLATE_NRECORDS);
+	v6_template.r[0].type = htons(NF9_IPV6_SRC_ADDR);
+	v6_template.r[0].length = htons(16);
+	v6_template.r[1].type = htons(NF9_IPV6_DST_ADDR);
+	v6_template.r[1].length = htons(16);
+	v6_template.r[2].type = htons(NF9_LAST_SWITCHED);
+	v6_template.r[2].length = htons(4);
+	v6_template.r[3].type = htons(NF9_FIRST_SWITCHED);
+	v6_template.r[3].length = htons(4);
+	v6_template.r[4].type = htons(NF9_IN_BYTES);
+	v6_template.r[4].length = htons(4);
+	v6_template.r[5].type = htons(NF9_IN_PACKETS);
+	v6_template.r[5].length = htons(4);
+	v6_template.r[6].type = htons(NF9_L4_SRC_PORT);
+	v6_template.r[6].length = htons(2);
+	v6_template.r[7].type = htons(NF9_L4_DST_PORT);
+	v6_template.r[7].length = htons(2);
+	v6_template.r[8].type = htons(NF9_IN_PROTOCOL);
+	v6_template.r[8].length = htons(1);
+	v6_template.r[9].type = htons(NF9_TCP_FLAGS);
+	v6_template.r[9].length = htons(1);
+	v6_template.r[10].type = htons(NF9_IP_PROTOCOL_VERSION);
+	v6_template.r[10].length = htons(1);
+}
+
+static int
+nf_flow_to_flowset(const struct FLOW *flow, u_char *packet, u_int len,
+    const struct timeval *system_boot_time, u_int *len_used)
+{
+	union {
+		struct NF9_SOFTFLOWD_DATA_V4 d4;
+		struct NF9_SOFTFLOWD_DATA_V6 d6;
+	} d[2];
+	struct NF9_SOFTFLOWD_DATA_COMMON *dc[2];
+	u_int freclen, ret_len, nflows;
+
+	bzero(d, sizeof(d));
+	*len_used = nflows = ret_len = 0;
+	switch (flow->af) {
+	case AF_INET:
+		freclen = sizeof(struct NF9_SOFTFLOWD_DATA_V4);
+		memcpy(&d[0].d4.src_addr, &flow->addr[0].v4, 4);
+		memcpy(&d[0].d4.dst_addr, &flow->addr[1].v4, 4);
+		memcpy(&d[1].d4.src_addr, &flow->addr[1].v4, 4);
+		memcpy(&d[1].d4.dst_addr, &flow->addr[0].v4, 4);
+		dc[0] = &d[0].d4.c;
+		dc[1] = &d[1].d4.c;
+		dc[0]->ipproto = dc[1]->ipproto = 4;
+		break;
+	case AF_INET6:
+		freclen = sizeof(struct NF9_SOFTFLOWD_DATA_V6);
+		memcpy(&d[0].d6.src_addr, &flow->addr[0].v6, 16);
+		memcpy(&d[0].d6.dst_addr, &flow->addr[1].v6, 16);
+		memcpy(&d[1].d6.src_addr, &flow->addr[1].v6, 16);
+		memcpy(&d[1].d6.dst_addr, &flow->addr[0].v6, 16);
+		dc[0] = &d[0].d6.c;
+		dc[1] = &d[1].d6.c;
+		dc[0]->ipproto = dc[1]->ipproto = 6;
+		break;
+	default:
+		return (-1);
+	}
+
+	dc[0]->first_switched = dc[1]->first_switched = 
+	    htonl(timeval_sub_ms(&flow->flow_start, system_boot_time));
+	dc[0]->last_switched = dc[1]->last_switched = 
+	    htonl(timeval_sub_ms(&flow->flow_last, system_boot_time));
+	dc[0]->bytes = htonl(flow->octets[0]);
+	dc[1]->bytes = htonl(flow->octets[1]);
+	dc[0]->packets = htonl(flow->packets[0]);
+	dc[1]->packets = htonl(flow->packets[1]);
+	dc[0]->src_port = dc[1]->dst_port = flow->port[0];
+	dc[1]->src_port = dc[0]->dst_port = flow->port[1];
+	dc[0]->protocol = dc[1]->protocol = flow->protocol;
+	dc[0]->tcp_flags = flow->tcp_flags[0];
+	dc[1]->tcp_flags = flow->tcp_flags[1];
+
+	if (flow->octets[0] > 0) {
+		if (ret_len + freclen > len)
+			return (-1);
+		memcpy(packet + ret_len, &d[0], freclen);
+		ret_len += freclen;
+		nflows++;
+	}
+	if (flow->octets[1] > 0) {
+		if (ret_len + freclen > len)
+			return (-1);
+		memcpy(packet + ret_len, &d[1], freclen);
+		ret_len += freclen;
+		nflows++;
+	}
+
+	*len_used = ret_len;
+	return (nflows);
+}
+
+/*
+ * Given an array of expired flows, send netflow v9 report packets
+ * Returns number of packets sent or -1 on error
+ */
+int
+send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock,
+    u_int64_t *flows_exported, struct timeval *system_boot_time,
+    int verbose_flag)
+{
+	struct NF9_HEADER *nf9;
+	struct NF9_DATA_FLOWSET_HEADER *dh;
+	struct timeval now;
+	u_int offset, last_af, i, j, num_packets, inc, last_valid;
+	socklen_t errsz;
+	int err, r;
+	u_char packet[NF9_SOFTFLOWD_MAX_PACKET_SIZE];
+
+	gettimeofday(&now, NULL);
+
+	if (nf9_pkts_until_template == -1) {
+		nf9_init_template();
+		nf9_pkts_until_template = 0;
+	}		
+
+	last_valid = num_packets = 0;
+	for (j = 0; j < num_flows;) {
+		bzero(packet, sizeof(packet));
+		nf9 = (struct NF9_HEADER *)packet;
+
+		nf9->version = htons(9);
+		nf9->flows = 0; /* Filled as we go, htons at end */
+		nf9->uptime_ms = htonl(timeval_sub_ms(&now, system_boot_time));
+		nf9->time_sec = htonl(time(NULL));
+		nf9->package_sequence = htonl(*flows_exported + j);
+		nf9->source_id = 0;
+		offset = sizeof(*nf9);
+
+		/* Refresh template headers if we need to */
+		if (nf9_pkts_until_template <= 0) {
+			memcpy(packet + offset, &v4_template,
+			    sizeof(v4_template));
+			offset += sizeof(v4_template);
+			memcpy(packet + offset, &v6_template,
+			    sizeof(v6_template));
+			offset += sizeof(v6_template);
+			nf9_pkts_until_template = NF9_DEFAULT_TEMPLATE_INTERVAL;
+		}
+
+		dh = NULL;
+		last_af = 0;
+		for (i = 0; i + j < num_flows; i++) {
+			if (dh == NULL || flows[i + j]->af != last_af) {
+				if (dh != NULL) {
+					if (offset % 4 != 0) {
+						/* Pad to multiple of 4 */
+						dh->c.length += 4 - (offset % 4);
+						offset += 4 - (offset % 4);
+					}
+					/* Finalise last header */
+					dh->c.length = htons(dh->c.length);
+				}
+				if (offset + sizeof(*dh) > sizeof(packet)) {
+					/* Mark header is finished */
+					dh = NULL;
+					break;
+				}
+				dh = (struct NF9_DATA_FLOWSET_HEADER *)
+				    (packet + offset);
+				dh->c.flowset_id =
+				    (flows[i + j]->af == AF_INET) ?
+				    v4_template.h.template_id : 
+				    v6_template.h.template_id;
+				last_af = flows[i + j]->af;
+				last_valid = offset;
+				dh->c.length = sizeof(*dh); /* Filled as we go */
+				offset += sizeof(*dh);
+			}
+
+			r = nf_flow_to_flowset(flows[i + j], packet + offset,
+			    sizeof(packet) - offset, system_boot_time, &inc);
+			if (r <= 0) {
+				/* yank off data header, if we had to go back */
+				if (last_valid)
+					offset = last_valid;
+				break;
+			}
+			offset += inc;
+			dh->c.length += inc;
+			nf9->flows += r;
+			last_valid = 0; /* Don't clobber this header now */
+			if (verbose_flag) {
+				logit(LOG_DEBUG, "Flow %d/%d: "
+				    "r %d offset %d type %04x len %d(0x%04x) "
+				    "flows %d", r, i, j, offset, 
+				    dh->c.flowset_id, dh->c.length, 
+				    dh->c.length, nf9->flows);
+			}
+		}
+		/* Don't finish header if it has already been done */
+		if (dh != NULL) {
+			if (offset % 4 != 0) {
+				/* Pad to multiple of 4 */
+				dh->c.length += 4 - (offset % 4);
+				offset += 4 - (offset % 4);
+			}
+			/* Finalise last header */
+			dh->c.length = htons(dh->c.length);
+		}
+		nf9->flows = htons(nf9->flows);
+
+		if (verbose_flag)
+			logit(LOG_DEBUG, "Sending flow packet len = %d", offset);
+		errsz = sizeof(err);
+		/* Clear ICMP errors */
+		getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz); 
+		if (send(nfsock, packet, (size_t)offset, 0) == -1)
+			return (-1);
+		num_packets++;
+		nf9_pkts_until_template--;
+
+		j += i;
+	}
+
+	*flows_exported += j;
+	return (num_packets);
+}
+
+void
+netflow9_resend_template(void)
+{
+	if (nf9_pkts_until_template > 0)
+		nf9_pkts_until_template = 0;
+}

+ 95 - 0
softflowctl.8

@@ -0,0 +1,95 @@
+.\" $Id: softflowctl.8,v 1.2 2006/03/16 08:24:19 djm Exp $
+.\"
+.\" Copyright (c) 2002 Damien Miller.  All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" 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.
+.\"
+.Dd October 18, 2002
+.Dt SOFTFLOWCTL 8
+.Os
+.Sh NAME
+.Nm softflowctl
+.Nd Remote control program for softflowd
+.Sh SYNOPSIS
+.Nm softflowctl
+.Op Fl h
+.Op Fl c Ar ctl_sock
+.Ar command
+.Sh DESCRIPTION
+.Nm
+is a remote control program used to control a running
+.Xr softflowd 8 
+daemon.
+.Pp
+The command-line options are as follows:
+.Bl -tag -width Ds
+.It Fl c Ar ctlsock
+Specify an alternate location for the remote control socket.
+Default is 
+.Pa /var/run/softflowd.ctl
+.It Fl h
+Displays commandline usage information.
+.El
+.Pp
+.Sh COMMANDS
+.Bl -tag -width Ds
+.It Pa shutdown
+Ask
+.Xr softflowd 8
+to gracefully exit. This is equivalent to sending it a 
+.Dv SIGTERM 
+or 
+.Dv SIGINT .
+.It Pa exit
+Ask
+.Xr softflowd 8
+to immediately exit. No flow expiry processing or data export is performed.
+.It Pa expire-all
+Immediately expire all tracked flows.
+.It Pa delete-all
+Immediately delete all tracked flows. No flow expiry processing or data 
+export is performed.
+.It Pa statistics
+Return statistics collected by 
+.Xr softflowd 8
+on expired flows.
+.It Pa debug+
+Increase the debugging level of 
+.Xr softflowd 8
+.It Pa debug-
+Decrease the debugging level.
+.It Pa stop-gather
+Stops network data collection by
+.Xr softflowd 8 .
+.It Pa start-gather
+Resumes network data collection.
+.It Pa dump-flows
+Return information on all tracked flows.
+.It Pa timeouts
+Print information on flow timeout parameters.
+.It Pa send-template
+Resend a NetFlow v.9 template record before the next flow export.
+Has no effect for other flow export versions.
+.El
+.Sh AUTHORS
+Damien Miller <djm@mindrot.org>
+.Sh SEE ALSO
+.Xr softflowd 8