Browse Source

Import upstream version 1.0.0

Hitoshi Irino 6 months ago
parent
commit
6945e52043
37 changed files with 8690 additions and 8572 deletions
  1. 0 2
      .cvsignore
  2. 0 4
      .hg_archival.txt
  3. 0 19
      .hgtags
  4. 19 0
      .travis.yml
  5. 2 0
      AUTHORS
  6. 1 0
      COPYING
  7. 1751 0
      ChangeLog
  8. 368 0
      INSTALL
  9. 17 0
      Makefile.am
  10. 0 58
      Makefile.in
  11. 30 0
      NEWS
  12. 20 4
      README
  13. 1152 1
      aclocal.m4
  14. 51 18
      common.h
  15. 0 169
      config.h.in
  16. 0 5673
      configure
  17. 46 5
      configure.ac
  18. 2 1
      freelist.c
  19. 462 205
      install-sh
  20. 981 0
      ipfix.c
  21. 141 0
      ipfix.h
  22. 144 20
      mkinstalldirs
  23. 122 111
      netflow1.c
  24. 179 120
      netflow5.c
  25. 362 333
      netflow9.c
  26. 54 0
      netflow9.h
  27. 232 0
      ntopng.c
  28. 171 0
      psamp.c
  29. 46 0
      psamp.h
  30. 4 1
      softflowctl.8
  31. 3 1
      softflowctl.c
  32. BIN
      softflowctl.pdf
  33. 52 6
      softflowd.8
  34. 2090 1708
      softflowd.c
  35. 187 112
      softflowd.h
  36. BIN
      softflowd.pdf
  37. 1 1
      softflowd.spec

+ 0 - 2
.cvsignore

@@ -1,2 +0,0 @@
-softflowd
-softflowctl

+ 0 - 4
.hg_archival.txt

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

+ 0 - 19
.hgtags

@@ -1,19 +0,0 @@
-0e7b1c83c22d691f0c2dc6a964d1334250f9be95 PRE_EXPIRY_RB_CONVERT
-0f4d543cfadd3f34162eb5e2785c057c548cfd22 SOFTFLOWD_0_3
-4680effcb255c612bc63f0ddedbea72f92151b59 SOFTFLOWD_0_9
-51c8e6737def4f6dd6de2692c98a8fda0d646a54 SOFTFLOWD_0_6
-7e447d5b8c8a7430bfaa234b45a06045b4ec04ba SOFTFLOWD_0_1
-7eaa764bbb3dbf71d5b329e61aed810bf7107f4a SOFTFLOWD_0_9_2
-8779cbdad42aaf29f981e2f9a7b617df8d2ac090 START
-9a9e2cd7e3b5dd05b63927acad9d0ca9bf39ce26 SOFTFLOWD_0_9_7
-9dae7a93ec5a71f921ea9ab8a46ad43942d28fc3 SOFTFLOWD_0_8
-b0c4bca0d46803f21e656a8c486e8a6ccb4fa676 SOFTFLOWD_0_2
-b7c24dd071091cbc74391e02799205c081edf8f1 SOFTFLOWD_0_8_1
-bcbc1910e8a68a3351d3bad37ca55558ff66d17c BEFORE_TREE_CHANGES
-bf9ccfda73346e315d37415d32a7c69653d4a245 SOFTFLOWD_0_5
-c025775ad959e68161ce6cf18a9ce9ffe35a92aa SOFTFLOWD_0_9_1
-ca5de0007bccbf42748d02630db01bb8a8961a92 SOFTFLOWD_0_7
-de48250d22aa20026d89fc715fff3bd27dcb0db1 PRE_BIDI
-eb6dc8d8b9c3166594cfa4bf5fd2c73c4a131820 SOFTFLOWD_0_7_1
-f81d538391377dc23346ddda4bd2fb0520daf6ea SOFTFLOWD_0_9_6
-ffda749c4623fcc78ea4a7ead6da6eeca64188aa SOFTFLOWD_0_9_8

+ 19 - 0
.travis.yml

@@ -0,0 +1,19 @@
+language: c
+
+os:
+  - linux
+  - osx
+
+compiler: gcc
+sudo: false
+addons:
+  apt:
+    packages:
+      libpcap-dev
+
+before_install:
+  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update         ; fi
+  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install libpcap; fi
+  
+before_script: autoreconf -if
+script: ./configure && make

+ 2 - 0
AUTHORS

@@ -0,0 +1,2 @@
+Original creator: Damien Miller <djm@mindrot.org>
+Current maintainer: Hitoshi Irino <irino@sfc.wide.ad.jp>

+ 1 - 0
COPYING

@@ -0,0 +1 @@
+LICENSE

File diff suppressed because it is too large
+ 1751 - 0
ChangeLog


+ 368 - 0
INSTALL

@@ -0,0 +1,368 @@
+Installation Instructions
+*************************
+
+   Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
+Foundation, Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell command './configure && make && make install'
+should configure, build, and install this package.  The following
+more-detailed instructions are generic; see the 'README' file for
+instructions specific to this package.  Some packages provide this
+'INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The 'configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a 'Makefile' in each directory of the package.
+It may also create one or more '.h' files containing system-dependent
+definitions.  Finally, it creates a shell script 'config.status' that
+you can run in the future to recreate the current configuration, and a
+file 'config.log' containing compiler output (useful mainly for
+debugging 'configure').
+
+   It can also use an optional file (typically called 'config.cache' and
+enabled with '--cache-file=config.cache' or simply '-C') that saves the
+results of its tests to speed up reconfiguring.  Caching is disabled by
+default to prevent problems with accidental use of stale cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how 'configure' could check whether to do them, and mail
+diffs or instructions to the address given in the 'README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point 'config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file 'configure.ac' (or 'configure.in') is used to create
+'configure' by a program called 'autoconf'.  You need 'configure.ac' if
+you want to change it or regenerate 'configure' using a newer version of
+'autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. 'cd' to the directory containing the package's source code and type
+     './configure' to configure the package for your system.
+
+     Running 'configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type 'make' to compile the package.
+
+  3. Optionally, type 'make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type 'make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the 'make install' phase executed with root
+     privileges.
+
+  5. Optionally, type 'make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior 'make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing 'make clean'.  To also remove the
+     files that 'configure' created (so you can compile the package for
+     a different kind of computer), type 'make distclean'.  There is
+     also a 'make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type 'make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide 'make
+     distcheck', which can by used by developers to test that all other
+     targets like 'make install' and 'make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the 'configure' script does not know about.  Run './configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give 'configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here is
+an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU 'make'.  'cd' to the
+directory where you want the object files and executables to go and run
+the 'configure' script.  'configure' automatically checks for the source
+code in the directory that 'configure' is in and in '..'.  This is known
+as a "VPATH" build.
+
+   With a non-GNU 'make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use 'make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple '-arch' options to the
+compiler but only a single '-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the 'lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, 'make install' installs the package's commands under
+'/usr/local/bin', include files under '/usr/local/include', etc.  You
+can specify an installation prefix other than '/usr/local' by giving
+'configure' the option '--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like '--bindir=DIR' to specify different values for particular
+kinds of files.  Run 'configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the default
+for these options is expressed in terms of '${prefix}', so that
+specifying just '--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to 'configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+'make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, 'make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+'${prefix}'.  Any directories that were specified during 'configure',
+but not in terms of '${prefix}', must each be overridden at install time
+for the entire installation to be relocated.  The approach of makefile
+variable overrides for each directory variable is required by the GNU
+Coding Standards, and ideally causes no recompilation.  However, some
+platforms have known limitations with the semantics of shared libraries
+that end up requiring recompilation when using this method, particularly
+noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the 'DESTDIR' variable.  For
+example, 'make install DESTDIR=/alternate/directory' will prepend
+'/alternate/directory' before all installation names.  The approach of
+'DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of '${prefix}'
+at 'configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving 'configure' the
+option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
+
+   Some packages pay attention to '--enable-FEATURE' options to
+'configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to '--with-PACKAGE' options, where PACKAGE
+is something like 'gnu-as' or 'x' (for the X Window System).  The
+'README' should mention any '--enable-' and '--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, 'configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the 'configure' options '--x-includes=DIR' and
+'--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of 'make' will be.  For these packages, running './configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with 'make V=1'; while running './configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with 'make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU CC
+is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   HP-UX 'make' updates targets which have the same time stamps as their
+prerequisites, which makes it generally unusable when shipped generated
+files such as 'configure' are involved.  Use GNU 'make' instead.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its '<wchar.h>' header file.  The option '-nodtk' can be used as a
+workaround.  If GNU CC is not installed, it is therefore recommended to
+try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put '/usr/ucb' early in your 'PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in '/usr/bin'.  So, if you need '/usr/ucb'
+in your 'PATH', put it _after_ '/usr/bin'.
+
+   On Haiku, software installed for all users goes in '/boot/common',
+not '/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features 'configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, 'configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+'--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as 'sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file 'config.sub' for the possible values of each field.  If
+'config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option '--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with '--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for 'configure' scripts to share,
+you can create a site shell script called 'config.site' that gives
+default values for variables like 'CC', 'cache_file', and 'prefix'.
+'configure' looks for 'PREFIX/share/config.site' if it exists, then
+'PREFIX/etc/config.site' if it exists.  Or, you can set the
+'CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all 'configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to 'configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the 'configure' command line, using 'VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified 'gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
+Autoconf limitation.  Until the limitation is lifted, you can use this
+workaround:
+
+     CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+'configure' Invocation
+======================
+
+   'configure' recognizes the following options to control how it
+operates.
+
+'--help'
+'-h'
+     Print a summary of all of the options to 'configure', and exit.
+
+'--help=short'
+'--help=recursive'
+     Print a summary of the options unique to this package's
+     'configure', and exit.  The 'short' variant lists options used only
+     in the top level, while the 'recursive' variant lists options also
+     present in any nested packages.
+
+'--version'
+'-V'
+     Print the version of Autoconf used to generate the 'configure'
+     script, and exit.
+
+'--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally 'config.cache'.  FILE defaults to '/dev/null' to
+     disable caching.
+
+'--config-cache'
+'-C'
+     Alias for '--cache-file=config.cache'.
+
+'--quiet'
+'--silent'
+'-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to '/dev/null' (any error
+     messages will still be shown).
+
+'--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     'configure' can determine that directory automatically.
+
+'--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names:: for
+     more details, including other options available for fine-tuning the
+     installation locations.
+
+'--no-create'
+'-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+'configure' also accepts some other, not widely useful, options.  Run
+'configure --help' for more details.

