Browse Source

Merge upstream version 0.9.9

Christoph Biedl 13 years ago
parent
commit
693ac7f191
27 changed files with 6010 additions and 384 deletions
  1. 4 0
      .hg_archival.txt
  2. 0 283
      ChangeLog
  3. 0 2
      Makefile.in
  4. 0 2
      README
  5. 0 2
      closefrom.c
  6. 1 1
      collector.pl
  7. 1 1
      common.h
  8. 169 0
      config.h.in
  9. 5673 0
      configure
  10. 4 2
      configure.ac
  11. 0 2
      convtime.c
  12. 0 4
      log.c
  13. 0 2
      log.h
  14. 0 2
      mkinstalldirs
  15. 2 6
      netflow1.c
  16. 8 7
      netflow5.c
  17. 79 12
      netflow9.c
  18. 0 2
      softflowctl.8
  19. 0 2
      softflowctl.c
  20. 13 11
      softflowd.8
  21. 41 28
      softflowd.c
  22. 14 3
      softflowd.h
  23. 0 1
      softflowd.init
  24. 1 3
      softflowd.spec
  25. 0 2
      strlcat.c
  26. 0 2
      strlcpy.c
  27. 0 2
      treetype.h

+ 4 - 0
.hg_archival.txt

@@ -0,0 +1,4 @@
+repo: a471267f42340e3926cc0d68c98ec64789cffcca
+node: c496d4d4934828f6b62ff38e1702891f75710b0a
+branch: default
+tag: softflowd-0.9.9

+ 0 - 283
ChangeLog

@@ -1,283 +0,0 @@
-20100504
- - (djm) Swap nf9 last/first switched. They were reversed in the struct
-   vs our template flowset. Patch from stephen AT sfnelson.org.
-   https://bugzilla.mindrot.org/show_bug.cgi?id=1760
-
-20091001
- - (djm) Lots of manpage tweaks from Tamas TEVESZ, ice AT extreme.hu
- - (djm) Support manual specification of an interface index to be used
-   as the input and output interface of all flows generated. Patch from
-   kempf AT rpi.edu
- - (djm) One more manpage tweak from Tamas TEVESZ.
- - (djm) Display softflowd start time in "softflowctl statistics" display.
-   Suggestion from Tamas TEVESZ.
-
-20080515
- - (djm) Fix typo in manpage for PID file location; patch from
-    ice AT extreme.hu
- - (djm) Make privsep directory compile-time configurable; patch from
-    ice AT extreme.hu
-
-20070901
- - (djm) Implement a very simple freelist allocator for flows and expiry
-   events
-
-20070831
- - (djm) Move max_flows into struct FLOWTRACK
-
-20070726
- - (djm) Add flow_get/flow_put and expiry_get/expiry_put functions to 
-   allocate and deallocate flows and expiry events, instead of calling
-   malloc/free directly. Right now these functions just call malloc/free
-   anyway, but they will soon be used to implemented pooled flow/expiry
-   allocations.
-
-20070725
- - (djm) KNF
- - (djm) Correctly exit from mainloop on signal - patch from Florian Weimer
- - (djm) openlog with LOG_NDELAY so socket is connected before privdrop - 
-   patch from Florian Weimer
-
-20061102
- - (djm) Document -v option and close Ed in manpage; from Nino Jogun
-   nino80 AT gmail.com
-
-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$
-

+ 0 - 2
Makefile.in

@@ -1,5 +1,3 @@
-# $Id$
-
 prefix=@prefix@
 exec_prefix=@exec_prefix@
 bindir=@bindir@

+ 0 - 2
README

@@ -66,5 +66,3 @@ The latest source code may be obtained from Google Code:
 http://code.google.com/p/softflowd/
 
 Damien Miller <djm@mindrot.org>
-
-$Id$

+ 0 - 2
closefrom.c

@@ -46,8 +46,6 @@
 # define OPEN_MAX	256
 #endif
 
-RCSID("$Id$");
-
 #ifndef lint
 static const char rcsid[] = "$Sudo: closefrom.c,v 1.6 2004/06/01 20:51:56 millert Exp $";
 #endif /* lint */

+ 1 - 1
collector.pl

@@ -3,7 +3,7 @@
 # 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
+# http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html 
 
 # XXX Doesn't support NetFlow 9
 

+ 1 - 1
common.h

@@ -73,7 +73,7 @@
 #define PROGNAME		"softflowd"
 
 /* The name of the program */