+ 17 - 0
Makefile.am

@@ -0,0 +1,17 @@
+bin_PROGRAMS = softflowd softflowctl
+COMMON = common.h convtime.h treetype.h sys-tree.h\
+  convtime.c strlcpy.c strlcat.c closefrom.c daemon.c
+if ENABLE_LEGACY
+  LEGACY_SOURCES = netflow9.c netflow1.c
+endif
+if ENABLE_NTOPNG
+  NTOPNG_SOURCES = ntopng.c
+endif
+softflowd_SOURCES = freelist.h log.h softflowd.h netflow9.h ipfix.h psamp.h\
+	freelist.c softflowd.c log.c netflow5.c ipfix.c psamp.c\
+  $(COMMON)
+EXTRA_softflowd_SOURCES = $(LEGACY_SOURCES) $(NTOPNG_SOURCES)
+softflowd_LDADD = $(LEGACY) $(NTOPNG)
+softflowd_DEPENDENCIES = $(LEGACY) $(NTOPNG)
+softflowctl_SOURCES = softflowctl.c $(COMMON)
+dist_man_MANS = softflowd.8 softflowctl.8

+ 0 - 58
Makefile.in

@@ -1,58 +0,0 @@
-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
-SOFTFLOWD=softflowd.o log.o netflow1.o netflow5.o netflow9.o freelist.o
-
-all: $(TARGETS)
-
-softflowd${EXEEXT}: ${SOFTFLOWD} $(COMMON)
-	$(CC) $(LDFLAGS) -o $@ ${SOFTFLOWD} $(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

+ 30 - 0
NEWS

@@ -0,0 +1,30 @@
+Fri Aug 16 2019
+Softflowd 1.0.0
+This release contains some new features.
+
+Details
+This release contains the following new features:
+Add support sending packet capture data using PSAMP format,
+Add function for sending to multiple destination with/without load-balance.
+Add function for injecting to ntopng directly.
+
+
+Mon Feb 13 2012
+Softflowd 0.9.9
+This release contains a number of bug fixes and some new features. It also welcomes Hitoshi Irino as a developer.
+
+Details
+This release contains the following new features:
+
+Add support for flow sampling, controlled by a new -s option (see softflowd(8) manpage for details)
+Add compile-time --chrootdir option to specify alternate chroot directory.
+Allow specification of input and output interface indices using a new -i option.
+Introduce a freelist allocator for expiry and flow objects, faster than malloc
+And the following bug fixes:
+
+Correctly exit from mainloop when a signal is received
+Fix logging from reduced-privileged child
+Many manpage typo, consistency and formatting fixes
+The softflow statistics command now displays the time at which softflowd was started
+Avoid spurious exit from mainloop while listening on "any" interface
+Correct broken IPv6 Netflow v.9 flows

+ 20 - 4
README

@@ -9,13 +9,18 @@ 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
+supplied PDF manpages. They were built with:
+
+man -t ./softflowd.8 | ps2pdf - softflowd.pdf
+man -t ./softflowctl.8 | ps2pdf - softflowctl.pdf
+
+You can view those pages 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). 
+softflowd's companion project "flowd" (http://www.mindrot.org/projects/flowd/). 
 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
@@ -28,6 +33,8 @@ Installing
 
 Building softflowd should be as simple as typing:
 
+autoconf
+autoreconf
 ./configure
 make
 make install
@@ -51,6 +58,10 @@ Todd C. Miller. Please refer to the LICENSE file for full details.
 Reporting Bugs
 --------------
 