-#define PROGVER			"0.9.8"
+#define PROGVER			"0.9.9"
 
 /* Default pidfile */
 #define DEFAULT_PIDFILE		"/var/run/" PROGNAME ".pid"

+ 169 - 0
config.h.in

@@ -0,0 +1,169 @@
+/* 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 home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* privdrop chroot directory */
+#undef PRIVDROP_CHROOT_DIR
+
+/* 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
+ 5673 - 0
configure


+ 4 - 2
configure.ac

@@ -1,5 +1,3 @@
-# $Id$
-#
 # Copyright (c) 2004 Damien Miller
 #
 # Permission to use, copy, modify, and distribute this software for any
@@ -49,6 +47,10 @@ AC_ARG_WITH(libs,
 	[  --with-libs             Specify additional libraries to link with],
 	[ if test "x$withval" != "xno" ; then LIBS="$LIBS $withval"; fi ]	
 )
+AC_ARG_WITH(chrootdir,
+	[  --with-chrootdir        Specify chroot directory],
+	[ AC_DEFINE_UNQUOTED([PRIVDROP_CHROOT_DIR], ["${withval}"], [privdrop chroot directory]) ]	
+)
 
 AC_CHECK_HEADERS(net/bpf.h pcap.h pcap-bpf.h)
 

+ 0 - 2
convtime.c

@@ -25,8 +25,6 @@
 #include "common.h"
 #include "convtime.h"
 
-RCSID("$Id$");
-
 #define SECONDS		1
 #define MINUTES		(SECONDS * 60)
 #define HOURS		(MINUTES * 60)

+ 0 - 4
log.c

@@ -22,14 +22,10 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id$ */
-
 #include "common.h"
 #include "log.h"
 #include <stdarg.h>
 
-RCSID("$Id$");
-
 static int logstderr = 0;
 
 void

+ 0 - 2
log.h

@@ -22,8 +22,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id$ */
-
 #ifndef _LOG_H
 #define _LOG_H
 

+ 0 - 2
mkinstalldirs

@@ -4,8 +4,6 @@
 # Created: 1993-05-16
 # Public domain
 
-# $Id$
-
 errstatus=0
 
 for file

+ 2 - 6
netflow1.c

@@ -22,19 +22,15 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id$ */
-
 #include "common.h"
 #include "log.h"
 #include "treetype.h"
 #include "softflowd.h"
 
-RCSID("$Id$");
-
 /*
  * 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
+ * http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html 
  */
 struct NF1_HEADER {
 	u_int16_t version, flows;
@@ -66,7 +62,7 @@ struct NF1_FLOW {
 int
 send_netflow_v1(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx,
     u_int64_t *flows_exported, struct timeval *system_boot_time, 
-    int verbose_flag)
+    int verbose_flag, struct OPTION *option)
 {
 	struct timeval now;
 	u_int32_t uptime_ms;

+ 8 - 7
netflow5.c

@@ -22,24 +22,21 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id$ */
-
 #include "common.h"
 #include "log.h"
 #include "treetype.h"
 #include "softflowd.h"
 
-RCSID("$Id$");
-
 /*
  * 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
+ * http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html 
  */
 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;
+	u_int8_t engine_type, engine_id;
+	u_int16_t sampling_interval;
 };
 struct NF5_FLOW {
 	u_int32_t src_ip, dest_ip, nexthop_ip;
@@ -64,7 +61,7 @@ struct NF5_FLOW {
 int
 send_netflow_v5(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx,
     u_int64_t *flows_exported, struct timeval *system_boot_time,
-    int verbose_flag)
+    int verbose_flag, struct OPTION *option)
 {
 	struct timeval now;
 	u_int32_t uptime_ms;
@@ -100,6 +97,10 @@ send_netflow_v5(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx,
 			hdr->time_sec = htonl(now.tv_sec);
 			hdr->time_nanosec = htonl(now.tv_usec * 1000);
 			hdr->flow_sequence = htonl(*flows_exported);
+			if (option->sample > 0) {
+				hdr->sampling_interval =
+					htons(0x01 << 14 | option->sample & 0x3FFF);
+			}
 			/* Other fields are left zero */
 			offset = sizeof(*hdr);
 		}		

+ 79 - 12
netflow9.c

@@ -22,15 +22,11 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id$ */
-
 #include "common.h"
 #include "log.h"
 #include "treetype.h"
 #include "softflowd.h"
 
-RCSID("$Id$");
-
 /* Netflow v.9 */
 struct NF9_HEADER {
 	u_int16_t version, flows;
@@ -44,6 +40,10 @@ struct NF9_TEMPLATE_FLOWSET_HEADER {
 	struct NF9_FLOWSET_HEADER_COMMON c;
 	u_int16_t template_id, count;
 } __packed;
+struct NF9_OPTION_TEMPLATE_FLOWSET_HEADER {
+	struct NF9_FLOWSET_HEADER_COMMON c;
+	u_int16_t template_id, scope_length, option_length;
+} __packed;
 struct NF9_TEMPLATE_FLOWSET_RECORD {
 	u_int16_t type, length;
 } __packed;
@@ -76,15 +76,26 @@ struct NF9_DATA_FLOWSET_HEADER {
 #define NF9_IPV6_SRC_ADDR		27
 #define NF9_IPV6_DST_ADDR		28
 /* ... */
+#define NF9_SAMPLING_INTERVAL           34
+#define NF9_SAMPLING_ALGORITHM          35
+/* ... */
 #define NF9_IP_PROTOCOL_VERSION		60
 
 /* Stuff pertaining to the templates that softflowd uses */
-#define NF9_SOFTFLOWD_TEMPLATE_NRECORDS	11
+#define NF9_SOFTFLOWD_TEMPLATE_NRECORDS	13
 struct NF9_SOFTFLOWD_TEMPLATE {
 	struct NF9_TEMPLATE_FLOWSET_HEADER h;
 	struct NF9_TEMPLATE_FLOWSET_RECORD r[NF9_SOFTFLOWD_TEMPLATE_NRECORDS];
 } __packed;
 
+#define NF9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS	1
+#define NF9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS	2
+struct NF9_SOFTFLOWD_OPTION_TEMPLATE {
+	struct NF9_OPTION_TEMPLATE_FLOWSET_HEADER h;
+	struct NF9_TEMPLATE_FLOWSET_RECORD s[NF9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS];
+	struct NF9_TEMPLATE_FLOWSET_RECORD r[NF9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS];
+} __packed;
+
 /* softflowd data flowset types */
 struct NF9_SOFTFLOWD_DATA_COMMON {
 	u_int32_t last_switched, first_switched;
@@ -104,22 +115,44 @@ struct NF9_SOFTFLOWD_DATA_V6 {
 	struct NF9_SOFTFLOWD_DATA_COMMON c;
 } __packed;
 
+struct NF9_SOFTFLOWD_OPTION_DATA {
+	struct NF9_FLOWSET_HEADER_COMMON c;	
+	u_int32_t scope_ifidx;
+	u_int32_t sampling_interval;
+	u_int8_t sampling_algorithm;
+	u_int8_t padding[3];
+} __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_SOFTFLOWD_OPTION_TEMPLATE_ID	256
 
 #define NF9_DEFAULT_TEMPLATE_INTERVAL	16
 
+/* ... */
+#define NF9_OPTION_SCOPE_SYSTEM    1
+#define NF9_OPTION_SCOPE_INTERFACE 2
+#define NF9_OPTION_SCOPE_LINECARD  3
+#define NF9_OPTION_SCOPE_CACHE     4
+#define NF9_OPTION_SCOPE_TEMPLATE  5
+/* ... */
+#define NF9_SAMPLING_ALGORITHM_DETERMINISTIC 1
+#define NF9_SAMPLING_ALGORITHM_RANDOM        2
+/* ... */
+
 static struct NF9_SOFTFLOWD_TEMPLATE v4_template;
 static struct NF9_SOFTFLOWD_TEMPLATE v6_template;
+static struct NF9_SOFTFLOWD_OPTION_TEMPLATE option_template;
+static struct NF9_SOFTFLOWD_OPTION_DATA option_data;
 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.flowset_id = htons(NF9_TEMPLATE_FLOWSET_ID);
 	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);
@@ -151,7 +184,7 @@ nf9_init_template(void)
 	v4_template.r[12].length = htons(1);
 
 	bzero(&v6_template, sizeof(v6_template));
-	v6_template.h.c.flowset_id = htons(0);
+	v6_template.h.c.flowset_id = htons(NF9_TEMPLATE_FLOWSET_ID);
 	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);
@@ -167,10 +200,10 @@ nf9_init_template(void)
 	v6_template.r[4].length = htons(4);
 	v6_template.r[5].type = htons(NF9_IN_PACKETS);
 	v6_template.r[5].length = htons(4);
-	v4_template.r[6].type = htons(NF9_IF_INDEX_IN);
-	v4_template.r[6].length = htons(4);
-	v4_template.r[7].type = htons(NF9_IF_INDEX_OUT);
-	v4_template.r[7].length = htons(4);
+	v6_template.r[6].type = htons(NF9_IF_INDEX_IN);
+	v6_template.r[6].length = htons(4);
+	v6_template.r[7].type = htons(NF9_IF_INDEX_OUT);
+	v6_template.r[7].length = htons(4);
 	v6_template.r[8].type = htons(NF9_L4_SRC_PORT);
 	v6_template.r[8].length = htons(2);
 	v6_template.r[9].type = htons(NF9_L4_DST_PORT);
@@ -183,6 +216,28 @@ nf9_init_template(void)
 	v6_template.r[12].length = htons(1);
 }
 
+static void
+nf9_init_option(u_int16_t ifidx, struct OPTION *option) {
+	bzero(&option_template, sizeof(option_template));
+	option_template.h.c.flowset_id = htons(NF9_OPTIONS_FLOWSET_ID);
+	option_template.h.c.length = htons(sizeof(option_template));
+	option_template.h.template_id = htons(NF9_SOFTFLOWD_OPTION_TEMPLATE_ID);
+	option_template.h.scope_length = htons(sizeof(option_template.s));
+	option_template.h.option_length = htons(sizeof(option_template.r));
+	option_template.s[0].type = htons(NF9_OPTION_SCOPE_INTERFACE);
+	option_template.s[0].length = htons(sizeof(option_data.scope_ifidx));
+	option_template.r[0].type = htons(NF9_SAMPLING_INTERVAL);
+	option_template.r[0].length = htons(sizeof(option_data.sampling_interval));
+	option_template.r[1].type = htons(NF9_SAMPLING_ALGORITHM);
+	option_template.r[1].length = htons(sizeof(option_data.sampling_algorithm));
+
+	bzero(&option_data, sizeof(option_data));
+	option_data.c.flowset_id = htons(NF9_SOFTFLOWD_OPTION_TEMPLATE_ID);
+	option_data.c.length = htons(sizeof(option_data));
+	option_data.scope_ifidx = htonl(ifidx);
+	option_data.sampling_interval = htonl(option->sample);
+	option_data.sampling_algorithm = NF9_SAMPLING_ALGORITHM_DETERMINISTIC;
+}
 static int
 nf_flow_to_flowset(const struct FLOW *flow, u_char *packet, u_int len,
     u_int16_t ifidx, const struct timeval *system_boot_time, u_int *len_used)
@@ -263,7 +318,7 @@ nf_flow_to_flowset(const struct FLOW *flow, u_char *packet, u_int len,
 int
 send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx,
     u_int64_t *flows_exported, struct timeval *system_boot_time,
-    int verbose_flag)
+    int verbose_flag, struct OPTION *option)
 {
 	struct NF9_HEADER *nf9;
 	struct NF9_DATA_FLOWSET_HEADER *dh;
@@ -278,6 +333,9 @@ send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx,
 	if (nf9_pkts_until_template == -1) {
 		nf9_init_template();
 		nf9_pkts_until_template = 0;
+		if (option != NULL && option->sample > 1){
+			nf9_init_option(ifidx, option);
+		}
 	}		
 
 	last_valid = num_packets = 0;
@@ -301,6 +359,15 @@ send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx,
 			memcpy(packet + offset, &v6_template,
 			    sizeof(v6_template));
 			offset += sizeof(v6_template);
+			if (option != NULL && option->sample > 1){
+				memcpy(packet + offset, &option_template,
+				       sizeof(option_template));
+				offset += sizeof(option_template);
+				memcpy(packet + offset, &option_data,
+				       sizeof(option_data));
+				offset += sizeof(option_data);
+			}
+
 			nf9_pkts_until_template = NF9_DEFAULT_TEMPLATE_INTERVAL;
 		}
 

+ 0 - 2
softflowctl.8

@@ -1,5 +1,3 @@
-.\" $Id$
-.\"
 .\" Copyright (c) 2002 Damien Miller.  All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without

+ 0 - 2
softflowctl.c

@@ -24,8 +24,6 @@
 
 #include "common.h"
 
-RCSID("$Id$");
-
 static void
 usage(void)
 {

+ 13 - 11
softflowd.8

@@ -1,5 +1,3 @@
-.\" $Id$
-.\"
 .\" Copyright (c) 2002 Damien Miller.  All rights reserved.
 .\" Portions Copyright (c) 2001 Kevin Steves.  All rights reserved.
 .\"
@@ -35,20 +33,21 @@
 .Op Fl L Ar hoplimit
 .Op Fl T Ar track_level
 .Op Fl c Ar ctl_sock
-.Ek
+.Bk -words
 .Oo Fl i\ \&
 .Sm off
 .Oo Ar if_ndx : Oc
 .Ar interface
 .Sm on
 .Oc
-.Bk words
+.Ek
 .Op Fl m Ar max_flows
 .Op Fl n Ar host:port
 .Op Fl p Ar pidfile
 .Op Fl r Ar pcap_file
 .Op Fl t Ar timeout_name=seconds
 .Op Fl v Ar netflow_version
+.Op Fl s Ar sampling_rate
 .Op bpf_expression
 .Sh DESCRIPTION
 .Nm
@@ -161,7 +160,7 @@ Specify an alternate location for the remote control socket in daemon mode.
 Default is
 .Pa /var/run/softflowd.ctl
 .It Fl m Ar max_flows
-Specify the maximum number of flow to concurrently track.
+Specify the maximum number of flows to concurrently track.
 If this limit is exceeded, the flows which have least recently seen traffic
 are forcibly expired.
 In practice, the actual maximum may briefly exceed this limit by a
@@ -173,7 +172,7 @@ than 800k of working data.
 Set the timeout names
 .Ar timeout_name
 to
-.Ar time
+.Ar time .
 Refer to the
 .Sx Timeouts
 section for the valid timeout names and their meanings.
@@ -189,7 +188,7 @@ should not fork and daemonise itself.
 .It Fl 6
 Force
 .Nm
-To track IPv6 flows even if the NetFlow export protocol does not support
+to track IPv6 flows even if the NetFlow export protocol does not support
 reporting them.
 This is useful for debugging and statistics gathering only.
 .It Fl D
@@ -234,6 +233,8 @@ Specify which version of the NetFlow(tm) protocol
 should use for export of the flow data.
 Supported versions are 1, 5 and 9.
 Default is version 5.
+.It Fl s Ar sampling_rate
+Specify periodical sampling rate (denominator).
 .El
 .Pp
 Any further command-line arguments will be concatenated together and
@@ -336,11 +337,10 @@ instance may be controlled using the
 command.
 This interface allows one to shut down the daemon, force expiry of
 all tracked flows and extract debugging and summary data.
-Also, upon receipt of a
+Also, receipt of a
 .Dv SIGTERM
 or
-.DV SIGINT
-.Nm
+.Dv SIGINT
 will cause
 .Nm
 to exit, after expiring all flows (and thus sending flow export packets
@@ -416,5 +416,7 @@ fragmented packets, but will not record TCP or UDP port information.
 .Xr pcap 3 ,
 .Xr bpf 4
 .Bd -literal
-http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_0/nfc_ug/nfcform.htm
+http://www.ietf.org/rfc/rfc3954.txt
+.br
+http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html
 .Ed

+ 41 - 28
softflowd.c

@@ -22,8 +22,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id$ */
-
 /*
  * This is software implementation of Cisco's NetFlow(tm) traffic       
  * reporting system. It operates by listening (via libpcap) on a        
@@ -53,8 +51,6 @@
 #include "log.h"
 #include <pcap.h>
 
-RCSID("$Id$");
-
 /* Global variables */
 static int verbose_flag = 0;		/* Debugging flag */
 static u_int16_t if_index = 0;		/* "manual" interface index */
@@ -99,7 +95,7 @@ static const struct DATALINK lt[] = {
 
 /* Netflow send functions */
 typedef int (netflow_send_func_t)(struct FLOW **, int, int, u_int16_t,
-	u_int64_t *, struct timeval *, int);
+	u_int64_t *, struct timeval *, int, struct OPTION *);
 struct NETFLOW_SENDER {
 	int version;
 	netflow_send_func_t *func;
@@ -270,7 +266,7 @@ format_flow(struct FLOW *flow)
 	snprintf(ftime, sizeof(ftime), "%s", 
 	    format_time(flow->flow_last.tv_sec));
 
-	snprintf(buf, sizeof(buf),  "seq:%llu [%s]:%hu <> [%s]:%hu proto:%u "
+	snprintf(buf, sizeof(buf),  "seq:%"PRIu64" [%s]:%hu <> [%s]:%hu proto:%u "
 	    "octets>:%u packets>:%u octets<:%u packets<:%u "
 	    "start:%s.%03ld finish:%s.%03ld tcp>:%02x tcp<:%02x "
 	    "flowlabel>:%08x flowlabel<:%08x ",
@@ -298,7 +294,7 @@ format_flow_brief(struct FLOW *flow)
 	inet_ntop(flow->af, &flow->addr[1], addr2, sizeof(addr2));
 
 	snprintf(buf, sizeof(buf), 
-	    "seq:%llu [%s]:%hu <> [%s]:%hu proto:%u",
+	    "seq:%"PRIu64" [%s]:%hu <> [%s]:%hu proto:%u",
 	    flow->flow_seq,
 	    addr1, ntohs(flow->port[0]), addr2, ntohs(flow->port[1]),
 	    (int)flow->protocol);
@@ -811,7 +807,7 @@ check_expired(struct FLOWTRACK *ft, struct NETFLOW_TARGET *target, int ex)
 
 			if (verbose_flag)
 				logit(LOG_DEBUG,
-				    "Queuing flow seq:%llu (%p) for expiry "
+				    "Queuing flow seq:%"PRIu64" (%p) for expiry "
 				    "reason %d", expiry->flow->flow_seq,
 				    expiry->flow, expiry->reason);
 
@@ -851,7 +847,7 @@ check_expired(struct FLOWTRACK *ft, struct NETFLOW_TARGET *target, int ex)
 		if (target != NULL && target->fd != -1) {
 			r = target->dialect->func(expired_flows, num_expired, 
 			    target->fd, if_index, &ft->flows_exported, 
-			    &ft->system_boot_time,  verbose_flag);
+			    &ft->system_boot_time,  verbose_flag, &ft->option);
 			if (verbose_flag)
 				logit(LOG_DEBUG, "sent %d netflow packets", r);
 			if (r > 0) {
@@ -976,13 +972,16 @@ statistics(struct FLOWTRACK *ft, FILE *out, pcap_t *pcap)
 	struct pcap_stat ps;
 
 	fprintf(out, "Number of active flows: %d\n", ft->num_flows);
-	fprintf(out, "Packets processed: %llu\n", ft->total_packets);
-	fprintf(out, "Fragments: %llu\n", ft->frag_packets);
-	fprintf(out, "Ignored packets: %llu (%llu non-IP, %llu too short)\n",
+	fprintf(out, "Packets processed: %"PRIu64"\n", ft->total_packets);
+	if (ft->non_sampled_packets) 
+		fprintf(out, "Packets non-sampled: %"PRIu64"\n",
+			ft->non_sampled_packets);
+	fprintf(out, "Fragments: %"PRIu64"\n", ft->frag_packets);
+	fprintf(out, "Ignored packets: %"PRIu64" (%"PRIu64" non-IP, %"PRIu64" too short)\n",
 	    ft->non_ip_packets + ft->bad_packets, ft->non_ip_packets, ft->bad_packets);
-	fprintf(out, "Flows expired: %llu (%llu forced)\n", 
+	fprintf(out, "Flows expired: %"PRIu64" (%"PRIu64" forced)\n", 
 	    ft->flows_expired, ft->flows_force_expired);
-	fprintf(out, "Flows exported: %llu in %llu packets (%llu failures)\n",
+	fprintf(out, "Flows exported: %"PRIu64" in %"PRIu64" packets (%"PRIu64" failures)\n",
 	    ft->flows_exported, ft->packets_sent, ft->flows_dropped);
 
 	if (pcap_stats(pcap, &ps) == 0) {
@@ -1007,16 +1006,16 @@ statistics(struct FLOWTRACK *ft, FILE *out, pcap_t *pcap)
 
 		fprintf(out, "\n");
 		fprintf(out, "Expired flow reasons:\n");
-		fprintf(out, "       tcp = %9llu   tcp.rst = %9llu   "
-		    "tcp.fin = %9llu\n", ft->expired_tcp, ft->expired_tcp_rst,
+		fprintf(out, "       tcp = %9"PRIu64"   tcp.rst = %9"PRIu64"   "
+		    "tcp.fin = %9"PRIu64"\n", ft->expired_tcp, ft->expired_tcp_rst,
 		    ft->expired_tcp_fin);
-		fprintf(out, "       udp = %9llu      icmp = %9llu   "
-		    "general = %9llu\n", ft->expired_udp, ft->expired_icmp,
+		fprintf(out, "       udp = %9"PRIu64"      icmp = %9"PRIu64"   "
+		    "general = %9"PRIu64"\n", ft->expired_udp, ft->expired_icmp,
 		    ft->expired_general);
-		fprintf(out, "   maxlife = %9llu\n", ft->expired_maxlife);
-		fprintf(out, "over 2 GiB = %9llu\n", ft->expired_overbytes);
-		fprintf(out, "  maxflows = %9llu\n", ft->expired_maxflows);
-		fprintf(out, "   flushed = %9llu\n", ft->expired_flush);
+		fprintf(out, "   maxlife = %9"PRIu64"\n", ft->expired_maxlife);
+		fprintf(out, "over 2 GiB = %9"PRIu64"\n", ft->expired_overbytes);
+		fprintf(out, "  maxflows = %9"PRIu64"\n", ft->expired_maxflows);
+		fprintf(out, "   flushed = %9"PRIu64"\n", ft->expired_flush);
 
 		fprintf(out, "\n");
 
@@ -1027,7 +1026,7 @@ statistics(struct FLOWTRACK *ft, FILE *out, pcap_t *pcap)
 				pe = getprotobynumber(i);
 				snprintf(proto, sizeof(proto), "%s (%d)", 
 				    pe != NULL ? pe->p_name : "Unknown", i);
-				fprintf(out, "  %17s: %14llu %12llu   %8.2fs "
+				fprintf(out, "  %17s: %14"PRIu64" %12"PRIu64"   %8.2fs "
 				    "%10.2fs\n", proto,
 				    ft->octets_pp[i], 
 				    ft->packets_pp[i],
@@ -1052,12 +1051,12 @@ dump_flows(struct FLOWTRACK *ft, FILE *out)
 		fprintf(out, "ACTIVE %s\n", format_flow(expiry->flow));
 		if ((long int) expiry->expires_at - now < 0) {
 			fprintf(out, 
-			    "EXPIRY EVENT for flow %llu now%s\n",
+			    "EXPIRY EVENT for flow %"PRIu64" now%s\n",
 			    expiry->flow->flow_seq, 
 			    expiry->expires_at == 0 ? " (FORCED)": "");
 		} else {
 			fprintf(out, 
-			    "EXPIRY EVENT for flow %llu in %ld seconds\n",
+			    "EXPIRY EVENT for flow %"PRIu64" in %ld seconds\n",
 			    expiry->flow->flow_seq, 
 			    (long int) expiry->expires_at - now);
 		}
@@ -1128,6 +1127,13 @@ flow_cb(u_char *user_data, const struct pcap_pkthdr* phdr,
 	struct CB_CTXT *cb_ctxt = (struct CB_CTXT *)user_data;
 	struct timeval tv;
 
+	if (cb_ctxt->ft->option.sample &&
+	    (cb_ctxt->ft->total_packets +
+	     cb_ctxt->ft->non_sampled_packets) %
+	    cb_ctxt->ft->option.sample > 0) {
+		cb_ctxt->ft->non_sampled_packets++;
+		return;
+	}
 	s = datalink_check(cb_ctxt->linktype, pkt, phdr->caplen, &af);
 	if (s < 0 || (!cb_ctxt->want_v6 && af == AF_INET6)) {
 		cb_ctxt->ft->non_ip_packets++;
@@ -1496,6 +1502,7 @@ usage(void)
 "                     NetFlow export protocol supports it\n"
 "  -d                 Don't daemonise (run in foreground)\n"
 "  -D                 Debug mode: foreground + verbosity + track v6 flows\n"
+"  -s sampling_rate   Specify periodical sampling rate (denominator)\n"
 "  -h                 Display this help\n"
 "\n"
 "Valid timeout names and default values:\n"
@@ -1707,7 +1714,7 @@ main(int argc, char **argv)
 	dontfork_flag = 0;
 	always_v6 = 0;
 
-	while ((ch = getopt(argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:")) != -1) {
+	while ((ch = getopt(argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:s:")) != -1) {
 		switch (ch) {
 		case '6':
 			always_v6 = 1;
@@ -1807,6 +1814,12 @@ main(int argc, char **argv)
 			}
 			target.dialect = &nf[i];
 			break;
+		case 's':
+			flowtrack.option.sample = atoi(optarg);
+			if (flowtrack.option.sample < 2) {
+				flowtrack.option.sample = 0;
+			}
+			break;
 		default:
 			fprintf(stderr, "Invalid commandline option.\n");
 			usage();
@@ -1847,7 +1860,7 @@ main(int argc, char **argv)
 	} else {	
 		FILE *pidfile;
 
-		daemon(0, 0);
+		r = daemon(0, 0);
 		loginit(PROGNAME, 0);
 
 		if ((pidfile = fopen(pidfile_path, "w")) == NULL) {
@@ -1924,7 +1937,7 @@ main(int argc, char **argv)
 				logit(LOG_ERR, "Exiting on pcap_dispatch: %s", 
 				    pcap_geterr(pcap));
 				break;
-			} else if (r == 0) {
+			} else if (r == 0 && capfile != NULL) {
 				logit(LOG_NOTICE, "Shutting down after "
 				    "pcap EOF");
 				graceful_shutdown_request = 1;

+ 14 - 3
softflowd.h

@@ -74,6 +74,13 @@ struct STATISTIC {
 #define TRACK_IP_ONLY		3	/* src/dst tuple */
 
 /*
+ * This structure contains optional information carried by Option Data
+ * Record.
+ */
+struct OPTION {
+	uint32_t sample;
+};
+/*
  * This structure is the root of the flow tracking system.
  * It holds the root of the tree of active flows and the head of the
  * tree of expiry events. It also collects miscellaneous statistics
@@ -106,6 +113,7 @@ struct FLOWTRACK {
 
 	/* Statistics */
 	u_int64_t total_packets;		/* # of good packets */
+	u_int64_t non_sampled_packets;		/* # of not sampled packets */
 	u_int64_t frag_packets;			/* # of fragmented packets */
 	u_int64_t non_ip_packets;		/* # of not-IP packets */
 	u_int64_t bad_packets;			/* # of bad packets */
@@ -135,6 +143,9 @@ struct FLOWTRACK {
 	u_int64_t expired_overbytes;
 	u_int64_t expired_maxflows;
 	u_int64_t expired_flush;
+
+	/* Optional information */
+	struct OPTION option;
 };
 
 /*
@@ -202,13 +213,13 @@ u_int32_t timeval_sub_ms(const struct timeval *t1, const struct timeval *t2);
 /* Prototypes for functions to send NetFlow packets, from netflow*.c */
 int send_netflow_v1(struct FLOW **flows, int num_flows, int nfsock,
     u_int16_t ifidx, u_int64_t *flows_exported, struct timeval *system_boot_time, 
-    int verbose_flag);
+    int verbose_flag, struct OPTION *option);
 int send_netflow_v5(struct FLOW **flows, int num_flows, int nfsock,
     u_int16_t ifidx, u_int64_t *flows_exported, struct timeval *system_boot_time,
-    int verbose_flag);
+    int verbose_flag, struct OPTION *option);
 int send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock,
     u_int16_t ifidx, u_int64_t *flows_exported, struct timeval *system_boot_time,
-    int verbose_flag);
+    int verbose_flag, struct OPTION *option);
 
 /* Force a resend of the flow template */
 void netflow9_resend_template(void);

+ 0 - 1
softflowd.init

@@ -1,7 +1,6 @@
 #!/bin/bash
 #
 # softflowd	Starts softflowd NetFlow probe
-# $Id$
 #
 # chkconfig: 2345 95 02
 # description: Starts and stops the softflowd Netflow probe

+ 1 - 3
softflowd.spec

@@ -1,11 +1,9 @@
-# $Id$
-
 # Figure out release tag (e.g. rhel3, fc1) based on redhat-release file
 %global _RHTAG %(sed 's/(.*)//;s/ [A-Z]* //;s/[a-z ]*//g' /etc/redhat-release | tr '[:upper:]' '[:lower:]')
 
 Name: softflowd
 Summary: Network traffic analyser capable of Cisco NetFlow data export
-Version: 0.9.8
+Version: 0.9.9
 Release: 1.%{_RHTAG}
 Source: softflowd-%{version}.tar.gz
 Group: System/Utilities

+ 0 - 2
strlcat.c

@@ -21,8 +21,6 @@
 #include "common.h"
 #ifndef HAVE_STRLCAT
 
-RCSID("$Id$");
-
 #if defined(LIBC_SCCS) && !defined(lint)
 static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $";
 #endif /* LIBC_SCCS and not lint */

+ 0 - 2
strlcpy.c

@@ -22,8 +22,6 @@
 
 #ifndef HAVE_STRLCPY
 
-RCSID("$Id$");
-
 #if defined(LIBC_SCCS) && !defined(lint)
 static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $";
 #endif /* LIBC_SCCS and not lint */

+ 0 - 2
treetype.h

@@ -22,8 +22,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id$ */
-
 /* Select our tree types for various data structures */
 
 #if defined(FLOW_RB)