+Please report bugs in softflowd (https://github.com/irino/softflowd/)
+to https://github.com/irino/softflowd/issues
+
+Following descriptions are historical information:
 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:
@@ -62,7 +73,12 @@ 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.
 
-The latest source code may be obtained from Google Code:
-http://code.google.com/p/softflowd/
+The latest source code may be obtained from Github:
+https://github.com/irino/softflowd/
+(This repository was forked from http://code.google.com/p/softflowd/)
 
+Original creator:
 Damien Miller <djm@mindrot.org>
+
+Current maintainer:
+Hitoshi Irino <irino@sfc.wide.ad.jp>

File diff suppressed because it is too large
+ 1152 - 1
aclocal.m4


+ 51 - 18
common.h

@@ -27,7 +27,8 @@
 
 #include "config.h"
 
-#define _BSD_SOURCE /* Needed for BSD-style struct ip,tcp,udp on Linux */
+#define _BSD_SOURCE             /* Needed for BSD-style struct ip,tcp,udp on Linux */
+#define _DEFAULT_SOURCE         /* It is recommended to use instead of _BSD_SOURCE on Linux */
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -45,6 +46,7 @@
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
 #include <arpa/inet.h>
+#include <net/ethernet.h>
 
 #include <unistd.h>
 #include <stdlib.h>
@@ -57,8 +59,10 @@
 #include <signal.h>
 #include <stdio.h>
 #include <string.h>
+#include <strings.h>
 #include <syslog.h>
 #include <time.h>
+#include <netdb.h>
 
 #if defined(HAVE_NET_BPF_H)
 #include <net/bpf.h>
@@ -69,11 +73,17 @@
 #include <inttypes.h>
 #endif
 
+#if defined(HAVE_SYS_ENDIAN_H)
+#include <sys/endian.h>
+#elif defined(HAVE_ENDIAN_H)
+#include <endian.h>
+#endif
+
 /* The name of the program */
 #define PROGNAME		"softflowd"
 
 /* The name of the program */
-#define PROGVER			"0.9.9"
+#define PROGVER			"1.0.0"
 
 /* Default pidfile */
 #define DEFAULT_PIDFILE		"/var/run/" PROGNAME ".pid"
@@ -86,7 +96,7 @@
 	    { (const char *)flowd_rcsid, "\100(#)" msg }	\
 
 #ifndef IP_OFFMASK
-# define IP_OFFMASK		0x1fff	/* mask for fragmenting bits */
+#define IP_OFFMASK		0x1fff  /* mask for fragmenting bits */
 #endif
 #ifndef IPV6_VERSION
 #define IPV6_VERSION		0x60
@@ -102,26 +112,26 @@
 #endif
 
 #ifndef _PATH_DEVNULL
-# define _PATH_DEVNULL		"/dev/null"
+#define _PATH_DEVNULL		"/dev/null"
 #endif
 
 #ifndef MIN
-# define MIN(a,b) (((a)<(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
 #endif
 #ifndef MAX
-# define MAX(a,b) (((a)>(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
 #endif
 #ifndef offsetof
-# define offsetof(type, member) ((size_t) &((type *)0)->member)
+#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
+#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)
@@ -150,20 +160,43 @@ typedef OUR_CFG_U_INT64_T u_int64_t;
 #endif
 
 #ifndef HAVE_STRLCPY
-size_t strlcpy(char *dst, const char *src, size_t siz);
+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);
+size_t strlcat (char *dst, const char *src, size_t siz);
 #endif
 #ifndef HAVE_CLOSEFROM
-void closefrom(int lowfd);
+void closefrom (int lowfd);
 #endif
 
 #ifndef HAVE_STRUCT_IP6_EXT
 struct ip6_ext {
-	u_int8_t ip6e_nxt;
-	u_int8_t ip6e_len;
+  u_int8_t ip6e_nxt;
+  u_int8_t ip6e_len;
 } __packed;
 #endif
 
+
+/* following lines are copy from unistd.h in Linux for avoidance warnings in compilation */
+#if defined(HAVE_SETRESGID) && !defined(_GNU_SOURCE)
+extern int setresgid (__uid_t __ruid, __uid_t __euid, __uid_t __suid);
+#endif
+#if defined(HAVE_SETRESUID) && !defined(_GNU_SOURCE)
+extern int setresuid (__uid_t __ruid, __uid_t __euid, __uid_t __suid);
+#endif
+
+#if defined (HAVE_DECL_HTONLL) && !defined (HAVE_DECL_HTOBE64)
+#define htobe64     htonll
+#endif
+
+#ifndef ETH_ALEN
+// https://cdn.kernel.org/pub/linux/kernel/people/marcelo/linux-2.4/include/linux/if_ether.h
+#define ETH_ALEN	6		/* Octets in one ethernet addr	 */
+#endif /* ETH_ALEN */
+
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#define htobe64(x) OSSwapHostToBigInt64(x)
+#endif /* __APPLE__ */
+
 #endif /* _SFD_COMMON_H */

+ 0 - 169
config.h.in

@@ -1,169 +0,0 @@
-/* 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
+ 0 - 5673
configure


+ 46 - 5
configure.ac

@@ -12,8 +12,9 @@
 # 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_INIT([softflowd], [1.0.0])
 AC_CONFIG_SRCDIR([softflowd.c])
+AM_INIT_AUTOMAKE
 
 AC_CONFIG_HEADER(config.h)
 AC_PROG_CC
@@ -31,6 +32,27 @@ 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_ENABLE(legacy,
+              AC_HELP_STRING([--enable-legacy],
+                             [enable legacy NetFlow implementation (default NO)]),
+              [legacy=yes],[legacy=no])
+AC_ARG_ENABLE(pthread,
+              AC_HELP_STRING([--enable-pthread], [enable pthread (default NO) (experimental, unstable)]),
+              [pthread=yes],[pthread=no])
+AC_ARG_ENABLE(ntopng,
+              AC_HELP_STRING([--enable-ntopng], [enable flow sending to ntopng with zeromq (default NO)]),
+              [ntopng=yes],[ntopng=no])
+AC_ARG_ENABLE(flow-spray,
+              AC_HELP_STRING([--enable-flow-spray],
+                             [enable spray as flow tree type(default is RB)]),
+              AC_DEFINE([FLOW_SPRAY], 1, [enable spray as flow tree type]),
+	      AC_DEFINE([FLOW_RB], 1, [enable RB(red-black) as flow tree type]))
+AC_ARG_ENABLE(expiry-spray,
+              AC_HELP_STRING([--enable-expiry-spray],
+                             [enable spray as expiry tree type (default is RB)]),
+              AC_DEFINE([EXPIRY_SPRAY], 1, [enable spray as flow tree type]),
+	      AC_DEFINE([EXPIRY_RB], 1, [enable RB(red-black) as flow tree type]))
+
 AC_ARG_WITH(cflags,
 	[  --with-cflags           Specify additional compiler flags],
 	[ if test "x$withval" != "xno" ; then CFLAGS="$CFLAGS $withval"; fi ]	
@@ -52,7 +74,8 @@ AC_ARG_WITH(chrootdir,
 	[ AC_DEFINE_UNQUOTED([PRIVDROP_CHROOT_DIR], ["${withval}"], [privdrop chroot directory]) ]	
 )
 
-AC_CHECK_HEADERS(net/bpf.h pcap.h pcap-bpf.h)
+AC_DEFINE([_BSD_SOURCE], [], [Define BSD SOURCE for Linux])
+AC_CHECK_HEADERS(net/bpf.h pcap.h pcap-bpf.h sys/endian.h endian.h)
 
 dnl AC_CHECK_HEADERS(netinet/in_systm.h netinet/tcp.h netinet/udp.h)
 dnl 
@@ -87,7 +110,8 @@ 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_FUNCS(closefrom daemon setresuid setreuid setresgid setgid strlcpy strlcat strsep)
+AC_CHECK_DECLS([htobe64, htonll])
 
 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])
@@ -97,6 +121,25 @@ AC_CHECK_SIZEOF(int, 4)
 AC_CHECK_SIZEOF(long int, 4)
 AC_CHECK_SIZEOF(long long int, 8)
 
+if test "x$legacy" = "xyes" ; then
+  AC_DEFINE([ENABLE_LEGACY], 1, [enable legacy NetFlow implementation])
+  LEGACY='netflow9.$(OBJEXT) netflow1.$(OBJEXT)'
+  AC_SUBST([LEGACY])
+fi
+AM_CONDITIONAL([ENABLE_LEGACY], [test x$legacy = xyes])
+if test "x$pthread" = "xyes" ; then
+  AC_DEFINE([ENABLE_PTHREAD], 1, [enable pthread])
+  AC_CHECK_LIB(pthread, pthread_create, [],[AC_MSG_ERROR([pthread.h not found])])
+  AC_CHECK_HEADERS(pthread.h, [],[AC_MSG_ERROR([pthread.h not found])])
+fi
+if test "x$ntopng" = "xyes" ; then
+  AC_DEFINE([ENABLE_NTOPNG], 1, [enable ntopng])
+   AC_CHECK_LIB(zmq, zmq_connect, [],[AC_MSG_ERROR([libzmq not found])])
+   AC_CHECK_HEADERS(zmq.h, [],[AC_MSG_ERROR([zmq.h not found])])
+  NTOPNG='ntopng.$(OBJEXT)'
+  AC_SUBST([NTOPNG])
+fi
+AM_CONDITIONAL([ENABLE_NTOPNG], [test x$ntopng = xyes])
 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
@@ -164,8 +207,6 @@ 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

+ 2 - 1
freelist.c

@@ -44,8 +44,9 @@
 void
 freelist_init(struct freelist *fl, size_t allocsz)
 {
+	size_t sizeof_fl = sizeof(fl);
 	FLOGIT((LOG_DEBUG, "%s: %s(%p, %zu)", __func__, __func__, fl, allocsz));
-	bzero(fl, sizeof(fl));
+	bzero(fl, sizeof_fl);
 	fl->allocsz = roundup(allocsz, FREELIST_ALLOC_ALIGN);
 	fl->free_entries = NULL;
 }

+ 462 - 205
install-sh

@@ -1,251 +1,508 @@
 #!/bin/sh
-#
 # install - install a program, script, or datafile
-# This comes from X11R5 (mit/util/scripts/install.sh).
+
+scriptversion=2014-09-12.12; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #
-# Copyright 1991 by the Massachusetts Institute of Technology
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
 #
-# 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.
+#
+# FSF changes to this file are in the public domain.
 #
 # Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
+# '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.
+# from scratch.
+
+tab='	'
+nl='
+'
+IFS=" $tab$nl"
 
+# Set DOITPROG to "echo" to test this script.
 
-# set DOITPROG to echo to test this script
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
 
-# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit="${DOITPROG-}"
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
 
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
 
-# put in absolute paths if you don't have them in your path; or use env. vars.
+posix_mkdir=
 
-mvprog="${MVPROG-mv}"
-cpprog="${CPPROG-cp}"
-chmodprog="${CHMODPROG-chmod}"
-chownprog="${CHOWNPROG-chown}"
-chgrpprog="${CHGRPPROG-chgrp}"
-stripprog="${STRIPPROG-strip}"
-rmprog="${RMPROG-rm}"
-mkdirprog="${MKDIRPROG-mkdir}"
+# Desired mode of installed file.
+mode=0755
 
-transformbasename=""
-transform_arg=""
-instcmd="$mvprog"
-chmodcmd="$chmodprog 0755"
-chowncmd=""
-chgrpcmd=""
-stripcmd=""
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
 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
+stripcmd=
 
-if [ x"$src" = x ]
-then
-	echo "install:	no input file specified"
-	exit 1
-else
-	true
-fi
+src=
+dst=
+dir_arg=
+dst_arg=
 
-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
+copy_on_change=false
+is_target_a_directory=possibly
 
-## this sed command emulates the dirname command
-dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
 
-# Make sure that the destination directory exists.
-#  this part is taken from Noah Friedman's mkinstalldirs script
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
 
-# Skip lots of stat calls in the usual case.
-if [ ! -d "$dstdir" ]; then
-defaultIFS='	
-'
-IFS="${IFS-${defaultIFS}}"
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
 
-oIFS="${IFS}"
-# Some sh's can't handle IFS=/ for some reason.
-IFS='%'
-set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
-IFS="${oIFS}"
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
 
-pathcomp=''
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
 
-while [ $# -ne 0 ] ; do
-	pathcomp="${pathcomp}${1}"
-	shift
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
 
-	if [ ! -d "${pathcomp}" ] ;
-	then
-		$mkdirprog "${pathcomp}"
-	else
-		true
-	fi
+    -C) copy_on_change=true;;
 
-	pathcomp="${pathcomp}/"
-done
-fi
+    -d) dir_arg=true;;
 
-if [ x"$dir_arg" != x ]
-then
-	$doit $instcmd $dst &&
+    -g) chgrpcmd="$chgrpprog $2"
+        shift;;
 
-	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
+    --help) echo "$usage"; exit $?;;
 
-# If we're going to rename the final executable, determine the name now.
+    -m) mode=$2
+        case $mode in
+          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+            echo "$0: invalid mode: $mode" >&2
+            exit 1;;
+        esac
+        shift;;
 
-	if [ x"$transformarg" = x ]
-	then
-		dstfile=`basename $dst`
-	else
-		dstfile=`basename $dst $transformbasename |
-			sed $transformarg`$transformbasename
-	fi
+    -o) chowncmd="$chownprog $2"
+        shift;;
 
-# don't allow the sed command to completely eliminate the filename
+    -s) stripcmd=$stripprog;;
 
-	if [ x"$dstfile" = x ]
-	then
-		dstfile=`basename $dst`
-	else
-		true
-	fi
+    -t)
+        is_target_a_directory=always
+        dst_arg=$2
+        # Protect names problematic for 'test' and other utilities.
+        case $dst_arg in
+          -* | [=\(\)!]) dst_arg=./$dst_arg;;
+        esac
+        shift;;
 
-# Make a temp file name in the proper directory.
+    -T) is_target_a_directory=never;;
 
-	dsttmp=$dstdir/#inst.$$#
+    --version) echo "$0 $scriptversion"; exit $?;;
 
-# Move or copy the file name to the temp name
+    --) shift
+        break;;
 
-	$doit $instcmd $src $dsttmp &&
+    -*) echo "$0: invalid option: $1" >&2
+        exit 1;;
 
-	trap "rm -f ${dsttmp}" 0 &&
+    *)  break;;
+  esac
+  shift
+done
 
-# and set any options; do chmod last to preserve setuid bits
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
 
-# 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 test -n "$dir_arg"; then
+  if test -n "$dst_arg"; then
+    echo "$0: target directory not allowed when installing a directory." >&2
+    exit 1
+  fi
+fi
 
-	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 &&
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for 'test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
 
-# Now rename the file to the real destination.
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call 'install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  if test $# -gt 1 || test "$is_target_a_directory" = always; then
+    if test ! -d "$dst_arg"; then
+      echo "$0: $dst_arg: Is not a directory." >&2
+      exit 1
+    fi
+  fi
+fi
 
-	$doit $rmcmd -f $dstdir/$dstfile &&
-	$doit $mvcmd $dsttmp $dstdir/$dstfile
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+        u_plus_rw=
+      else
+        u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+        u_plus_rw=
+      else
+        u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
 
-fi &&
+for src
+do
+  # Protect names problematic for 'test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test "$is_target_a_directory" = never; then
+        echo "$0: $dst_arg: Is a directory" >&2
+        exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      dstdir=`dirname "$dst"`
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+        # Create intermediate dirs using mode 755 as modified by the umask.
+        # This is like FreeBSD 'install' as of 1997-10-28.
+        umask=`umask`
+        case $stripcmd.$umask in
+          # Optimize common cases.
+          *[2367][2367]) mkdir_umask=$umask;;
+          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+          *[0-7])
+            mkdir_umask=`expr $umask + 22 \
+              - $umask % 100 % 40 + $umask % 20 \
+              - $umask % 10 % 4 + $umask % 2
+            `;;
+          *) mkdir_umask=$umask,go-w;;
+        esac
+
+        # With -d, create the new directory with the user-specified mode.
+        # Otherwise, rely on $mkdir_umask.
+        if test -n "$dir_arg"; then
+          mkdir_mode=-m$mode
+        else
+          mkdir_mode=
+        fi
+
+        posix_mkdir=false
+        case $umask in
+          *[123567][0-7][0-7])
+            # POSIX mkdir -p sets u+wx bits regardless of umask, which
+            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+            ;;
+          *)
+            # $RANDOM is not portable (e.g. dash);  use it when possible to
+            # lower collision chance
+            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+            trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+            # As "mkdir -p" follows symlinks and we work in /tmp possibly;  so
+            # create the $tmpdir first (and fail if unsuccessful) to make sure
+            # that nobody tries to guess the $tmpdir name.
+            if (umask $mkdir_umask &&
+                $mkdirprog $mkdir_mode "$tmpdir" &&
+                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+            then
+              if test -z "$dir_arg" || {
+                   # Check for POSIX incompatibilities with -m.
+                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                   # other-writable bit of parent directory when it shouldn't.
+                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                   test_tmpdir="$tmpdir/a"
+                   ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+                   case $ls_ld_tmpdir in
+                     d????-?r-*) different_mode=700;;
+                     d????-?--*) different_mode=755;;
+                     *) false;;
+                   esac &&
+                   $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+                     ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                   }
+                 }
+              then posix_mkdir=:
+              fi
+              rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+            else
+              # Remove any dirs left behind by ancient mkdir implementations.
+              rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+            fi
+            trap '' 0;;
+        esac;;
+    esac
 
+    if
+      $posix_mkdir && (
+        umask $mkdir_umask &&
+        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+        /*) prefix='/';;
+        [-=\(\)!]*) prefix='./';;
+        *)  prefix='';;
+      esac
+
+      oIFS=$IFS
+      IFS=/
+      set -f
+      set fnord $dstdir
+      shift
+      set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+        test X"$d" = X && continue
+
+        prefix=$prefix$d
+        if test -d "$prefix"; then
+          prefixes=
+        else
+          if $posix_mkdir; then
+            (umask=$mkdir_umask &&
+             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+            # Don't fail if two instances are running concurrently.
+            test -d "$prefix" || exit 1
+          else
+            case $prefix in
+              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+              *) qprefix=$prefix;;
+            esac
+            prefixes="$prefixes '$qprefix'"
+          fi
+        fi
+        prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+        # Don't fail if two instances are running concurrently.
+        (umask $mkdir_umask &&
+         eval "\$doit_exec \$mkdirprog $prefixes") ||
+          test -d "$dstdir" || exit 1
+        obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # 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 $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
+       set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       set +f &&
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+        # Now remove or move aside any old file at destination location.
+        # We try this two ways since rm can't unlink itself on some
+        # systems and the destination file might be busy for other
+        # reasons.  In this case, the final cleanup might fail but the new
+        # file should still install successfully.
+        {
+          test ! -f "$dst" ||
+          $doit $rmcmd -f "$dst" 2>/dev/null ||
+          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+          } ||
+          { echo "$0: cannot unlink or rename $dst" >&2
+            (exit 1); exit 1
+          }
+        } &&
+
+        # Now rename the file to the real destination.
+        $doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
 
-exit 0
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:

+ 981 - 0
ipfix.c

@@ -0,0 +1,981 @@
+/*
+ * Copyright 2002 Damien Miller <djm@mindrot.org> All rights reserved.
+ * Copyright 2012 Hitoshi Irino <irino@sfc.wide.ad.jp> 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 "log.h"
+#include "treetype.h"
+#include "softflowd.h"
+#include "netflow9.h"
+#include "ipfix.h"
+#include "psamp.h"
+
+const struct IPFIX_FIELD_SPECIFIER field_v4[] = {
+  {IPFIX_sourceIPv4Address, 4},
+  {IPFIX_destinationIPv4Address, 4}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_v6[] = {
+  {IPFIX_sourceIPv6Address, 16},
+  {IPFIX_destinationIPv6Address, 16}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_common[] = {
+  {IPFIX_octetDeltaCount, 4},
+  {IPFIX_packetDeltaCount, 4},
+  {IPFIX_ingressInterface, 4},
+  {IPFIX_egressInterface, 4}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_transport[] = {
+  {IPFIX_sourceTransportPort, 2},
+  {IPFIX_destinationTransportPort, 2},
+  {IPFIX_protocolIdentifier, 1},
+  {IPFIX_tcpControlBits, 1},
+  {IPFIX_ipVersion, 1},
+  {IPFIX_ipClassOfService, 1}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_icmp4[] = {
+  {IPFIX_icmpTypeCodeIPv4, 2},
+  {IPFIX_ipVersion, 1},
+  {IPFIX_ipClassOfService, 1}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_icmp6[] = {
+  {IPFIX_icmpTypeCodeIPv6, 2},
+  {IPFIX_ipVersion, 1},
+  {IPFIX_ipClassOfService, 1}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_vlan[] = {
+  {IPFIX_vlanId, 2},
+  {IPFIX_postVlanId, 2}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_ether[] = {
+  {IPFIX_sourceMacAddress, 6},
+  {IPFIX_postDestinationMacAddress, 6}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_timesec[] = {
+  {IPFIX_flowStartSeconds, 4},
+  {IPFIX_flowEndSeconds, 4}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_timemsec[] = {
+  {IPFIX_flowStartMilliSeconds, 8},
+  {IPFIX_flowEndMilliSeconds, 8}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_timeusec[] = {
+  {IPFIX_flowStartMicroSeconds, 8},
+  {IPFIX_flowEndMicroSeconds, 8}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_timensec[] = {
+  {IPFIX_flowStartNanoSeconds, 8},
+  {IPFIX_flowEndNanoSeconds, 8}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_timesysup[] = {
+  {IPFIX_flowStartSysUpTime, 4},
+  {IPFIX_flowEndSysUpTime, 4}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_bicommon[] = {
+  {IPFIX_octetDeltaCount, 4},
+  {IPFIX_packetDeltaCount, 4},
+  {IPFIX_ipClassOfService, 1}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_bitransport[] =
+  { {IPFIX_tcpControlBits, 1} };
+
+const struct IPFIX_FIELD_SPECIFIER field_biicmp4[] =
+  { {IPFIX_icmpTypeCodeIPv4, 2} };
+
+const struct IPFIX_FIELD_SPECIFIER field_biicmp6[] =
+  { {IPFIX_icmpTypeCodeIPv6, 2} };
+
+const struct IPFIX_FIELD_SPECIFIER field_scope[] =
+  { {IPFIX_meteringProcessId, 4} };
+
+const struct IPFIX_FIELD_SPECIFIER field_option[] = {
+  {IPFIX_systemInitTimeMilliseconds, 8},
+  {PSAMP_samplingPacketInterval, 4},
+  {PSAMP_samplingPacketSpace, 4},
+  {PSAMP_selectorAlgorithm, 2}
+};
+
+const struct IPFIX_FIELD_SPECIFIER field_nf9scope[] =
+  { {NFLOW9_OPTION_SCOPE_INTERFACE, 4} };
+
+const struct IPFIX_FIELD_SPECIFIER field_nf9option[] = {
+  {NFLOW9_SAMPLING_INTERVAL, 4},
+  {NFLOW9_SAMPLING_ALGORITHM, 1}
+};
+
+/* Stuff pertaining to the templates that softflowd uses */
+#define IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS          \
+    sizeof(field_v4) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS        \
+    sizeof(field_timesysup) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS      \
+    sizeof(field_common) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS   \
+    sizeof(field_transport) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS        \
+    sizeof(field_icmp4) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS        \
+    sizeof(field_vlan) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS       \
+    sizeof(field_ether) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS    \
+    sizeof(field_bicommon) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS \
+    sizeof(field_bitransport) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS      \
+    sizeof(field_biicmp4) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+
+#define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS       \
+    IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS +        \
+    IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS +      \
+    IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS +    \
+    IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS + \
+    IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS +      \
+    IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS
+
+#define IPFIX_SOFTFLOWD_TEMPLATE_BI_NRECORDS    \
+    IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS +  \
+    IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS
+
+struct IPFIX_SOFTFLOWD_TEMPLATE {
+  struct IPFIX_TEMPLATE_SET_HEADER h;
+  struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS];
+  struct IPFIX_VENDOR_FIELD_SPECIFIER
+    v[IPFIX_SOFTFLOWD_TEMPLATE_BI_NRECORDS];
+  u_int16_t data_len, bi_count;
+} __packed;
+
+#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS   \
+    sizeof(field_scope) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS        \
+    sizeof(field_option) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+
+#define NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS  \
+    sizeof(field_nf9scope) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+#define NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS       \
+    sizeof(field_nf9option) / sizeof(struct IPFIX_FIELD_SPECIFIER)
+
+struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE {
+  struct IPFIX_OPTION_TEMPLATE_SET_HEADER h;
+  struct IPFIX_FIELD_SPECIFIER
+    s[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS];
+  struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS];
+} __packed;
+
+/* softflowd data set */
+struct IPFIX_SOFTFLOWD_DATA_COMMON {
+  u_int32_t octetDeltaCount, packetDeltaCount;
+  u_int32_t ingressInterface, egressInterface;
+} __packed;
+
+struct IPFIX_SOFTFLOWD_DATA_TRANSPORT {
+  u_int16_t sourceTransportPort, destinationTransportPort;
+  u_int8_t protocolIdentifier, tcpControlBits, ipVersion, ipClassOfService;
+} __packed;
+
+struct IPFIX_SOFTFLOWD_DATA_ICMP {
+  u_int16_t icmpTypeCode;
+  u_int8_t ipVersion, ipClassOfService;
+} __packed;
+
+struct IPFIX_SOFTFLOWD_DATA_VLAN {
+  u_int16_t vlanId, postVlanId;
+} __packed;
+
+struct IPFIX_SOFTFLOWD_DATA_ETHER {
+  u_int8_t sourceMacAddress[6], destinationMacAddress[6];
+} __packed;
+
+struct IPFIX_SOFTFLOWD_DATA_BICOMMON {
+  u_int32_t octetDeltaCount, packetDeltaCount;
+  u_int8_t ipClassOfService;
+} __packed;
+
+struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT {
+  u_int8_t tcpControlBits;
+} __packed;
+
+struct IPFIX_SOFTFLOWD_DATA_BIICMP {
+  u_int16_t icmpTypeCode;
+} __packed;
+
+union IPFIX_SOFTFLOWD_DATA_TIME {
+  struct {
+    u_int32_t start;
+    u_int32_t end;
+  } u32;
+  struct {
+    u_int64_t start;
+    u_int64_t end;
+  } u64;
+};
+
+struct IPFIX_SOFTFLOWD_DATA_V4ADDR {
+  u_int32_t sourceIPv4Address, destinationIPv4Address;
+} __packed;
+
+struct IPFIX_SOFTFLOWD_DATA_V6ADDR {
+  struct in6_addr sourceIPv6Address, destinationIPv6Address;
+} __packed;
+
+struct IPFIX_SOFTFLOWD_OPTION_DATA {
+  struct IPFIX_SET_HEADER c;
+  u_int32_t scope_pid;
+  u_int64_t systemInitTimeMilliseconds;
+  u_int32_t samplingInterval;
+  u_int32_t samplingSpace;
+  u_int16_t samplingAlgorithm;
+} __packed;
+
+struct NFLOW9_SOFTFLOWD_OPTION_DATA {
+  struct IPFIX_SET_HEADER c;
+  u_int32_t scope_ifidx;
+  u_int32_t samplingInterval;
+  u_int8_t samplingAlgorithm;
+} __packed;
+
+/* Local data: templates and counters */
+#define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE     1428
+#define IPFIX_SOFTFLOWD_V4_TEMPLATE_ID      1024
+#define IPFIX_SOFTFLOWD_ICMPV4_TEMPLATE_ID  1025
+#define IPFIX_SOFTFLOWD_V6_TEMPLATE_ID      2048
+#define IPFIX_SOFTFLOWD_ICMPV6_TEMPLATE_ID  2049
+#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID  256
+
+#define IPFIX_DEFAULT_TEMPLATE_INTERVAL 16
+
+/* ... */
+#define IPFIX_OPTION_SCOPE_SYSTEM               1
+#define IPFIX_OPTION_SCOPE_INTERFACE            2
+#define IPFIX_OPTION_SCOPE_LINECARD             3
+#define IPFIX_OPTION_SCOPE_CACHE                4
+#define IPFIX_OPTION_SCOPE_TEMPLATE             5
+/* ... */
+#define IPFIX_SAMPLING_ALGORITHM_DETERMINISTIC  1
+#define IPFIX_SAMPLING_ALGORITHM_RANDOM         2
+/* ... */
+
+// prototype
+void memcpy_template (u_char * packet, u_int * offset,
+                      struct IPFIX_SOFTFLOWD_TEMPLATE *template,
+                      u_int8_t bi_flag);
+
+// variables
+enum { TMPLV4, TMPLICMPV4, TMPLV6, TMPLICMPV6, TMPLMAX };
+static struct IPFIX_SOFTFLOWD_TEMPLATE templates[TMPLMAX];
+static struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE option_template;
+static struct IPFIX_SOFTFLOWD_OPTION_DATA option_data;
+static struct NFLOW9_SOFTFLOWD_OPTION_DATA nf9opt_data;
+
+static int ipfix_pkts_until_template = -1;
+
+int
+ipfix_init_fields (struct IPFIX_FIELD_SPECIFIER *dst,
+                   u_int * index,
+                   const struct IPFIX_FIELD_SPECIFIER *src,
+                   u_int field_number) {
+  int i, length = 0;
+  for (i = 0; i < field_number; i++) {
+    dst[*index + i].ie = htons (src[i].ie);
+    dst[*index + i].length = htons (src[i].length);
+    length += src[i].length;
+  }
+  *index += field_number;
+  return length;
+}
+
+void
+conv_unix_to_ntp (struct timeval tv, struct ntp_time_t *ntp) {
+  if (ntp != NULL) {
+    ntp->second = tv.tv_sec + 0x83AA7E80;
+    ntp->fraction =
+      (uint32_t) ((double) (tv.tv_usec + 1) * (double) (1LL << 32) * 1.0e-6);
+  }
+}
+
+struct timeval
+conv_ntp_to_unix (struct ntp_time_t ntp) {
+  struct timeval tv = {
+    ntp.second - 0x83AA7E80,    // the seconds from Jan 1, 1900 to Jan 1, 1970
+    (uint32_t) ((double) ntp.fraction * 1.0e6 / (double) (1LL << 32))
+  };
+  return tv;
+}
+
+static int
+ipfix_init_bifields (struct IPFIX_SOFTFLOWD_TEMPLATE *template,
+                     u_int * index,
+                     const struct IPFIX_FIELD_SPECIFIER *fields,
+                     u_int field_number) {
+  int i, length = 0;
+  for (i = 0; i < field_number; i++) {
+    template->v[*index + i].ie = htons (fields[i].ie | 0x8000);
+    template->v[*index + i].length = htons (fields[i].length);
+    template->v[*index + i].pen = htonl (REVERSE_PEN);
+    length += fields[i].length;
+  }
+  *index += field_number;
+  return length;
+}
+
+static int
+ipfix_init_template_time (struct FLOWTRACKPARAMETERS *param,
+                          struct IPFIX_SOFTFLOWD_TEMPLATE *template,
+                          u_int * index) {
+  int length = 0;
+  if (param->time_format == 's') {
+    length = ipfix_init_fields (template->r, index,
+                                field_timesec,
+                                IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
+  } else if (param->time_format == 'm') {
+    length = ipfix_init_fields (template->r, index,
+                                field_timemsec,
+                                IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
+  } else if (param->time_format == 'M') {
+    length = ipfix_init_fields (template->r, index,
+                                field_timeusec,
+                                IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
+  } else if (param->time_format == 'n') {
+    length = ipfix_init_fields (template->r, index,
+                                field_timensec,
+                                IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
+  } else {
+    length = ipfix_init_fields (template->r, index,
+                                field_timesysup,
+                                IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
+  }
+  return length;
+}
+
+static void
+ipfix_init_template_unity (struct FLOWTRACKPARAMETERS *param,
+                           struct IPFIX_SOFTFLOWD_TEMPLATE *template,
+                           u_int template_id, u_int8_t v6_flag,
+                           u_int8_t icmp_flag, u_int8_t bi_flag,
+                           u_int16_t version) {
+  u_int index = 0, bi_index = 0, length = 0;
+  bzero (template, sizeof (*template));
+  template->h.c.set_id = htons (version == 10 ?
+                                IPFIX_TEMPLATE_SET_ID :
+                                NFLOW9_TEMPLATE_SET_ID);
+  template->h.r.template_id = htons (template_id);
+  if (v6_flag) {
+    length += ipfix_init_fields (template->r, &index,
+                                 field_v6,
+                                 IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS);
+  } else {
+    length += ipfix_init_fields (template->r, &index,
+                                 field_v4,
+                                 IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS);
+  }
+  length += ipfix_init_template_time (param, template, &index);
+  length += ipfix_init_fields (template->r, &index,
+                               field_common,
+                               IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS);
+  if (icmp_flag) {
+    if (v6_flag) {
+      length += ipfix_init_fields (template->r, &index,
+                                   field_icmp6,
+                                   IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS);
+    } else {
+      length += ipfix_init_fields (template->r, &index,
+                                   field_icmp4,
+                                   IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS);
+    }
+  } else {
+    length += ipfix_init_fields (template->r, &index,
+                                 field_transport,
+                                 IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS);
+  }
+  if (param->track_level >= TRACK_FULL_VLAN) {
+    length += ipfix_init_fields (template->r, &index,
+                                 field_vlan,
+                                 IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS);
+  }
+  if (param->track_level >= TRACK_FULL_VLAN_ETHER) {
+    length += ipfix_init_fields (template->r, &index,
+                                 field_ether,
+                                 IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS);
+  }
+  if (bi_flag) {
+    length +=
+      ipfix_init_bifields (template, &bi_index,
+                           field_bicommon,
+                           IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS);
+    if (icmp_flag) {
+      if (v6_flag) {
+        length +=
+          ipfix_init_bifields (template, &bi_index,
+                               field_biicmp6,
+                               IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS);
+      } else {
+        length +=
+          ipfix_init_bifields (template, &bi_index,
+                               field_biicmp4,
+                               IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS);
+      }
+    } else {
+      length +=
+        ipfix_init_bifields (template, &bi_index,
+                             field_bitransport,
+                             IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS);
+
+    }
+  }
+  template->bi_count = bi_index;
+  template->h.r.count = htons (index + bi_index);
+  template->h.c.length =
+    htons (sizeof (struct IPFIX_TEMPLATE_SET_HEADER) +
+           index * sizeof (struct IPFIX_FIELD_SPECIFIER) +
+           bi_index * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER));
+  template->data_len = length;
+}
+
+static void
+ipfix_init_template (struct FLOWTRACKPARAMETERS *param,
+                     u_int8_t bi_flag, u_int16_t version) {
+  u_int8_t v6_flag = 0, icmp_flag = 0;
+  u_int16_t template_id = 0;
+  int i = 0;
+  for (i = 0; i < TMPLMAX; i++) {
+    switch (i) {
+    case TMPLV4:
+      v6_flag = 0;
+      icmp_flag = 0;
+      template_id = IPFIX_SOFTFLOWD_V4_TEMPLATE_ID;
+      break;
+    case TMPLICMPV4:
+      v6_flag = 0;
+      icmp_flag = 1;
+      template_id = IPFIX_SOFTFLOWD_ICMPV4_TEMPLATE_ID;
+      break;
+    case TMPLV6:
+      v6_flag = 1;
+      icmp_flag = 0;
+      template_id = IPFIX_SOFTFLOWD_V6_TEMPLATE_ID;
+      break;
+    case TMPLICMPV6:
+      v6_flag = 1;
+      icmp_flag = 1;
+      template_id = IPFIX_SOFTFLOWD_ICMPV6_TEMPLATE_ID;
+      break;
+    }
+    ipfix_init_template_unity (param, &templates[i],
+                               template_id, v6_flag,
+                               icmp_flag, bi_flag, version);
+  }
+}
+
+static void
+nflow9_init_option (u_int16_t ifidx, struct OPTION *option) {
+  u_int scope_index = 0, option_index = 0;
+  u_int16_t scope_len =
+    NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS *
+    sizeof (struct IPFIX_FIELD_SPECIFIER);
+  u_int16_t opt_len =
+    NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS *
+    sizeof (struct IPFIX_FIELD_SPECIFIER);
+
+  bzero (&option_template, sizeof (option_template));
+  option_template.h.c.set_id = htons (NFLOW9_OPTION_TEMPLATE_SET_ID);
+  option_template.h.c.length =
+    htons (sizeof (option_template.h) + scope_len + opt_len);
+  option_template.h.u.n.template_id =
+    htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
+  option_template.h.u.n.scope_length = htons (scope_len);
+  option_template.h.u.n.option_length = htons (opt_len);
+  ipfix_init_fields (option_template.s, &scope_index,
+                     field_nf9scope,
+                     NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS);
+  ipfix_init_fields (option_template.r, &option_index,
+                     field_nf9option,
+                     NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
+  bzero (&nf9opt_data, sizeof (nf9opt_data));
+  nf9opt_data.c.set_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
+  nf9opt_data.c.length = htons (sizeof (nf9opt_data));
+  nf9opt_data.scope_ifidx = htonl (ifidx);
+  nf9opt_data.samplingInterval =
+    htonl (option->sample > 1 ? option->sample : 1);
+  nf9opt_data.samplingAlgorithm = NFLOW9_SAMPLING_ALGORITHM_DETERMINISTIC;
+}
+
+static void
+ipfix_init_option (struct timeval *system_boot_time, struct OPTION *option) {
+  u_int scope_index = 0, option_index = 0;
+  bzero (&option_template, sizeof (option_template));
+  option_template.h.c.set_id = htons (IPFIX_OPTION_TEMPLATE_SET_ID);
+  option_template.h.c.length = htons (sizeof (option_template));
+  option_template.h.u.i.r.template_id =
+    htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
+  option_template.h.u.i.r.count =
+    htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS +
+           IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
+  option_template.h.u.i.scope_count =
+    htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS);
+
+  ipfix_init_fields (option_template.s, &scope_index,
+                     field_scope,
+                     IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS);
+  ipfix_init_fields (option_template.r, &option_index, field_option,
+                     IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
+
+  bzero (&option_data, sizeof (option_data));
+  option_data.c.set_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
+  option_data.c.length = htons (sizeof (option_data));
+  option_data.scope_pid = htonl ((u_int32_t) option->meteringProcessId);
+#if defined(htobe64) || defined(HAVE_DECL_HTOBE64)
+  option_data.systemInitTimeMilliseconds =
+    htobe64 ((u_int64_t) system_boot_time->tv_sec * 1000 +
+             (u_int64_t) system_boot_time->tv_usec / 1000);
+#endif
+  option_data.samplingAlgorithm = htons (PSAMP_selectorAlgorithm_count);
+  option_data.samplingInterval = htonl (1);
+  option_data.samplingSpace =
+    htonl (option->sample > 0 ? option->sample - 1 : 0);
+}
+
+static int
+copy_data_time (union IPFIX_SOFTFLOWD_DATA_TIME *dt,
+                const struct FLOW *flow,
+                const struct timeval *system_boot_time,
+                struct FLOWTRACKPARAMETERS *param) {
+  int length = (param->time_format == 'm' || param->time_format == 'M'
+                || param->time_format == 'n') ? 16 : 8;
+  if (dt == NULL)
+    return -1;
+
+  switch (param->time_format) {
+    struct ntp_time_t ntptime;
+  case 's':
+    dt->u32.start = htonl (flow->flow_start.tv_sec);
+    dt->u32.end = htonl (flow->flow_last.tv_sec);
+    break;
+#if defined(htobe64) || defined(HAVE_DECL_HTOBE64)
+  case 'm':
+    dt->u64.start =
+      htobe64 ((u_int64_t) flow->flow_start.tv_sec * 1000 +
+               (u_int64_t) flow->flow_start.tv_usec / 1000);
+    dt->u64.end =
+      htobe64 ((u_int64_t) flow->flow_last.tv_sec * 1000 +
+               (u_int64_t) flow->flow_last.tv_usec / 1000);
+    break;
+  case 'M':
+  case 'n':
+    conv_unix_to_ntp ((struct timeval) flow->flow_start, &ntptime);
+    dt->u64.start =
+      htobe64 ((u_int64_t) ntptime.second << 32 | ntptime.fraction);
+    conv_unix_to_ntp ((struct timeval) flow->flow_last, &ntptime);
+    dt->u64.end =
+      htobe64 ((u_int64_t) ntptime.second << 32 | ntptime.fraction);
+    break;
+#endif
+  default:
+    dt->u32.start =
+      htonl (timeval_sub_ms (&flow->flow_start, system_boot_time));
+    dt->u32.end = htonl (timeval_sub_ms (&flow->flow_last, system_boot_time));
+    break;
+  }
+  return length;
+}
+
+static u_int
+ipfix_flow_to_template_index (const struct FLOW *flow) {
+  u_int index = 0;
+  if (flow->af == AF_INET) {
+    index = (flow->protocol == IPPROTO_ICMP) ? TMPLICMPV4 : TMPLV4;
+  } else if (flow->af == AF_INET6) {
+    index = (flow->protocol == IPPROTO_ICMPV6) ? TMPLICMPV6 : TMPLV6;
+  }
+  return index;
+}
+
+static int
+ipfix_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,
+                       struct FLOWTRACKPARAMETERS *param, u_int8_t bi_flag) {
+  struct IPFIX_SOFTFLOWD_DATA_V4ADDR *d4[2] = { NULL, NULL };
+  struct IPFIX_SOFTFLOWD_DATA_V6ADDR *d6[2] = { NULL, NULL };
+  union IPFIX_SOFTFLOWD_DATA_TIME *dt[2] = { NULL, NULL };
+  struct IPFIX_SOFTFLOWD_DATA_COMMON *dc[2] = { NULL, NULL };
+  struct IPFIX_SOFTFLOWD_DATA_TRANSPORT *dtr[2] = { NULL, NULL };
+  struct IPFIX_SOFTFLOWD_DATA_ICMP *di[2] = { NULL, NULL };
+  struct IPFIX_SOFTFLOWD_DATA_VLAN *dv[2] = { NULL, NULL };
+  struct IPFIX_SOFTFLOWD_DATA_ETHER *de[2] = { NULL, NULL };
+  struct IPFIX_SOFTFLOWD_DATA_BICOMMON *dbc = NULL;
+  struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *dbtr = NULL;
+  struct IPFIX_SOFTFLOWD_DATA_BIICMP *dbi = NULL;
+
+  u_int freclen = 0, nflows = 0, offset = 0;
+  u_int frecnum = bi_flag ? 1 : 2;
+  u_int tmplindex = ipfix_flow_to_template_index (flow);
+  int i = 0;
+  freclen = templates[tmplindex].data_len;
+  if (len < freclen * frecnum)
+    return (-1);
+
+  for (i = 0; i < frecnum; i++) {
+    if (bi_flag == 0 && flow->octets[i] == 0)
+      continue;
+    nflows++;
+    if (flow->af == AF_INET) {
+      d4[i] = (struct IPFIX_SOFTFLOWD_DATA_V4ADDR *) &packet[offset];
+      memcpy (&d4[i]->sourceIPv4Address, &flow->addr[i].v4, 4);
+      memcpy (&d4[i]->destinationIPv4Address, &flow->addr[i ^ 1].v4, 4);
+      offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_V4ADDR);
+    } else if (flow->af == AF_INET6) {
+      d6[i] = (struct IPFIX_SOFTFLOWD_DATA_V6ADDR *) &packet[offset];
+      memcpy (&d6[i]->sourceIPv6Address, &flow->addr[i].v6, 16);
+      memcpy (&d6[i]->destinationIPv6Address, &flow->addr[i ^ 1].v6, 16);
+      offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_V6ADDR);
+    }
+
+    dt[i] = (union IPFIX_SOFTFLOWD_DATA_TIME *) &packet[offset];
+    offset += copy_data_time (dt[i], flow, system_boot_time, param);
+
+    dc[i] = (struct IPFIX_SOFTFLOWD_DATA_COMMON *) &packet[offset];
+    dc[i]->octetDeltaCount = htonl (flow->octets[i]);
+    dc[i]->packetDeltaCount = htonl (flow->packets[i]);
+    dc[i]->ingressInterface = dc[i]->egressInterface = htonl (ifidx);
+    offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_COMMON);
+
+    if (flow->protocol != IPPROTO_ICMP && flow->protocol != IPPROTO_ICMPV6) {
+      dtr[i] = (struct IPFIX_SOFTFLOWD_DATA_TRANSPORT *) &packet[offset];
+      dtr[i]->sourceTransportPort = flow->port[i];
+      dtr[i]->destinationTransportPort = flow->port[i ^ 1];
+      dtr[i]->protocolIdentifier = flow->protocol;
+      dtr[i]->tcpControlBits = flow->tcp_flags[i];
+      dtr[i]->ipClassOfService = flow->tos[i];
+      dtr[i]->ipVersion = (flow->af == AF_INET) ? 4 : 6;
+      offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_TRANSPORT);
+    } else {
+      di[i] = (struct IPFIX_SOFTFLOWD_DATA_ICMP *) &packet[offset];
+      di[i]->icmpTypeCode = flow->port[i ^ 1];
+      di[i]->ipClassOfService = flow->tos[i];
+      di[i]->ipVersion = (flow->af == AF_INET) ? 4 : 6;
+      offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_ICMP);
+    }
+    if (param->track_level >= TRACK_FULL_VLAN) {
+      dv[i] = (struct IPFIX_SOFTFLOWD_DATA_VLAN *) &packet[offset];
+      dv[i]->vlanId = flow->vlanid[i];
+      dv[i]->postVlanId = flow->vlanid[i ^ 1];
+      offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_VLAN);
+    }
+    if (param->track_level >= TRACK_FULL_VLAN_ETHER) {
+      de[i] = (struct IPFIX_SOFTFLOWD_DATA_ETHER *) &packet[offset];
+      memcpy (&de[i]->sourceMacAddress, &flow->ethermac[i], 6);
+      memcpy (&de[i]->destinationMacAddress, &flow->ethermac[i ^ 1], 6);
+      offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_ETHER);
+    }
+    if (bi_flag && i == 0) {
+      dbc = (struct IPFIX_SOFTFLOWD_DATA_BICOMMON *) &packet[offset];
+      dbc->octetDeltaCount = htonl (flow->octets[1]);
+      dbc->packetDeltaCount = htonl (flow->packets[1]);
+      dbc->ipClassOfService = flow->tos[1];
+      offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BICOMMON);
+      if (flow->protocol != IPPROTO_ICMP && flow->protocol != IPPROTO_ICMPV6) {
+        dbtr = (struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *)
+          &packet[offset];
+        dbtr->tcpControlBits = flow->tcp_flags[1];
+        offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT);
+      } else {
+        dbi = (struct IPFIX_SOFTFLOWD_DATA_BIICMP *)
+          &packet[offset];
+        dbi->icmpTypeCode = flow->port[1];
+        offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BIICMP);
+      }
+    }
+  }
+  *len_used = offset;
+  return (nflows);
+}
+
+static int
+valuate_icmp (struct FLOW *flow) {
+  if (flow == NULL)
+    return -1;
+  if (flow->af == AF_INET)
+    if (flow->protocol == IPPROTO_ICMP)
+      return 1;
+    else
+      return 0;
+  else if (flow->af == AF_INET6)
+    if (flow->protocol == IPPROTO_ICMPV6)
+      return 1;
+    else
+      return 0;
+  else
+    return -1;
+  return -1;
+}
+
+void
+ipfix_resend_template (void) {
+  if (ipfix_pkts_until_template > 0)
+    ipfix_pkts_until_template = 0;
+}
+
+void
+memcpy_template (u_char * packet, u_int * offset,
+                 struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int8_t bi_flag) 
+{
+  int size = ntohs (template->h.c.length) -
+    template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER);
+  memcpy (packet + *offset, template, size);
+  *offset += size;
+  if (bi_flag) {
+    size = template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER);
+    memcpy (packet + *offset, template->v, size);
+    *offset += size;
+  }
+}
+
+/*
+ * Given an array of expired flows, send ipfix report packets
+ * Returns number of packets sent or -1 on error
+ */
+static int
+send_ipfix_common (struct FLOW **flows, int num_flows,
+                   struct NETFLOW_TARGET *target,
+                   u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
+                   int verbose_flag, u_int8_t bi_flag, u_int16_t version) {
+  struct IPFIX_HEADER *ipfix;
+  struct NFLOW9_HEADER *nf9;
+  struct IPFIX_SET_HEADER *dh;
+  struct timeval now;
+  u_int offset, last_af, i, j, num_packets, inc, last_valid, tmplindex;
+  int8_t icmp_flag, last_icmp_flag;
+  int r;
+  u_int records;
+  u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
+  struct timeval *system_boot_time = &param->system_boot_time;
+  u_int64_t *flows_exported = &param->flows_exported;
+  u_int64_t *records_sent = &param->records_sent;
+  struct OPTION *option = &param->option;
+
+  if (version != 9 && version != 10)
+    return (-1);
+  if (param->adjust_time)
+    now = param->last_packet_time;
+  else
+    gettimeofday (&now, NULL);
+
+  if (ipfix_pkts_until_template == -1) {
+    ipfix_init_template (param, bi_flag, version);
+    ipfix_pkts_until_template = 0;
+    if (option != NULL) {
+      if (version == 10) {
+        ipfix_init_option (system_boot_time, option);
+      } else {
+        nflow9_init_option (ifidx, option);
+      }
+    }
+  }
+
+  last_valid = num_packets = 0;
+  for (j = 0; j < num_flows;) {
+    bzero (packet, sizeof (packet));
+    if (version == 10) {
+      ipfix = (struct IPFIX_HEADER *) packet;
+      ipfix->version = htons (version);
+      ipfix->length = 0;        /* Filled as we go, htons at end */
+      if (param->adjust_time)
+        ipfix->export_time = htonl (now.tv_sec);
+      else
+        ipfix->export_time = htonl (time (NULL));
+      ipfix->od_id = 0;
+      offset = sizeof (*ipfix);
+    } else if (version == 9) {
+      nf9 = (struct NFLOW9_HEADER *) packet;
+      nf9->version = htons (version);
+      nf9->flows = 0;           /* Filled as we go, htons at end */
+      nf9->uptime_ms = htonl (timeval_sub_ms (&now, system_boot_time));
+      if (param->adjust_time)
+        nf9->export_time = htonl (now.tv_sec);
+      else
+        nf9->export_time = htonl (time (NULL));
+      nf9->od_id = 0;
+      offset = sizeof (*nf9);
+    }
+
+    /* Refresh template headers if we need to */
+    if (ipfix_pkts_until_template <= 0) {
+      for (i = 0; i < TMPLMAX; i++) {
+        memcpy_template (packet, &offset, &templates[i], bi_flag);
+      }
+      if (option != NULL) {
+        u_int16_t opt_tmpl_len = ntohs (option_template.h.c.length);
+        memcpy (packet + offset, &option_template, opt_tmpl_len);
+        offset += opt_tmpl_len;
+        if (version == 10) {
+          memcpy (packet + offset, &option_data, sizeof (option_data));
+          offset += sizeof (option_data);
+        } else if (version == 9) {
+          memcpy (packet + offset, &nf9opt_data, sizeof (nf9opt_data));
+          offset += sizeof (nf9opt_data);
+        }
+      }
+
+      ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL;
+      if (target->is_loadbalance && target->num_destinations > 1) {
+        ipfix->length = htons (offset);
+        if (version == 10) {
+          ipfix->sequence =
+            htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
+        } else if (version == 9) {
+          nf9->sequence =
+            htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
+        }
+        if (send_multi_destinations
+            (target->num_destinations, target->destinations, 0, packet,
+             offset) < 0)
+          return (-1);
+        offset = version == 10 ? sizeof (*ipfix) : sizeof (*nf9);       // resest offset
+      }
+    }
+
+    dh = NULL;
+    last_af = 0;
+    last_icmp_flag = -1;
+    records = 0;
+    for (i = 0; i + j < num_flows; i++) {
+      icmp_flag = valuate_icmp (flows[i + j]);
+      if (dh == NULL || flows[i + j]->af != last_af ||
+          icmp_flag != last_icmp_flag) {
+        if (dh != NULL) {
+          if (offset % 4 != 0) {
+            /* Pad to multiple of 4 */
+            dh->length += 4 - (offset % 4);
+            offset += 4 - (offset % 4);
+          }
+          /* Finalise last header */
+          dh->length = htons (dh->length);
+        }
+        if (offset + sizeof (*dh) > sizeof (packet)) {
+          /* Mark header is finished */
+          dh = NULL;
+          break;
+        }
+        dh = (struct IPFIX_SET_HEADER *) (packet + offset);
+        tmplindex = ipfix_flow_to_template_index (flows[i + j]);
+        dh->set_id = templates[tmplindex].h.r.template_id;
+        last_af = flows[i + j]->af;
+        last_icmp_flag = icmp_flag;
+        last_valid = offset;
+        dh->length = sizeof (*dh);      /* Filled as we go */
+        offset += sizeof (*dh);
+      }
+      r = ipfix_flow_to_flowset (flows[i + j],
+                                 packet + offset,
+                                 sizeof (packet) - offset,
+                                 ifidx, system_boot_time,
+                                 &inc, param, bi_flag);
+      if (r <= 0) {
+        /* yank off data header, if we had to go back */
+        if (last_valid)
+          offset = last_valid;
+        break;
+      }
+      records += (u_int) r;
+      offset += inc;
+      dh->length += inc;
+      last_valid = 0;           /* Don't clobber this header now */
+      if (verbose_flag) {
+        logit (LOG_DEBUG, "Flow %d/%d: "
+               "r %d offset %d ie %04x len %d(0x%04x)",
+               r, i, j, offset, dh->set_id, dh->length, dh->length);
+      }
+    }
+    /* Don't finish header if it has already been done */
+    if (dh != NULL) {
+      if (offset % 4 != 0) {
+        /* Pad to multiple of 4 */
+        dh->length += 4 - (offset % 4);
+        offset += 4 - (offset % 4);
+      }
+      /* Finalise last header */
+      dh->length = htons (dh->length);
+    }
+    ipfix->length = htons (offset);
+    *records_sent += records;
+    if (version == 10) {
+      ipfix->sequence =
+        htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
+    } else if (version == 9) {
+      nf9->sequence =
+        htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
+    }
+
+    if (verbose_flag)
+      logit (LOG_DEBUG, "Sending flow packet len = %d", offset);
+    if (send_multi_destinations
+        (target->num_destinations, target->destinations,
+         target->is_loadbalance, packet, offset) < 0)
+      return (-1);
+    num_packets++;
+    ipfix_pkts_until_template--;
+
+    j += i;
+  }
+
+  *flows_exported += j;
+  param->packets_sent += num_packets;
+#ifdef ENABLE_PTHREAD
+  if (use_thread)
+    free (flows);
+#endif /* ENABLE_PTHREAD */
+  return (num_packets);
+}
+
+int
+send_nflow9 (struct SENDPARAMETER sp) {
+  return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx,
+                            sp.param, sp.verbose_flag, 0, 9);
+}
+
+int
+send_ipfix (struct SENDPARAMETER sp) {
+  return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx,
+                            sp.param, sp.verbose_flag, 0, 10);
+}
+
+int
+send_ipfix_bi (struct SENDPARAMETER sp) {
+  return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx,
+                            sp.param, sp.verbose_flag, 1, 10);
+}

+ 141 - 0
ipfix.h

@@ -0,0 +1,141 @@
+/*
+ * Copyright 2019 Hitoshi Irino <irino@sfc.wide.ad.jp> 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 _IPFIX_H
+#define _IPFIX_H
+
+#include "softflowd.h"
+
+#define IPFIX_TEMPLATE_SET_ID           2
+#define IPFIX_OPTION_TEMPLATE_SET_ID    3
+#define IPFIX_MIN_RECORD_SET_ID         256
+
+/* Flowset record ies the we care about */
+#define IPFIX_octetDeltaCount           1
+#define IPFIX_packetDeltaCount          2
+/* ... */
+#define IPFIX_protocolIdentifier        4
+#define IPFIX_ipClassOfService          5
+/* ... */
+#define IPFIX_tcpControlBits            6
+#define IPFIX_sourceTransportPort       7
+#define IPFIX_sourceIPv4Address         8
+/* ... */
+#define IPFIX_ingressInterface          10
+#define IPFIX_destinationTransportPort  11
+#define IPFIX_destinationIPv4Address    12
+/* ... */
+#define IPFIX_egressInterface           14
+/* ... */
+#define IPFIX_flowEndSysUpTime          21
+#define IPFIX_flowStartSysUpTime        22
+/* ... */
+#define IPFIX_sourceIPv6Address         27
+#define IPFIX_destinationIPv6Address    28
+/* ... */
+#define IPFIX_icmpTypeCodeIPv4          32
+/* ... */
+#define IPFIX_sourceMacAddress          56
+#define IPFIX_postDestinationMacAddress 57
+#define IPFIX_vlanId                    58
+#define IPFIX_postVlanId                59
+
+#define IPFIX_ipVersion                     60
+/* ... */
+#define IPFIX_icmpTypeCodeIPv6              139
+/* ... */
+#define IPFIX_meteringProcessId             143
+/* ... */
+#define IPFIX_flowStartSeconds              150
+#define IPFIX_flowEndSeconds                151
+#define IPFIX_flowStartMilliSeconds         152
+#define IPFIX_flowEndMilliSeconds           153
+#define IPFIX_flowStartMicroSeconds         154
+#define IPFIX_flowEndMicroSeconds           155
+#define IPFIX_flowStartNanoSeconds          156
+#define IPFIX_flowEndNanoSeconds            157
+/* ... */
+#define IPFIX_systemInitTimeMilliseconds    160
+/* ... */
+
+
+#define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE     1428
+struct IPFIX_HEADER {
+  u_int16_t version, length;
+  u_int32_t export_time;        /* in seconds */
+  u_int32_t sequence, od_id;
+} __packed;
+struct IPFIX_SET_HEADER {
+  u_int16_t set_id, length;
+} __packed;
+struct IPFIX_TEMPLATE_RECORD_HEADER {
+  u_int16_t template_id, count;
+} __packed;
+struct IPFIX_TEMPLATE_SET_HEADER {
+  struct IPFIX_SET_HEADER c;
+  struct IPFIX_TEMPLATE_RECORD_HEADER r;
+} __packed;
+
+struct IPFIX_FIELD_SPECIFIER {
+  u_int16_t ie, length;
+} __packed;
+
+struct IPFIX_OPTION_TEMPLATE_SET_HEADER {
+  struct IPFIX_SET_HEADER c;
+  union {
+    struct {
+      struct IPFIX_TEMPLATE_RECORD_HEADER r;
+      u_int16_t scope_count;
+    } i;
+    struct {
+      u_int16_t template_id;
+      u_int16_t scope_length;
+      u_int16_t option_length;
+    } n;
+  } u;
+} __packed;
+
+struct IPFIX_VENDOR_FIELD_SPECIFIER {
+  u_int16_t ie, length;
+  u_int32_t pen;
+} __packed;
+#define REVERSE_PEN 29305
+
+struct ntp_time_t {
+  uint32_t second;
+  uint32_t fraction;
+};
+
+/* Prototypes for functions to send NetFlow packets */
+int send_nflow9 (struct SENDPARAMETER sp);
+int send_ipfix (struct SENDPARAMETER sp);
+int send_ipfix_bi (struct SENDPARAMETER sp);
+/* Force a resend of the flow template */
+void ipfix_resend_template (void);
+int ipfix_init_fields (struct IPFIX_FIELD_SPECIFIER *dst, u_int * index,
+                       const struct IPFIX_FIELD_SPECIFIER *src,
+                       u_int field_number);
+void conv_unix_to_ntp (struct timeval tv, struct ntp_time_t *ntp);
+struct timeval conv_ntp_to_unix (struct ntp_time_t ntp);
+#endif /* _IPFIX_H */

+ 144 - 20
mkinstalldirs

@@ -1,38 +1,162 @@
 #! /bin/sh
 # mkinstalldirs --- make directory hierarchy
-# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+
+scriptversion=2009-04-28.21; # UTC
+
+# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
 # Created: 1993-05-16
-# Public domain
+# Public domain.
+#
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
 
+nl='
+'
+IFS=" ""	$nl"