Browse Source

Import upstream version 1.1.0

Hitoshi Irino 2 months ago
parent
commit
6b1f750107
26 changed files with 1748 additions and 1928 deletions
  1. 7 1
      .travis.yml
  2. 325 0
      ChangeLog
  3. 3 3
      INSTALL
  4. 1 1
      Makefile.am
  5. 12 1
      NEWS
  6. 17 3
      README
  7. 0 1152
      aclocal.m4
  8. 17 4
      common.h
  9. 20 10
      configure.ac
  10. 1 1
      freelist.c
  11. 0 508
      install-sh
  12. 81 27
      ipfix.c
  13. 28 14
      ipfix.h
  14. 0 162
      mkinstalldirs
  15. 6 6
      netflow9.c
  16. 4 4
      ntopng.c
  17. 1 1
      psamp.c
  18. 100 0
      softflowctl.md
  19. BIN
      softflowctl.pdf
  20. 18 3
      softflowd.8
  21. 158 26
      softflowd.c
  22. 5 0
      softflowd.h
  23. 540 0
      softflowd.html
  24. 403 0
      softflowd.md
  25. BIN
      softflowd.pdf
  26. 1 1
      softflowd.spec

+ 7 - 1
.travis.yml

@@ -3,7 +3,13 @@ language: c
 os:
   - linux
   - osx
-
+arch:
+  - amd64
+  - ppc64le
+matrix:
+  exclude:
+   - os: osx
+     arch: ppc64le
 compiler: gcc
 sudo: false
 addons:

+ 325 - 0
ChangeLog

@@ -1,3 +1,328 @@
+commit 1d5ca1ca6423a96a0065dd493e8280e73d09d7bc
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Mon Sep 19 14:11:53 2022 +0000
+
+    solve warnings
+
+commit fb015b413b9b5d9708db8c5468b62c47284b497a
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Aug 13 06:57:19 2022 +0000
+
+    Update man page for -x option.
+    Add softflowd.html generated from softflowd.8 (groff -Thtml -mandoc -c softflowd.8 > softflowd.html)
+    Update softflowd.md generated from softflowd.html (pandoc -f html -t markdown softflowd.html > softflowd.md)
+
+commit 18049517c1eef937bfbe71a9da10ef83db76eb23
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Aug 13 02:23:00 2022 +0000
+
+    Add -x option for supporting MPLS packet.
+
+commit 52eab7bd3c786a406fbf0e96c76b03accf5cc9b6
+Merge: c96ad14 2fe941e
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Dec 19 00:01:47 2020 +0900
+
+    Merge pull request #36 from sanjaymsh/ppc64le
+    
+    Travis-ci:added support for ppc64le
+
+commit 2fe941e5505defffdcc8197c64300d44d3e97e32
+Author: sanjay-cpu <snjkmr32@gmail.com>
+Date:   Thu Dec 17 08:44:32 2020 +0000
+
+    Travis-ci:added support for ppc64le
+
+commit c96ad14fcab93d9c79e22cacc41cb149cfce7e19
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sun Sep 20 05:58:47 2020 +0900
+
+    Add markdown files generated from manpages
+
+commit a305d9151e75939dae251ab17a7c7f999b0f9e5c
+Merge: b9bacb0 e3eff52
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Fri Jul 31 23:58:46 2020 +0900
+
+    Merge pull request #34 from atonkyra/add-buffer-size-argument
+    
+    Add option for setting libpcap buffer size
+
+commit e3eff52474625375ae64fb28c0fdf5989c7a8e0b
+Author: Antti Tönkyrä <antti@sensorfleet.com>
+Date:   Wed Jul 29 13:28:08 2020 +0300
+
+    Add option for setting libpcap buffer size
+
+commit b9bacb0c64e1a3adb45600706f160f9f0f5c3419
+Merge: a86b5e3 f19307b
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Jul 25 14:39:39 2020 +0900
+
+    Merge pull request #33 from pwp333/ifname
+    
+    Amend configure help message to add IPFIX for enable-ifname
+
+commit f19307b0533bcadaadaccbc63ec26e8c23820c84
+Author: Michael Hu <mhu@aviatrix.com>
+Date:   Thu Jul 23 16:10:12 2020 -0700
+
+    Amend configure help message to add IPFIX for enable-ifname
+
+commit a86b5e35e5cbfb9aa6ac0d0a02f70dbfc1232063
+Merge: 72c1f9a dcedadb
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Fri Jul 24 07:59:57 2020 +0900
+
+    Merge pull request #29 from pwp333/ifname
+    
+    Report interfaceName in normal data and tempalte record
+
+commit 72c1f9ab77205c7107d9aeb13eb01701b890dd14
+Merge: f5dd974 2eebed3
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Thu Jul 23 13:42:42 2020 +0900
+
+    Merge pull request #32 from pwp333/icmp
+    
+    Report ip protocol number for ICMP flow for IPFIX
+
+commit 2eebed3a8aba2d84dbf71a13c0250467c2ff5989
+Author: Michael Hu <pwp333@hotmail.com>
+Date:   Fri Jul 17 17:43:24 2020 -0700
+
+    Report ip protocol number for ICMP flow for IPFIX
+    
+    Currently protocol number is missing in v9/IPFIX for ICMP flow.
+
+commit dcedadb3cd302ddbbcc7fafea98de9b371c4ca69
+Author: Michael Hu <pwp333@hotmail.com>
+Date:   Mon Jun 15 23:23:57 2020 -0700
+
+    Report interfaceName in normal data and template of v9 record
+    
+    Some popular netflow collectors like logstash and elasticsearch
+    take if_name from common netflow records only.
+    
+    Add configure option --enable-ifname to report interfaceName
+    in normal data and template of v9 record.
+    
+    Also fix if_name is empty string always since strlen(src_string) is 0 initially.
+    Need to use sizeof() instead.
+
+commit f5dd97464623d0a58435cb74acefa8f7f78ed3d6
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Jul 11 15:32:40 2020 +0900
+
+    Fix sequence in Netflow v9 header.
+
+commit 986358392821934f4629f3a306563f9206a13368
+Merge: c8cc54a ab9faac
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Thu May 28 07:21:29 2020 +0900
+
+    Merge pull request #28 from overhacked/vlan_mask_fix
+    
+    Correctly mask the 802.1q TCI bytes
+
+commit ab9faacae7b39230cecdb8e2b9edcea766c396fb
+Author: Ross Williams <ross@ross-williams.net>
+Date:   Wed May 27 19:39:41 2020 +0000
+
+    Correctly mask the 802.1q TCI bytes
+    
+    The 802.1q tag is constructed as follows:
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |             TPID              | PCP | |          VID          |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                                           ^
+                                           |
+                                          DEI
+                                    \_______________________________/
+                                                   TCI
+    
+    softflowd assumed that all 16 bits of the TCI represented the
+    VLAN ID (VID). If the PCP or DEI were not zero, the reported VLAN
+    ID would be incorrect (e.g. VLAN 4090 reported as 12282, not a valid
+    VID). The solution here is to apply a 12-bit mask to the extracted TCI
+    bytes.
+    
+    This discards the PCP and DEI value, but softflowd wasn't reporting
+    those anyway. They could be recovered in the future if needed. For
+    terms and definitions without reading the IEEE 802.1q standard, the
+    Wikipedia article is excellent: https://en.wikipedia.org/wiki/IEEE_802.1Q
+
+commit c8cc54a30376a79960e8ad1264ace129f9e743af
+Merge: ebe6cc4 8f94ea2
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Mon May 25 06:38:43 2020 +0900
+
+    Merge pull request #27 from overhacked/patch-1
+    
+    Fix ipfix.c `vlanId` & `postVlanId` network byte order
+
+commit 8f94ea27f27e17d508c6888681255dc0721e3c38
+Author: Ross Williams <ross@ross-williams.net>
+Date:   Sun May 24 08:08:03 2020 -0400
+
+    Fix ipfix.c vlanId network byte order
+    
+    IPFIX requires the vlanid to be in network byte order but it was
+    being exported in host byte order.
+
+commit ebe6cc44d896334bb4b4f3e7f8f34f304fb0c56c
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat May 9 20:44:15 2020 +0900
+
+    fix code to avoid gcc warnings about buffer overflow.
+
+commit 1c038e107469821da906192065139d5df48c5d74
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat May 9 19:52:45 2020 +0900
+
+    remove autogenerated file
+
+commit f690df8166341b543e86cd65d39841d08b9c3721
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat May 9 19:50:57 2020 +0900
+
+    update README
+
+commit ead968d2843019dfb9e686f1c114833be761b32c
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sun Apr 26 15:09:03 2020 +0900
+
+    Add flowDirection and flowEndReason in IPFIX and NetFlow v9
+
+commit f1223c3e81dd0191f30edb05cee8cdcb0fc7162d
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sun Apr 26 11:11:26 2020 +0900
+
+    Add interfaceName in option tamplate of IPFIX and NetFlow v9
+
+commit 1401758248ac7d31be6af68c293ff3b38d64b042
+Merge: f510969 3e731d4
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Wed Apr 15 22:48:03 2020 +0900
+
+    Merge pull request #24 from tofurky/ntopng_ntohs_ports
+    
+    Convert ports to host byte order for ntopng
+
+commit 3e731d4d806250a37826a6cd283ba9ca2c6406bb
+Author: Matt Merhar <mattmerhar@protonmail.com>
+Date:   Sat Apr 11 21:40:50 2020 -0400
+
+    Convert ports to host byte order for ntopng
+    
+    ntopng expects the ports to be in host byte order and does no conversion
+    of its own.
+    
+    Tested on both big (MIPS) and little (x86_64) endian devices with ntopng
+    4.0.
+    
+    Signed-off-by: Matt Merhar <mattmerhar@protonmail.com>
+
+commit f5109693f76dd608c2ce40f51b039c68023dc6a7
+Merge: 178c5ff 020dd2a
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Fri Apr 10 21:33:30 2020 +0900
+
+    Merge pull request #23 from neheb/patch-1
+    
+    fix compilation with musl
+
+commit 020dd2a325a15ba8bd995e5ea19ba23477b85e58
+Author: Rosen Penev <rosenp@gmail.com>
+Date:   Sat Mar 28 17:20:00 2020 -0700
+
+    fix compilation with musl
+    
+    __uid_t is a glibc type.
+
+commit 178c5ff522308a20986184306ae04ec1c276f33d
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Nov 30 00:18:05 2019 +0900
+
+    fix bug that displays wrong (dec instead of hex) MAC Address in ntopng
+
+commit db2fbb082fa9c7fbaacadfbf862c139099195202
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sun Nov 17 17:38:24 2019 +0900
+
+    Add -S option for specifying send interface name.
+
+commit 479ca8fb32db4d74b543abc1437dd504502faf9d
+Merge: fe37a4e 07ae8b2
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Wed Sep 4 22:43:09 2019 +0900
+
+    Merge pull request #18 from bruceg/no-promisc
+    
+    Add support for non-promiscuous operation
+
+commit 07ae8b26890e8c4b0dbebd58438fe0e1aa990831
+Author: Bruce Guenter <bruce@untroubled.org>
+Date:   Mon Sep 2 10:30:16 2019 -0600
+
+    Add support for non-promiscuous operation
+    
+    Signed-off-by: Bruce Guenter <bruce@untroubled.org>
+
+commit fe37a4e64f12d1d571ef9c2b00dfd54debba4c16
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Aug 24 09:21:07 2019 +0900
+
+    Update README about manpages
+
+commit 64d7e96f2aca9188cf847a49a1a7e1dd9dc91d07
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Aug 24 08:52:31 2019 +0900
+
+    deleting pdfs from git
+
+commit 3681af73d21b3f34cb555de29b464b320e41745b
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Aug 24 07:14:56 2019 +0900
+
+    Changing installation directory from bin to sbin which is original installation directory. (Issue #16)
+
+commit 088cf827075dbd4ba6a73761d05d85d9d1d8ca66
+Merge: 9cf249e f9a1e88
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Sat Aug 24 07:01:17 2019 +0900
+
+    Merge pull request #17 from neheb/master
+    
+    Replace deprecated bzero with memset
+
+commit f9a1e8829c6b442c1d8d8d0b78b7b672ede0cee2
+Author: Rosen Penev <rosenp@gmail.com>
+Date:   Fri Aug 23 12:39:36 2019 -0700
+
+    Replace deprecated bzero with memset
+    
+    bzero is optionally unavailable with uClibc-ng.
+
+commit 9cf249ebc18745a59418a62de124ff3975b59a01
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Fri Aug 16 22:42:16 2019 +0900
+
+    fix typo in NEWS
+
+commit f0a614318d1f9b39106da47b78659dfcb12568c8
+Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
+Date:   Fri Aug 16 20:31:36 2019 +0900
+
+    Minor fixes
+    
+    - fix typos.
+    - update date in NEWS
+    - symlink from LICENSE to COPYING
+    - replace "0.9.9" to "1.0.0"
+
 commit bf7f0ec0c335d8d367c9b1e64371acd8e7bcc1d0
 Author: Hitoshi Irino <irino@sfc.wide.ad.jp>
 Date:   Thu Aug 15 23:05:08 2019 +0900

+ 3 - 3
INSTALL

@@ -1,8 +1,8 @@
 Installation Instructions
 *************************
 
-   Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
-Foundation, Inc.
+   Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free
+Software Foundation, Inc.
 
    Copying and distribution of this file, with or without modification,
 are permitted in any medium without royalty provided the copyright
@@ -225,7 +225,7 @@ order to use an ANSI C compiler:
 
 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
+   HP-UX 'make' updates targets which have the same timestamps as their
 prerequisites, which makes it generally unusable when shipped generated
 files such as 'configure' are involved.  Use GNU 'make' instead.
 

+ 1 - 1
Makefile.am

@@ -1,4 +1,4 @@
-bin_PROGRAMS = softflowd softflowctl
+sbin_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

+ 12 - 1
NEWS

@@ -1,3 +1,14 @@
+Fri Sep 20 2022
+Softflowd 1.1.0
+This release contains some new features and some bug fix by community.
+
+Details
+This release contains the following new features:
+Add -x option which means number of MPLS shim label header for decoding and exporting MPLS packet.
+Add -B option for specifying Libpcap buffer size.
+Add exporting interface name with --enable-ifname configure option.
+
+
 Fri Aug 16 2019
 Softflowd 1.0.0
 This release contains some new features.
@@ -27,4 +38,4 @@ 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
+Correct broken IPv6 Netflow v.9 flows

+ 17 - 3
README

@@ -9,11 +9,26 @@ 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 PDF manpages. They were built with:
+softflowd wiki in following URLs:
+https://github.com/irino/softflowd/wiki/softflowd
+https://github.com/irino/softflowd/wiki/softflowctl
+
+PDF manpages can be built with:
 
 man -t ./softflowd.8 | ps2pdf - softflowd.pdf
 man -t ./softflowctl.8 | ps2pdf - softflowctl.pdf
 
+HTML manpages can be built with:
+
+groff -mandoc -Thtml softflowd.8 > softflowd.html
+groff -mandoc -Thtml softflowctl.8 > softflowctl.html
+
+Markdown manpages (which are published in wiki pages) can be built
+from above HtML manpages:
+
+pandoc -s softflowd.html -o softflowd.md
+pandoc -s softflowctl.html -o softflowctl.md
+
 You can view those pages prior to installation using:
 
 /usr/bin/nroff -c -mandoc softflowd.8 | less
@@ -33,8 +48,7 @@ Installing
 
 Building softflowd should be as simple as typing:
 
-autoconf
-autoreconf
+autoreconf -if # instead of "aclocal && autoheader && automake --add-missing && autoconf"
 ./configure
 make
 make install

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


+ 17 - 4
common.h

@@ -83,7 +83,7 @@
 #define PROGNAME		"softflowd"
 
 /* The name of the program */
-#define PROGVER			"1.0.0"
+#define PROGVER			"1.1.0"
 
 /* Default pidfile */
 #define DEFAULT_PIDFILE		"/var/run/" PROGNAME ".pid"
@@ -179,10 +179,10 @@ struct ip6_ext {
 
 /* 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);
+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);
+extern int setresuid (uid_t __ruid, uid_t __euid, uid_t __suid);
 #endif
 
 #if defined (HAVE_DECL_HTONLL) && !defined (HAVE_DECL_HTOBE64)
@@ -191,9 +191,22 @@ extern int setresuid (__uid_t __ruid, __uid_t __euid, __uid_t __suid);
 
 #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	 */
+#define ETH_ALEN	6       /* Octets in one ethernet addr   */
 #endif /* ETH_ALEN */
 
+#ifndef ETH_P_MPLS_UC
+#define ETH_P_MPLS_UC	0x8847  /* MPLS Unicast traffic         */
+#endif /* ETH_P_MPLS_UC */
+#ifndef MPLS_LS_S_MASK
+#define MPLS_LS_S_MASK          0x00000100
+#endif /* MPLS_LS_S_MASK */
+#ifndef MPLS_LS_S_SHIFT
+#define MPLS_LS_S_SHIFT         8
+#endif /* MPLS_LS_S_SHIFT */
+#ifndef IFNAMSIZ                /* defined in <net/if.h> in linux */
+#define IFNAMSIZ 16
+#endif /* IFNAMSIZ */
+
 #ifdef __APPLE__
 #include <libkern/OSByteOrder.h>
 #define htobe64(x) OSSwapHostToBigInt64(x)

+ 20 - 10
configure.ac

@@ -12,11 +12,11 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-AC_INIT([softflowd], [1.0.0])
+AC_INIT([softflowd],[1.1.0])
 AC_CONFIG_SRCDIR([softflowd.c])
 AM_INIT_AUTOMAKE
 
-AC_CONFIG_HEADER(config.h)
+AC_CONFIG_HEADERS([config.h])
 AC_PROG_CC
 AC_PROG_INSTALL
 
@@ -33,23 +33,23 @@ AC_ARG_ENABLE(gcc-warnings,
 	[ 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)]),
+              AS_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)]),
+              AS_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)]),
+              AS_HELP_STRING([--enable-ntopng],[enable flow sending to ntopng with zeromq (default NO)]),
               [ntopng=yes],[ntopng=no])
+AC_ARG_ENABLE(ifname,
+              AS_HELP_STRING([--enable-ifname],[enable flow reporting iface name in normal data of v9 and IPFIX (default NO)]),
+              [ifname=yes],[ifname=no])
 AC_ARG_ENABLE(flow-spray,
-              AC_HELP_STRING([--enable-flow-spray],
-                             [enable spray as flow tree type(default is RB)]),
+              AS_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)]),
+              AS_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]))
 
@@ -140,6 +140,9 @@ if test "x$ntopng" = "xyes" ; then
   AC_SUBST([NTOPNG])
 fi
 AM_CONDITIONAL([ENABLE_NTOPNG], [test x$ntopng = xyes])
+if test "x$ifname" = "xyes" ; then
+  AC_DEFINE([ENABLE_IFNAME], 1, [enable reporting iface name])
+fi
 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
@@ -207,6 +210,13 @@ if test "x$ac_cv_lib_pcap_pcap_open_live" != "xyes" ; then
 	AC_MSG_ERROR([libpcap not found])
 fi
 
+AC_CANONICAL_HOST
+case "$host_os" in
+ linux-gnu*)
+	AC_DEFINE([LINUX], [], [Linux OS])
+ ;;
+esac
+
 AC_EXEEXT
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT

+ 1 - 1
freelist.c

@@ -46,7 +46,7 @@ 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);
+	memset(fl, 0, sizeof_fl);
 	fl->allocsz = roundup(allocsz, FREELIST_ALLOC_ALIGN);
 	fl->free_entries = NULL;
 }

+ 0 - 508
install-sh

@@ -1,508 +0,0 @@
-#!/bin/sh
-# install - install a program, script, or datafile
-
-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.
-#
-# 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.
-#
-#
-# 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
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-
-tab='	'
-nl='
-'
-IFS=" $tab$nl"
-
-# Set DOITPROG to "echo" to test this script.
-
-doit=${DOITPROG-}
-doit_exec=${doit:-exec}
-
-# 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}
-
-posix_mkdir=
-
-# Desired mode of installed file.
-mode=0755
-
-chgrpcmd=
-chmodcmd=$chmodprog
-chowncmd=
-mvcmd=$mvprog
-rmcmd="$rmprog -f"
-stripcmd=
-
-src=
-dst=
-dir_arg=
-dst_arg=
-
-copy_on_change=false
-is_target_a_directory=possibly
-
-usage="\
-Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
-   or: $0 [OPTION]... SRCFILES... DIRECTORY
-   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
-   or: $0 [OPTION]... -d DIRECTORIES...
-
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
-
-Options:
-     --help     display this help and exit.
-     --version  display version info and exit.
-
-  -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.
-
-Environment variables override the default commands:
-  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
-  RMPROG STRIPPROG
-"
-
-while test $# -ne 0; do
-  case $1 in
-    -c) ;;
-
-    -C) copy_on_change=true;;
-
-    -d) dir_arg=true;;
-
-    -g) chgrpcmd="$chgrpprog $2"
-        shift;;
-
-    --help) echo "$usage"; exit $?;;
-
-    -m) mode=$2
-        case $mode in
-          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
-            echo "$0: invalid mode: $mode" >&2
-            exit 1;;
-        esac
-        shift;;
-
-    -o) chowncmd="$chownprog $2"
-        shift;;
-
-    -s) stripcmd=$stripprog;;
-
-    -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;;
-
-    -T) is_target_a_directory=never;;
-
-    --version) echo "$0 $scriptversion"; exit $?;;
-
-    --) shift
-        break;;
-
-    -*) echo "$0: invalid option: $1" >&2
-        exit 1;;
-
-    *)  break;;
-  esac
-  shift
-done
-
-# We allow the use of options -d and -T together, by making -d
-# take the precedence; this is for compatibility with GNU install.
-
-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 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
-
-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
-
-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
-
-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
-
-# 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:

+ 81 - 27
ipfix.c

@@ -45,7 +45,12 @@ const struct IPFIX_FIELD_SPECIFIER field_common[] = {
   {IPFIX_octetDeltaCount, 4},
   {IPFIX_packetDeltaCount, 4},
   {IPFIX_ingressInterface, 4},
-  {IPFIX_egressInterface, 4}
+  {IPFIX_egressInterface, 4},
+  {IPFIX_flowDirection, 1},
+  {IPFIX_flowEndReason, 1},
+#ifdef ENABLE_IFNAME
+  {IPFIX_interfaceName, IFNAMSIZ}
+#endif
 };
 
 const struct IPFIX_FIELD_SPECIFIER field_transport[] = {
@@ -59,12 +64,14 @@ const struct IPFIX_FIELD_SPECIFIER field_transport[] = {
 
 const struct IPFIX_FIELD_SPECIFIER field_icmp4[] = {
   {IPFIX_icmpTypeCodeIPv4, 2},
+  {IPFIX_protocolIdentifier, 1},
   {IPFIX_ipVersion, 1},
   {IPFIX_ipClassOfService, 1}
 };
 
 const struct IPFIX_FIELD_SPECIFIER field_icmp6[] = {
   {IPFIX_icmpTypeCodeIPv6, 2},
+  {IPFIX_protocolIdentifier, 1},
   {IPFIX_ipVersion, 1},
   {IPFIX_ipClassOfService, 1}
 };
@@ -126,7 +133,8 @@ const struct IPFIX_FIELD_SPECIFIER field_option[] = {
   {IPFIX_systemInitTimeMilliseconds, 8},
   {PSAMP_samplingPacketInterval, 4},
   {PSAMP_samplingPacketSpace, 4},
-  {PSAMP_selectorAlgorithm, 2}
+  {PSAMP_selectorAlgorithm, 2},
+  {IPFIX_interfaceName, IFNAMSIZ}
 };
 
 const struct IPFIX_FIELD_SPECIFIER field_nf9scope[] =
@@ -134,7 +142,8 @@ const struct IPFIX_FIELD_SPECIFIER field_nf9scope[] =
 
 const struct IPFIX_FIELD_SPECIFIER field_nf9option[] = {
   {NFLOW9_SAMPLING_INTERVAL, 4},
-  {NFLOW9_SAMPLING_ALGORITHM, 1}
+  {NFLOW9_SAMPLING_ALGORITHM, 1},
+  {IPFIX_interfaceName, IFNAMSIZ}
 };
 
 /* Stuff pertaining to the templates that softflowd uses */
@@ -200,6 +209,10 @@ struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE {
 struct IPFIX_SOFTFLOWD_DATA_COMMON {
   u_int32_t octetDeltaCount, packetDeltaCount;
   u_int32_t ingressInterface, egressInterface;
+  u_int8_t flowDirection, flowEndReason;
+#ifdef ENABLE_IFNAME
+  char interfaceName[IFNAMSIZ];
+#endif
 } __packed;
 
 struct IPFIX_SOFTFLOWD_DATA_TRANSPORT {
@@ -209,7 +222,7 @@ struct IPFIX_SOFTFLOWD_DATA_TRANSPORT {
 
 struct IPFIX_SOFTFLOWD_DATA_ICMP {
   u_int16_t icmpTypeCode;
-  u_int8_t ipVersion, ipClassOfService;
+  u_int8_t protocolIdentifier, ipVersion, ipClassOfService;
 } __packed;
 
 struct IPFIX_SOFTFLOWD_DATA_VLAN {
@@ -259,6 +272,7 @@ struct IPFIX_SOFTFLOWD_OPTION_DATA {
   u_int32_t samplingInterval;
   u_int32_t samplingSpace;
   u_int16_t samplingAlgorithm;
+  char interfaceName[IFNAMSIZ];
 } __packed;
 
 struct NFLOW9_SOFTFLOWD_OPTION_DATA {
@@ -266,6 +280,7 @@ struct NFLOW9_SOFTFLOWD_OPTION_DATA {
   u_int32_t scope_ifidx;
   u_int32_t samplingInterval;
   u_int8_t samplingAlgorithm;
+  char interfaceName[IFNAMSIZ];
 } __packed;
 
 /* Local data: templates and counters */
@@ -292,7 +307,7 @@ struct NFLOW9_SOFTFLOWD_OPTION_DATA {
 // prototype
 void memcpy_template (u_char * packet, u_int * offset,
                       struct IPFIX_SOFTFLOWD_TEMPLATE *template,
-                      u_int8_t bi_flag);
+                      u_int8_t bi_flag, u_int8_t max_num_label);
 
 // variables
 enum { TMPLV4, TMPLICMPV4, TMPLV6, TMPLICMPV6, TMPLMAX };
@@ -388,7 +403,7 @@ ipfix_init_template_unity (struct FLOWTRACKPARAMETERS *param,
                            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));
+  memset (template, 0, sizeof (*template));
   template->h.c.set_id = htons (version == 10 ?
                                 IPFIX_TEMPLATE_SET_ID :
                                 NFLOW9_TEMPLATE_SET_ID);
@@ -457,12 +472,14 @@ ipfix_init_template_unity (struct FLOWTRACKPARAMETERS *param,
     }
   }
   template->bi_count = bi_index;
-  template->h.r.count = htons (index + bi_index);
+  template->h.r.count = htons (index + bi_index + param->max_num_label);        // mpls
   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;
+           bi_index * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER) +
+           param->max_num_label * sizeof (struct IPFIX_FIELD_SPECIFIER));
+  template->data_len =
+    length + param->max_num_label * IPFIX_mplsLabelStackSection_SIZE;
 }
 
 static void
@@ -510,7 +527,7 @@ nflow9_init_option (u_int16_t ifidx, struct OPTION *option) {
     NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS *
     sizeof (struct IPFIX_FIELD_SPECIFIER);
 
-  bzero (&option_template, sizeof (option_template));
+  memset (&option_template, 0, 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);
@@ -524,19 +541,24 @@ nflow9_init_option (u_int16_t ifidx, struct OPTION *option) {
   ipfix_init_fields (option_template.r, &option_index,
                      field_nf9option,
                      NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
-  bzero (&nf9opt_data, sizeof (nf9opt_data));
+  memset (&nf9opt_data, 0, 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;
+  strncpy (nf9opt_data.interfaceName, option->interfaceName,
+           strlen (option->interfaceName) <
+           sizeof (nf9opt_data.interfaceName) ?
+           strlen (option->interfaceName) :
+           sizeof (nf9opt_data.interfaceName));
 }
 
 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));
+  memset (&option_template, 0, 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 =
@@ -553,7 +575,7 @@ ipfix_init_option (struct timeval *system_boot_time, struct OPTION *option) {
   ipfix_init_fields (option_template.r, &option_index, field_option,
                      IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
 
-  bzero (&option_data, sizeof (option_data));
+  memset (&option_data, 0, 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);
@@ -566,6 +588,11 @@ ipfix_init_option (struct timeval *system_boot_time, struct OPTION *option) {
   option_data.samplingInterval = htonl (1);
   option_data.samplingSpace =
     htonl (option->sample > 0 ? option->sample - 1 : 0);
+  strncpy (option_data.interfaceName, option->interfaceName,
+           strlen (option->interfaceName) <
+           sizeof (option_data.interfaceName) ?
+           strlen (option->interfaceName) :
+           sizeof (option_data.interfaceName));
 }
 
 static int
@@ -640,11 +667,12 @@ ipfix_flow_to_flowset (const struct FLOW *flow, u_char * packet,
   struct IPFIX_SOFTFLOWD_DATA_BICOMMON *dbc = NULL;
   struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *dbtr = NULL;
   struct IPFIX_SOFTFLOWD_DATA_BIICMP *dbi = NULL;
+  struct OPTION *option = &param->option;
 
   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;
+  int i = 0, k = 0;
   freclen = templates[tmplindex].data_len;
   if (len < freclen * frecnum)
     return (-1);
@@ -672,6 +700,14 @@ ipfix_flow_to_flowset (const struct FLOW *flow, u_char * packet,
     dc[i]->octetDeltaCount = htonl (flow->octets[i]);
     dc[i]->packetDeltaCount = htonl (flow->packets[i]);
     dc[i]->ingressInterface = dc[i]->egressInterface = htonl (ifidx);
+    dc[i]->flowDirection = i;
+    dc[i]->flowEndReason = flow->flowEndReason;
+#ifdef ENABLE_IFNAME
+    strncpy (dc[i]->interfaceName, option->interfaceName,
+             strlen (option->interfaceName) <
+             sizeof (dc[i]->interfaceName) ?
+             strlen (option->interfaceName) : sizeof (dc[i]->interfaceName));
+#endif
     offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_COMMON);
 
     if (flow->protocol != IPPROTO_ICMP && flow->protocol != IPPROTO_ICMPV6) {
@@ -686,14 +722,15 @@ ipfix_flow_to_flowset (const struct FLOW *flow, u_char * packet,
     } else {
       di[i] = (struct IPFIX_SOFTFLOWD_DATA_ICMP *) &packet[offset];
       di[i]->icmpTypeCode = flow->port[i ^ 1];
+      di[i]->protocolIdentifier = flow->protocol;
       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];
+      dv[i]->vlanId = htons (flow->vlanid[i]);
+      dv[i]->postVlanId = htons (flow->vlanid[i ^ 1]);
       offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_VLAN);
     }
     if (param->track_level >= TRACK_FULL_VLAN_ETHER) {
@@ -720,6 +757,11 @@ ipfix_flow_to_flowset (const struct FLOW *flow, u_char * packet,
         offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BIICMP);
       }
     }
+    for (k = 0; k < param->max_num_label; k++) {
+      memcpy (&packet[offset], &flow->mplsLabels[k],
+              IPFIX_mplsLabelStackSection_SIZE);
+      offset += IPFIX_mplsLabelStackSection_SIZE;
+    }
   }
   *len_used = offset;
   return (nflows);
@@ -752,10 +794,12 @@ ipfix_resend_template (void) {
 
 void
 memcpy_template (u_char * packet, u_int * offset,
-                 struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int8_t bi_flag) 
-{
+                 struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int8_t bi_flag,
+                 u_int8_t max_num_label) {
+  int i = 0;
   int size = ntohs (template->h.c.length) -
-    template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER);
+    template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER) -
+    max_num_label * sizeof (struct IPFIX_FIELD_SPECIFIER);
   memcpy (packet + *offset, template, size);
   *offset += size;
   if (bi_flag) {
@@ -763,6 +807,14 @@ memcpy_template (u_char * packet, u_int * offset,
     memcpy (packet + *offset, template->v, size);
     *offset += size;
   }
+  // mpls
+  for (i = 0; i < max_num_label; i++) {
+    struct IPFIX_FIELD_SPECIFIER *mpls_fs =
+      (struct IPFIX_FIELD_SPECIFIER *) &packet[*offset];
+    mpls_fs->ie = htons (IPFIX_mplsTopLabelStackSection + i);
+    mpls_fs->length = htons (IPFIX_mplsLabelStackSection_SIZE);
+    *offset += sizeof (struct IPFIX_FIELD_SPECIFIER);
+  }
 }
 
 /*
@@ -787,6 +839,7 @@ send_ipfix_common (struct FLOW **flows, int num_flows,
   u_int64_t *flows_exported = &param->flows_exported;
   u_int64_t *records_sent = &param->records_sent;
   struct OPTION *option = &param->option;
+  static u_int sequence = 1;
 
   if (version != 9 && version != 10)
     return (-1);
@@ -809,7 +862,7 @@ send_ipfix_common (struct FLOW **flows, int num_flows,
 
   last_valid = num_packets = 0;
   for (j = 0; j < num_flows;) {
-    bzero (packet, sizeof (packet));
+    memset (packet, 0, sizeof (packet));
     if (version == 10) {
       ipfix = (struct IPFIX_HEADER *) packet;
       ipfix->version = htons (version);
@@ -836,7 +889,8 @@ send_ipfix_common (struct FLOW **flows, int num_flows,
     /* 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);
+        memcpy_template (packet, &offset, &templates[i], bi_flag,
+                         param->max_num_label);
       }
       if (option != NULL) {
         u_int16_t opt_tmpl_len = ntohs (option_template.h.c.length);
@@ -853,13 +907,13 @@ send_ipfix_common (struct FLOW **flows, int num_flows,
 
       ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL;
       if (target->is_loadbalance && target->num_destinations > 1) {
-        ipfix->length = htons (offset);
         if (version == 10) {
+          ipfix->length = htons (offset);
           ipfix->sequence =
             htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
         } else if (version == 9) {
-          nf9->sequence =
-            htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
+          nf9->flows = htons (records);
+          nf9->sequence = htonl (sequence++);
         }
         if (send_multi_destinations
             (target->num_destinations, target->destinations, 0, packet,
@@ -931,14 +985,14 @@ send_ipfix_common (struct FLOW **flows, int num_flows,
       /* Finalise last header */
       dh->length = htons (dh->length);
     }
-    ipfix->length = htons (offset);
     *records_sent += records;
     if (version == 10) {
+      ipfix->length = htons (offset);
       ipfix->sequence =
         htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
     } else if (version == 9) {
-      nf9->sequence =
-        htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
+      nf9->flows = htons (records);
+      nf9->sequence = htonl (sequence++);
     }
 
     if (verbose_flag)

+ 28 - 14
ipfix.h

@@ -60,27 +60,41 @@
 #define IPFIX_postDestinationMacAddress 57
 #define IPFIX_vlanId                    58
 #define IPFIX_postVlanId                59
-
-#define IPFIX_ipVersion                     60
+#define IPFIX_ipVersion                 60
+#define IPFIX_flowDirection             61
+#define IPFIX_mplsTopLabelStackSection  70
+/* ... */
+#define IPFIX_interfaceName             82
+/* ... */
+#define IPFIX_flowEndReason             136
 /* ... */
-#define IPFIX_icmpTypeCodeIPv6              139
+#define IPFIX_icmpTypeCodeIPv6          139
 /* ... */
-#define IPFIX_meteringProcessId             143
+#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_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_systemInitTimeMilliseconds 160
 /* ... */
 
+// flow end reason for ipfix ie 136
+#define IPFIX_flowEndReason_idleTimeout    0x01
+#define IPFIX_flowEndReason_activeTimeout  0x02
+#define IPFIX_flowEndReason_endOfFlow      0x03
+#define IPFIX_flowEndReason_forceEnd       0x04
+#define IPFIX_flowEndReason_lackOfResource 0x05
+
+#define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE  1428
+#define IPFIX_mplsLabelStackSection_SIZE 3
+
 
-#define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE     1428
 struct IPFIX_HEADER {
   u_int16_t version, length;
   u_int32_t export_time;        /* in seconds */

+ 0 - 162
mkinstalldirs

@@ -1,162 +0,0 @@
-#! /bin/sh
-# mkinstalldirs --- make directory hierarchy
-
-scriptversion=2009-04-28.21; # UTC
-
-# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
-# Created: 1993-05-16
-# 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"
-errstatus=0
-dirmode=
-
-usage="\
-Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
-
-Create each directory DIR (with mode MODE, if specified), including all
-leading file name components.
-
-Report bugs to <bug-automake@gnu.org>."
-
-# process command line arguments
-while test $# -gt 0 ; do
-  case $1 in
-    -h | --help | --h*)         # -h for help
-      echo "$usage"
-      exit $?
-      ;;
-    -m)                         # -m PERM arg
-      shift
-      test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
-      dirmode=$1
-      shift
-      ;;
-    --version)
-      echo "$0 $scriptversion"
-      exit $?
-      ;;
-    --)                         # stop option processing
-      shift
-      break
-      ;;
-    -*)                         # unknown option
-      echo "$usage" 1>&2
-      exit 1
-      ;;
-    *)                          # first non-opt arg
-      break
-      ;;
-  esac
-done
-
-for file
-do
-  if test -d "$file"; then
-    shift
-  else
-    break
-  fi
-done
-
-case $# in
-  0) exit 0 ;;
-esac
-
-# Solaris 8's mkdir -p isn't thread-safe.  If you mkdir -p a/b and
-# mkdir -p a/c at the same time, both will detect that a is missing,
-# one will create a, then the other will try to create a and die with
-# a "File exists" error.  This is a problem when calling mkinstalldirs
-# from a parallel make.  We use --version in the probe to restrict
-# ourselves to GNU mkdir, which is thread-safe.
-case $dirmode in
-  '')
-    if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
-      echo "mkdir -p -- $*"
-      exec mkdir -p -- "$@"
-    else
-      # On NextStep and OpenStep, the 'mkdir' command does not
-      # recognize any option.  It will interpret all options as
-      # directories to create, and then abort because '.' already
-      # exists.
-      test -d ./-p && rmdir ./-p
-      test -d ./--version && rmdir ./--version
-    fi
-    ;;
-  *)
-    if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
-       test ! -d ./--version; then
-      echo "mkdir -m $dirmode -p -- $*"
-      exec mkdir -m "$dirmode" -p -- "$@"
-    else
-      # Clean up after NextStep and OpenStep mkdir.
-      for d in ./-m ./-p ./--version "./$dirmode";
-      do
-        test -d $d && rmdir $d
-      done
-    fi
-    ;;
-esac
-
-for file
-do
-  case $file in
-    /*) pathcomp=/ ;;
-    *)  pathcomp= ;;
-  esac
-  oIFS=$IFS
-  IFS=/
-  set fnord $file
-  shift
-  IFS=$oIFS
-
-  for d
-  do
-    test "x$d" = x && continue
-
-    pathcomp=$pathcomp$d
-    case $pathcomp in
-      -*) pathcomp=./$pathcomp ;;
-    esac
-
-    if test ! -d "$pathcomp"; then
-      echo "mkdir $pathcomp"
-
-      mkdir "$pathcomp" || lasterr=$?
-
-      if test ! -d "$pathcomp"; then
-	errstatus=$lasterr
-      else
-	if test ! -z "$dirmode"; then
-	  echo "chmod $dirmode $pathcomp"
-	  lasterr=
-	  chmod "$dirmode" "$pathcomp" || lasterr=$?
-
-	  if test ! -z "$lasterr"; then
-	    errstatus=$lasterr
-	  fi
-	fi
-      fi
-    fi
-
-    pathcomp=$pathcomp/
-  done
-done
-
-exit $errstatus
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 2
-# 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:

+ 6 - 6
netflow9.c

@@ -145,7 +145,7 @@ static int nf9_pkts_until_template = -1;
 
 static void
 nf9_init_template (void) {
-  bzero (&v4_template, sizeof (v4_template));
+  memset (&v4_template, 0, sizeof (v4_template));
   v4_template.h.c.flowset_id = htons (NFLOW9_TEMPLATE_SET_ID);
   v4_template.h.c.length = htons (sizeof (v4_template));
   v4_template.h.template_id = htons (NF9_SOFTFLOWD_V4_TEMPLATE_ID);
@@ -182,7 +182,7 @@ nf9_init_template (void) {
   v4_template.r[14].length = htons (2);
   v4_template.r[15].type = htons (NF9_SRC_VLAN);
   v4_template.r[15].length = htons (2);
-  bzero (&v6_template, sizeof (v6_template));
+  memset (&v6_template, 0, sizeof (v6_template));
   v6_template.h.c.flowset_id = htons (NFLOW9_TEMPLATE_SET_ID);
   v6_template.h.c.length = htons (sizeof (v6_template));
   v6_template.h.template_id = htons (NF9_SOFTFLOWD_V6_TEMPLATE_ID);
@@ -223,7 +223,7 @@ nf9_init_template (void) {
 
 static void
 nf9_init_option (u_int16_t ifidx, struct OPTION *option) {
-  bzero (&option_template, sizeof (option_template));
+  memset (&option_template, 0, sizeof (option_template));
   option_template.h.c.flowset_id = htons (NFLOW9_OPTION_TEMPLATE_SET_ID);
   option_template.h.c.length = htons (sizeof (option_template));
   option_template.h.template_id = htons (NF9_SOFTFLOWD_OPTION_TEMPLATE_ID);
@@ -238,7 +238,7 @@ nf9_init_option (u_int16_t ifidx, struct OPTION *option) {
   option_template.r[1].length =
     htons (sizeof (option_data.sampling_algorithm));
 
-  bzero (&option_data, sizeof (option_data));
+  memset (&option_data, 0, sizeof (option_data));
   option_data.c.flowset_id = htons (NF9_SOFTFLOWD_OPTION_TEMPLATE_ID);
   option_data.c.length = htons (sizeof (option_data));
   option_data.scope_ifidx = htonl (ifidx);
@@ -257,7 +257,7 @@ nf_flow_to_flowset (const struct FLOW *flow, u_char * packet, u_int len,
   struct NF9_SOFTFLOWD_DATA_COMMON *dc[2];
   u_int freclen, ret_len, nflows;
 
-  bzero (d, sizeof (d));
+  memset (d, 0, sizeof (d));
   *len_used = nflows = ret_len = 0;
   switch (flow->af) {
   case AF_INET:
@@ -363,7 +363,7 @@ send_netflow_v9 (struct SENDPARAMETER sp) {
 
   last_valid = num_packets = 0;
   for (j = 0; j < num_flows;) {
-    bzero (packet, sizeof (packet));
+    memset (packet, 0, sizeof (packet));
     nf9 = (struct NFLOW9_HEADER *) packet;
 
     nf9->version = htons (9);

+ 4 - 4
ntopng.c

@@ -81,8 +81,8 @@ add_json_flow (struct SENDPARAMETER *sp, struct FLOW *flow, char *buf, size_t le
       "\"21\": %d," /* last timestamp */
       "\"6\": %d," /* tcp flags */
       "\"4\": %d", /* protocol */
-    flow->port[0],
-    flow->port[1],
+    ntohs(flow->port[0]),
+    ntohs(flow->port[1]),
     flow->octets[1],
     flow->packets[1],
     flow->octets[0],
@@ -142,8 +142,8 @@ add_json_flow (struct SENDPARAMETER *sp, struct FLOW *flow, char *buf, size_t le
 
   if (sp->param->track_level >= TRACK_FULL_VLAN_ETHER) {
     size += snprintf(buf + size, len - size,
-        ",\"56\":\"%d:%d:%d:%d:%d:%d\"," /* ether mac src */
-        "\"57\":\"%d:%d:%d:%d:%d:%d\"", /* ether mac dst */
+        ",\"56\":\"%x:%x:%x:%x:%x:%x\"," /* ether mac src */
+        "\"57\":\"%x:%x:%x:%x:%x:%x\"", /* ether mac dst */
         flow->ethermac[0][0],flow->ethermac[0][1],flow->ethermac[0][2],
         flow->ethermac[0][3],flow->ethermac[0][4],flow->ethermac[0][5],
         flow->ethermac[1][0],flow->ethermac[1][1],flow->ethermac[1][2],

+ 1 - 1
psamp.c

@@ -51,7 +51,7 @@ static int psamp_pkts_until_template = -1;
 static void
 psamp_init_template (struct PSAMP_SOFTFLOWD_TEMPLATE *template_p) {
   u_int index = 0;
-  bzero (template_p, sizeof (*template_p));
+  memset (template_p, 0, sizeof (*template_p));
   template_p->h.c.set_id = htons (IPFIX_TEMPLATE_SET_ID);
   template_p->h.c.length = htons (sizeof (struct PSAMP_SOFTFLOWD_TEMPLATE));
   template_p->h.r.template_id = htons (PSAMP_SOFTFLOWD_TEMPLATE_ID);

+ 100 - 0
softflowctl.md

@@ -0,0 +1,100 @@
+* * *
+
+SOFTFLOWCTL(8) BSD System Manager's Manual SOFTFLOWCTL(8)
+
+**NAME**
+
+**softflowctl** -- Remote control program for softflowd
+
+**SYNOPSIS**
+
+**softflowctl** [ **-h** ] [ **-c  ** _ctl_sock_ ] _command_
+
+**DESCRIPTION**
+
+**softflowctl** is a remote control program used to control a running
+softflowd(8) daemon.
+
+The command line options are as follows:
+
+**-c** _ctlsock_
+
+Specify an alternate location for the remote control socket. Default is
+_/var/run/softflowd.ctl_
+
+**-h**
+
+Display command line usage information.
+
+**COMMANDS** _  
+shutdown_
+
+Ask softflowd(8) to gracefully exit. This is equivalent to sending it a
+SIGTERM or SIGINT.
+
+_exit_
+
+Ask softflowd(8) to immediately exit. No flow expiry processing or data export
+is performed.
+
+_expire-all_
+
+Immediately expire all tracked flows.
+
+_delete-all_
+
+Immediately delete all tracked flows. No flow expiry processing or data export
+is performed.
+
+_statistics_
+
+Return statistics collected by softflowd(8) on expired flows.
+
+_debug+_
+
+Increase the debugging level of softflowd(8)
+
+_debug-_
+
+Decrease the debugging level.
+
+_stop-gather_
+
+Stops network data collection by softflowd(8).
+
+_start-gather_
+
+Resumes network data collection.
+
+_dump-flows_
+
+Return information on all tracked flows.
+
+_timeouts_
+
+Print information on flow timeout parameters.
+
+_send-template_
+
+Resend a NetFlow v.9 template record before the next flow export. Has no
+effect for other flow export versions.
+
+**BUGS**
+
+All times are unconditionally displayed in UTC, regardless of the system
+timezone. Please report bugs in softflowctl to
+https://github.com/irino/softflowd/issues
+
+**AUTHORS**
+
+Damien Miller <djm@mindrot.org>  
+Hitoshi Irino (current maintainer) <irino@sfc.wide.ad.jp>
+
+**SEE ALSO**
+
+softflowd(8)
+
+BSD October 18, 2002 BSD
+
+* * *
+

BIN
softflowctl.pdf


+ 18 - 3
softflowd.8

@@ -21,7 +21,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd July 15, 2019
+.Dd November 17, 2019
 .Dt SOFTFLOWD 8
 .Os
 .Sh NAME
@@ -29,7 +29,7 @@
 .Nd Traffic flow monitoring
 .Sh SYNOPSIS
 .Nm softflowd
-.Op Fl 6dDhbal
+.Op Fl 6dDhbalN
 .Op Fl L Ar hoplimit
 .Op Fl T Ar track_level
 .Op Fl c Ar ctl_sock
@@ -52,6 +52,8 @@
 .Op Fl s Ar sampling_rate
 .Op Fl C Ar capture_length
 .Op Fl R Ar receive_port
+.Op Fl S Ar send_interface_name
+.Op Fl x Ar number_of_mpls_labels
 .Op bpf_expression
 .Sh DESCRIPTION
 .Nm
@@ -74,7 +76,9 @@ However, too few statistics are collected to make this
 mode really useful for anything other than debugging.
 .Pp
 Network traffic may be obtained by listening on a promiscuous network
-interface or by reading stored
+interface (unless the
+.Fl N
+option is given) or by reading stored
 .Xr pcap 3
 files, such as those written by
 .Xr tcpdump 8 .
@@ -126,6 +130,9 @@ The destination port may be a portname listed in
 .Xr services 5
 or a numeric port.
 Comma can be used for specifying multiple destinations.
+.It Fl N
+Do not put the interface into promiscuous mode. Note that the interface
+might be in promiscuous mode for some other reason.
 .It Fl i Xo
 .Sm off
 .Oo Ar if_ndx : Oc
@@ -205,12 +212,16 @@ This implies the
 and
 .Fl 6
 flags and turns on additional debugging output.
+.It Fl B Ar size_bytes
+Libpcap buffer size in bytes
 .It Fl b
 Bidirectional mode in IPFIX (-b work with -v 10)
 .It Fl a
 Adjusting time for reading pcap file (-a work with -r)
 .It Fl l
 Load balancing mode for multiple destinations which are specified with -n
+.It Fl x Ar number_of_mpls_labels
+specify number of mpls labels for export 
 .It Fl h
 Display command-line usage information.
 .It Fl L Ar hoplimit
@@ -260,6 +271,10 @@ Specify periodical sampling rate (denominator).
 Specify length for packet capture (snaplen).
 .It Fl R Ar receive_port
 Specify port number for PSAMP receive mode.
+.It Fl S Ar send_interface_name
+Specify send interface name.
+(This option works on Linux only because of use of SO_BINDTODEVICE for
+setsockopt.)
 .El
 .Pp
 Any further command-line arguments will be concatenated together and

+ 158 - 26
softflowd.c

@@ -53,6 +53,9 @@
 #include "ipfix.h"
 #include "psamp.h"
 #include <pcap.h>
+#ifdef LINUX
+#include <net/if.h>
+#endif /* LINUX */
 
 #define IPFIX_PORT 4739
 
@@ -158,7 +161,7 @@ sighand_other (int signum) {
 static int
 flow_compare (struct FLOW *a, struct FLOW *b) {
   /* Be careful to avoid signed vs unsigned issues here */
-  int r;
+  int r, i;
   if (track_level == TRACK_FULL_VLAN || track_level == TRACK_FULL_VLAN_ETHER) {
     if (a->vlanid[0] != b->vlanid[0])
       return (a->vlanid[0] > b->vlanid[0] ? 1 : -1);
@@ -203,6 +206,13 @@ flow_compare (struct FLOW *a, struct FLOW *b) {
   if (a->port[1] != b->port[1])
     return (ntohs (a->port[1]) > ntohs (b->port[1]) ? 1 : -1);
 
+  if (a->mplsLabelStackDepth != b->mplsLabelStackDepth)
+    return (a->mplsLabelStackDepth > b->mplsLabelStackDepth ? 1 : -1);
+  for (i = 0; i < a->mplsLabelStackDepth; i++) {
+    if (a->mplsLabels[i] != b->mplsLabels[i])
+      return (a->mplsLabels[i] > b->mplsLabels[i] ? 1 : -1);
+  }
+
   return (0);
 }
 
@@ -293,7 +303,7 @@ format_ethermac (uint8_t ethermac[6]) {
 static const char *
 format_flow (struct FLOW *flow) {
   char addr1[64], addr2[64], start_time[32], fin_time[32];
-  static char buf[1024];
+  static char buf[4096];
 
   inet_ntop (flow->af, &flow->addr[0], addr1, sizeof (addr1));
   inet_ntop (flow->af, &flow->addr[1], addr2, sizeof (addr2));
@@ -326,7 +336,7 @@ format_flow (struct FLOW *flow) {
 static const char *
 format_flow_brief (struct FLOW *flow) {
   char addr1[64], addr2[64];
-  static char buf[1024];
+  static char buf[4096];
 
   inet_ntop (flow->af, &flow->addr[0], addr1, sizeof (addr1));
   inet_ntop (flow->af, &flow->addr[1], addr2, sizeof (addr2));
@@ -524,6 +534,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
   if (flow->octets[0] > (1U << 31) || flow->octets[1] > (1U << 31)) {
     flow->expiry->expires_at = 0;
     flow->expiry->reason = R_OVERBYTES;
+    flow->flowEndReason = IPFIX_flowEndReason_lackOfResource;
     goto out;
   }
 
@@ -533,6 +544,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
       ft->param.maximum_lifetime) {
     flow->expiry->expires_at = 0;
     flow->expiry->reason = R_MAXLIFE;
+    flow->flowEndReason = IPFIX_flowEndReason_activeTimeout;
     goto out;
   }
 
@@ -543,6 +555,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
       flow->expiry->expires_at = flow->flow_last.tv_sec +
         ft->param.tcp_rst_timeout;
       flow->expiry->reason = R_TCP_RST;
+      flow->flowEndReason = IPFIX_flowEndReason_endOfFlow;
       goto out;
     }
     /* Finished TCP flows */
@@ -551,6 +564,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
       flow->expiry->expires_at = flow->flow_last.tv_sec +
         ft->param.tcp_fin_timeout;
       flow->expiry->reason = R_TCP_FIN;
+      flow->flowEndReason = IPFIX_flowEndReason_endOfFlow;
       goto out;
     }
 
@@ -559,6 +573,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
       flow->expiry->expires_at = flow->flow_last.tv_sec +
         ft->param.tcp_timeout;
       flow->expiry->reason = R_TCP;
+      flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
       goto out;
     }
   }
@@ -567,6 +582,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
     /* UDP flows */
     flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.udp_timeout;
     flow->expiry->reason = R_UDP;
+    flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
     goto out;
   }
 
@@ -577,6 +593,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
     flow->expiry->expires_at = flow->flow_last.tv_sec +
       ft->param.icmp_timeout;
     flow->expiry->reason = R_ICMP;
+    flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
     goto out;
   }
 
@@ -584,6 +601,7 @@ flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) {
   flow->expiry->expires_at = flow->flow_last.tv_sec +
     ft->param.general_timeout;
   flow->expiry->reason = R_GENERAL;
+  flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
 
 out:
   if (ft->param.maximum_lifetime != 0 && flow->expiry->expires_at != 0) {
@@ -610,13 +628,13 @@ out:
  * (the actual expiry is performed elsewhere)
  */
 static int
-process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af,
+process_packet (struct FLOWTRACK *ft, const u_int8_t * frame_data, int af,
                 const u_int32_t caplen, const u_int32_t len,
                 struct ether_header *ether, u_int16_t vlanid,
-                const struct timeval *received_time) {
+                const struct timeval *received_time, u_int8_t num_label) {
   struct FLOW tmp, *flow;
-  int frag, ndx;
-
+  int frag, ndx, i;
+  const u_int8_t *pkt = frame_data + num_label * 4;
   /* Convert the IP packet to a flow identity */
   memset (&tmp, 0, sizeof (tmp));
   switch (af) {
@@ -659,6 +677,11 @@ process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af,
     break;
   }
 
+  tmp.mplsLabelStackDepth = num_label;
+  for (i = 0; i < num_label && i < 10; i++) {
+    tmp.mplsLabels[i] = *(((u_int32_t *) frame_data) + i);
+  }
+
   /* If a matching flow does not exist, create and insert one */
   if ((flow = FLOW_FIND (FLOWS, &ft->flows, &tmp)) == NULL) {
     /* Allocate and fill in the flow */
@@ -681,6 +704,7 @@ process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af,
     /* Must be non-zero (0 means expire immediately) */
     flow->expiry->expires_at = 1;
     flow->expiry->reason = R_GENERAL;
+    flow->flowEndReason = IPFIX_flowEndReason_idleTimeout;
     EXPIRY_INSERT (EXPIRIES, &ft->expiries, flow->expiry);
 
     ft->param.num_flows++;
@@ -708,7 +732,7 @@ process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af,
  * Subtract two timevals. Returns (t1 - t2) in milliseconds.
  */
 u_int32_t
-timeval_sub_ms (const struct timeval * t1, const struct timeval * t2) {
+timeval_sub_ms (const struct timeval *t1, const struct timeval *t2) {
   struct timeval res;
 
   res.tv_sec = t1->tv_sec - t2->tv_sec;
@@ -1187,7 +1211,8 @@ dump_flows (struct FLOWTRACK *ft, FILE * out) {
  */
 static int
 datalink_check (int linktype, const u_int8_t * pkt, u_int32_t caplen, int *af,
-                struct ether_header **ether, u_int16_t * vlanid) {
+                struct ether_header **ether, u_int16_t * vlanid,
+                u_int8_t * num_label) {
   int i, j;
   u_int32_t frametype;
   int vlan_size = 0;
@@ -1221,6 +1246,11 @@ datalink_check (int linktype, const u_int8_t * pkt, u_int32_t caplen, int *af,
         *vlanid <<= 8;
         *vlanid |= pkt[j + dl->skiplen];
       }
+      /* 
+       * Mask out the PCP and DEI values,
+       * leaving just the VID.
+       */
+      *vlanid &= 0xFFF;
       vlan_size = 4;
     }
   }
@@ -1243,7 +1273,21 @@ datalink_check (int linktype, const u_int8_t * pkt, u_int32_t caplen, int *af,
     *af = AF_INET;
   else if (frametype == dl->ft_v6)
     *af = AF_INET6;
-  else
+  else if (frametype == ETH_P_MPLS_UC && num_label != NULL) {
+    u_int32_t shim = 0;
+    u_int8_t ip_version = 0;
+    do {
+      shim = *((u_int32_t *) (pkt + dl->skiplen + vlan_size) + *num_label);
+      *num_label += 1;
+    } while (!((ntohl (shim) & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT));
+    ip_version = (pkt[dl->skiplen + vlan_size + *num_label * 4] & 0xf0) >> 4;
+    if (ip_version == 4)
+      *af = AF_INET;
+    else if (ip_version == 6)
+      *af = AF_INET6;
+    else
+      return (-1);
+  } else
     return (-1);
 
   return (dl->skiplen + vlan_size);
@@ -1261,6 +1305,8 @@ flow_cb (u_char * user_data, const struct pcap_pkthdr *phdr,
   struct timeval tv;
   u_int16_t vlanid = 0;
   struct ether_header *ether = NULL;
+  u_char *mpls_hdr = NULL;
+  u_int8_t num_label = 0;
 
   if (cb_ctxt->ft->param.total_packets == 0) {
     if (cb_ctxt->ft->param.adjust_time) {
@@ -1283,7 +1329,7 @@ flow_cb (u_char * user_data, const struct pcap_pkthdr *phdr,
   }
 
   s = datalink_check (cb_ctxt->linktype, pkt, phdr->caplen, &af, &ether,
-                      &vlanid);
+                      &vlanid, &num_label);
   if (s < 0 || (!cb_ctxt->want_v6 && af == AF_INET6)) {
     cb_ctxt->ft->param.non_ip_packets++;
     cb_ctxt->ft->param.total_packets--;
@@ -1291,7 +1337,8 @@ flow_cb (u_char * user_data, const struct pcap_pkthdr *phdr,
     tv.tv_sec = phdr->ts.tv_sec;
     tv.tv_usec = phdr->ts.tv_usec;
     if (process_packet (cb_ctxt->ft, pkt + s, af, phdr->caplen - s,
-                        phdr->len - s, ether, vlanid, &tv) == PP_MALLOC_FAIL)
+                        phdr->len - s, ether, vlanid, &tv,
+                        num_label) == PP_MALLOC_FAIL)
       cb_ctxt->fatal = 1;
   }
   if (cb_ctxt->ft->param.adjust_time)
@@ -1471,6 +1518,19 @@ recvsock (uint16_t portnumber) {
   return rsock;
 }
 
+#ifdef LINUX
+static void
+bind_device (int sock, char *ifname) {
+  struct ifreq ifr;
+  memset (&ifr, 0, sizeof (ifr));
+  strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+  if (setsockopt
+      (sock, SOL_SOCKET, SO_BINDTODEVICE, (void *) &ifr, sizeof (ifr)) < 0) {
+    perror ("SO_BINDTODEVICE failed");
+  }
+}
+#endif /* LINUX */
+
 static int
 connsock (struct sockaddr_storage *addr, socklen_t len, int hoplimit,
           int protocol) {
@@ -1566,21 +1626,44 @@ unix_listener (const char *path) {
 
 static void
 setup_packet_capture (struct pcap **pcap, int *linktype,
-                      char *dev, char *capfile, char *bpf_prog, int need_v6) {
+                      char *dev, char *capfile, char *bpf_prog, int need_v6,
+                      int promisc, int buffer_size_override) {
   char ebuf[PCAP_ERRBUF_SIZE];
   struct bpf_program prog_c;
   u_int32_t bpf_mask, bpf_net;
+  int res;
 
   /* Open pcap */
   if (dev != NULL) {
     if (!snaplen)
       snaplen = need_v6 ? LIBPCAP_SNAPLEN_V6 : LIBPCAP_SNAPLEN_V4;
-    if ((*pcap = pcap_open_live (dev, snaplen, 1, 0, ebuf)) == NULL) {
-      fprintf (stderr, "pcap_open_live: %s\n", ebuf);
+    if ((*pcap = pcap_create (dev, ebuf)) == NULL) {
+      fprintf (stderr, "pcap_create: %s\n", ebuf);
+      exit (1);
+    }
+    if ((res = pcap_set_snaplen (*pcap, snaplen)) != 0) {
+      fprintf (stderr, "pcap_set_snaplen: %s\n", pcap_geterr (*pcap));
       exit (1);
     }
+    if ((res = pcap_set_promisc (*pcap, promisc)) != 0) {
+      fprintf (stderr, "pcap_set_promisc: %s\n", pcap_geterr (*pcap));
+      exit (1);
+    }
+    if ((res = pcap_set_timeout (*pcap, 0)) != 0) {
+      fprintf (stderr, "pcap_set_timeout: %s\n", pcap_geterr (*pcap));
+      exit (1);
+    }
+    if (buffer_size_override > 0)
+      if ((res = pcap_set_buffer_size (*pcap, buffer_size_override)) != 0) {
+        fprintf (stderr, "pcap_set_buffer_size: %s\n", pcap_geterr (*pcap));
+        exit (1);
+      }
     if (pcap_lookupnet (dev, &bpf_net, &bpf_mask, ebuf) == -1)
       bpf_net = bpf_mask = 0;
+    if ((res = pcap_activate (*pcap)) != 0) {
+      fprintf (stderr, "pcap_activate: %s\n", pcap_geterr (*pcap));
+      exit (1);
+    }
   } else {
     if ((*pcap = pcap_open_offline (capfile, ebuf)) == NULL) {
       fprintf (stderr, "pcap_open_offline(%s): %s\n", capfile, ebuf);
@@ -1589,7 +1672,7 @@ setup_packet_capture (struct pcap **pcap, int *linktype,
     bpf_net = bpf_mask = 0;
   }
   *linktype = pcap_datalink (*pcap);
-  if (datalink_check (*linktype, NULL, 0, NULL, NULL, NULL) == -1) {
+  if (datalink_check (*linktype, NULL, 0, NULL, NULL, NULL, NULL) == -1) {
     fprintf (stderr, "Unsupported datalink type %d\n", *linktype);
     exit (1);
   }
@@ -1701,6 +1784,7 @@ usage (void) {
            "  -P udp|tcp|sctp         Specify transport layer protocol for exporting packets\n"
            "  -A sec|milli|micro|nano Specify absolute time format form exporting records\n"
            "  -s sampling_rate        Specify periodical sampling rate (denominator)\n"
+           "  -B bytes                Libpcap buffer size in bytes\n"
            "  -b                      Bidirectional mode in IPFIX (-b work with -v 10)\n"
            "  -a                      Adjusting time for reading pcap file (-a work with -r)\n"
            "  -C capture_length       Specify length for packet capture (snaplen)\n"
@@ -1709,6 +1793,11 @@ usage (void) {
 #ifdef ENABLE_PTHREAD
            "  -M                      Enable multithread\n"
 #endif /* ENABLE_PTHREAD */
+           "  -N                      Disable promiscuous mode\n"
+#ifdef LINUX
+           "  -S send_interface_name  Specify send interface name\n"
+#endif /* LINUX */
+           "  -x                      Specify number of MPLS labels\n"
            "  -h                      Display this help\n"
            "\n"
            "Valid timeout names and default values:\n"
@@ -1870,23 +1959,25 @@ drop_privs (void) {
     exit (1);
   }
 #if defined(HAVE_SETRESGID)
-  if (setresgid (pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) {
+  if (setresgid (pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
 #elif defined(HAVE_SETREGID)
-  if (setregid (pw->pw_gid, pw->pw_gid) == -1) {
+  if (setregid (pw->pw_gid, pw->pw_gid) == -1)
 #else
-  if (setegid (pw->pw_gid) == -1 || setgid (pw->pw_gid) == -1) {
+  if (setegid (pw->pw_gid) == -1 || setgid (pw->pw_gid) == -1)
 #endif
+  {
     logit (LOG_ERR, "Couldn't set gid (%u): %s",
            (unsigned int) pw->pw_gid, strerror (errno));
     exit (1);
   }
 #if defined(HAVE_SETRESUID)
-  if (setresuid (pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) {
+  if (setresuid (pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
 #elif defined(HAVE_SETREUID)
-  if (setreuid (pw->pw_uid, pw->pw_uid) == -1) {
+  if (setreuid (pw->pw_uid, pw->pw_uid) == -1)
 #else
-  if (seteuid (pw->pw_uid) == -1 || setuid (pw->pw_uid) == -1) {
+  if (seteuid (pw->pw_uid) == -1 || setuid (pw->pw_uid) == -1)
 #endif
+  {
     logit (LOG_ERR, "Couldn't set uid (%u): %s",
            (unsigned int) pw->pw_uid, strerror (errno));
     exit (1);
@@ -1907,9 +1998,13 @@ main (int argc, char **argv) {
   struct CB_CTXT cb_ctxt;
   struct pollfd pl[2];
   struct DESTINATION *dest;
+  int pcap_override_buffer_size = 0;
   int protocol = IPPROTO_UDP;
   int version = 0;
   int rsock = 0, recvport = IPFIX_PORT, recvloop = 0;
+#ifdef LINUX
+  char *send_ifname;
+#endif /* LINUX */
 #ifdef ENABLE_PTHREAD
   int use_thread = 0;
   pthread_t read_thread = 0;
@@ -1917,6 +2012,7 @@ main (int argc, char **argv) {
   pthread_mutex_init (&read_mutex, NULL);
   pthread_cond_init (&read_cond, NULL);
 #endif /* ENABLE_PTHREAD */
+  int use_promisc = 1;
 
   closefrom (STDERR_FILENO + 1);
 
@@ -1935,7 +2031,7 @@ main (int argc, char **argv) {
 
   while ((ch =
           getopt (argc, argv,
-                  "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:baC:lR:M")) != -1) {
+                  "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:B:baC:lR:MNS:x:")) != -1) {
     switch (ch) {
     case '6':
       always_v6 = 1;
@@ -1974,6 +2070,10 @@ main (int argc, char **argv) {
       }
       if (verbose_flag)
         fprintf (stderr, "Using %s (idx: %d)\n", dev, if_index);
+      strncpy (flowtrack.param.option.interfaceName, dev,
+               strlen (dev) <
+               sizeof (flowtrack.param.option.interfaceName) ?
+               strlen (dev) : sizeof (flowtrack.param.option.interfaceName));
       break;
     case 'r':
       if (capfile != NULL || dev != NULL) {
@@ -1984,6 +2084,11 @@ main (int argc, char **argv) {
       capfile = optarg;
       dontfork_flag = 1;
       ctlsock_path = NULL;
+      strncpy (flowtrack.param.option.interfaceName, capfile,
+               strlen (capfile) <
+               sizeof (flowtrack.param.option.interfaceName) ?
+               strlen (capfile) :
+               sizeof (flowtrack.param.option.interfaceName));
       break;
     case 't':
       /* Will exit on failure */
@@ -2064,6 +2169,9 @@ main (int argc, char **argv) {
         flowtrack.param.option.sample = 0;
       }
       break;
+    case 'B':
+      pcap_override_buffer_size = atoi (optarg);
+      break;
     case 'P':
       if (strcasecmp (optarg, "udp") == 0)
         protocol = IPPROTO_UDP;
@@ -2117,6 +2225,23 @@ main (int argc, char **argv) {
       use_thread = 1;
 #endif /* ENABLE_PTHREAD */
       break;
+    case 'N':
+      use_promisc = 0;
+      break;
+#ifdef LINUX
+    case 'S':
+      send_ifname = optarg;
+      break;
+#endif /* LINUX */
+    case 'x':
+      flowtrack.param.max_num_label = atoi (optarg);
+      if (flowtrack.param.max_num_label < 0
+          || flowtrack.param.max_num_label > 10) {
+        fprintf (stderr, "Invalid number of MPLS label\n\n");
+        usage ();
+        exit (1);
+      }
+      break;
     default:
       fprintf (stderr, "Invalid commandline option.\n");
       usage ();
@@ -2136,7 +2261,8 @@ main (int argc, char **argv) {
   /* Will exit on failure */
   if (capfile != NULL || dev != NULL)
     setup_packet_capture (&pcap, &linktype, dev, capfile, bpf_prog,
-                          target.dialect->v6_capable || always_v6);
+                          target.dialect->v6_capable || always_v6,
+                          use_promisc, pcap_override_buffer_size);
   else if (rsock > 0)
     linktype = 1;               //LINKTYPE_ETHERNET
 
@@ -2164,6 +2290,11 @@ main (int argc, char **argv) {
       } else
 #endif
         dest->sock = connsock (&dest->ss, dest->sslen, hoplimit, protocol);
+#ifdef LINUX
+      if (dest->sock > 0 && send_ifname != NULL) {
+        bind_device (dest->sock, send_ifname);
+      }
+#endif /* LINUX */
     }
   }
 
@@ -2216,8 +2347,9 @@ main (int argc, char **argv) {
   for (dest_idx = 0; dest_idx < target.num_destinations; dest_idx++) {
     dest = &target.destinations[dest_idx];
     if (dest->ss.ss_family != 0) {
-      logit (LOG_NOTICE, "Exporting flows to [%s]:%s", dest->hostname,
-             dest->servname);
+      logit (LOG_NOTICE, "Exporting flows from %s to [%s]:%s",
+             flowtrack.param.option.interfaceName,
+             dest->hostname, dest->servname);
     }
   }
   flowtrack.param.option.meteringProcessId = getpid ();

+ 5 - 0
softflowd.h

@@ -102,6 +102,7 @@ struct STATISTIC {
 struct OPTION {
   uint32_t sample;
   pid_t meteringProcessId;
+  char interfaceName[IFNAMSIZ];
 };
 
 struct FLOWTRACKPARAMETERS {
@@ -163,6 +164,7 @@ struct FLOWTRACKPARAMETERS {
   u_int8_t bidirection;
   u_int8_t adjust_time;
   u_int8_t is_psamp;
+  u_int8_t max_num_label;
   struct timeval last_packet_time;
 };
 /*
@@ -216,6 +218,9 @@ struct FLOW {
   u_int16_t vlanid[2];          /* vlanid */
   uint8_t ethermac[2][6];
   u_int8_t protocol;            /* Protocol */
+  u_int8_t flowEndReason;
+  u_int32_t mplsLabelStackDepth;
+  u_int32_t mplsLabels[10];
 };
 
 /*

+ 540 - 0
softflowd.html

@@ -0,0 +1,540 @@
+<!-- Creator     : groff version 1.22.4 -->
+<!-- CreationDate: Sat Aug 13 06:54:00 2022 -->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+<meta name="Content-Style" content="text/css">
+<style type="text/css">
+       p       { margin-top: 0; margin-bottom: 0; vertical-align: top }
+       pre     { margin-top: 0; margin-bottom: 0; vertical-align: top }
+       table   { margin-top: 0; margin-bottom: 0; vertical-align: top }
+       h1      { text-align: center }
+</style>
+<title></title>
+</head>
+<body>
+
+<hr>
+
+
+<p>SOFTFLOWD(8) BSD System Manager&rsquo;s Manual
+SOFTFLOWD(8)</p>
+
+<p style="margin-top: 1em"><b>NAME</b></p>
+
+<p style="margin-left:6%;"><b>softflowd</b> &mdash; Traffic
+flow monitoring</p>
+
+<p style="margin-top: 1em"><b>SYNOPSIS</b></p>
+
+<p style="margin-left:19%;"><b>softflowd</b>
+[<b>-6dDhbalN</b>] [<b>-L&nbsp;</b><i>hoplimit</i>]
+[<b>-T&nbsp;</b><i>track_level</i>]
+[<b>-c&nbsp;</b><i>ctl_sock</i>] [</p>
+
+<p><b>-i&nbsp;</b> [ <i><br>
+if_ndx</i>:]<i>interface</i> ]
+[<b>-m&nbsp;</b><i>max_flows</i>]
+[<b>-n&nbsp;</b><i>host:port</i>]
+[<b>-p&nbsp;</b><i>pidfile</i>]
+[<b>-r&nbsp;</b><i>pcap_file</i>]
+[<b>-t&nbsp;</b><i>timeout_name=seconds</i>]
+[<b>-v&nbsp;</b><i>netflow_version</i>]
+[<b>-P&nbsp;</b><i>transport_protocol</i>]
+[<b>-A&nbsp;</b><i>time_format</i>]
+[<b>-s&nbsp;</b><i>sampling_rate</i>]
+[<b>-C&nbsp;</b><i>capture_length</i>]
+[<b>-R&nbsp;</b><i>receive_port</i>]
+[<b>-S&nbsp;</b><i>send_interface_name</i>]
+[<b>-x&nbsp;</b><i>number_of_mpls_labels</i>]
+[bpf_expression]</p>
+
+<p style="margin-top: 1em"><b>DESCRIPTION</b></p>
+
+<p style="margin-left:6%;"><b>softflowd</b> is a software
+implementation of a flow-based network traffic monitor.
+<b>softflowd</b> reads network traffic and gathers
+information about active traffic flows. A &quot;traffic
+flow&quot; is communication between two IP addresses or (if
+the overlying protocol is TCP or UDP) address/port
+tuples.</p>
+
+<p style="margin-left:6%; margin-top: 1em">The intended use
+of <b>softflowd</b> is as a software implementation of
+Cisco&rsquo;s NetFlow(tm) traffic account system.
+<b>softflowd</b> supports data export using versions 1, 5, 9
+or 10 (a.k.a. IPFIX) of the NetFlow protocol.
+<b>softflowd</b> can also run in statistics-only mode, where
+it just collects summary information. However, too few
+statistics are collected to make this mode really useful for
+anything other than debugging.</p>
+
+<p style="margin-left:6%; margin-top: 1em">Network traffic
+may be obtained by listening on a promiscuous network
+interface (unless the <b>-N</b> option is given) or by
+reading stored pcap(3) files, such as those written by
+tcpdump(8). Traffic may be filtered with an optional bpf(4)
+program, specified on the command-line as
+<i>bpf_expression</i>. <b>softflowd</b> is IPv6 capable and
+will track IPv6 flows if the NetFlow export protocol
+supports it (currently only NetFlow v.9 possesses an IPv6
+export capability).</p>
+
+
+<p style="margin-left:6%; margin-top: 1em"><b>softflowd</b>
+tries to track only active traffic flows. When the flow has
+been quiescent for a period of time it is expired
+automatically. Flows may also be expired early if they
+approach their traffic counts exceed 2 Gib or if the number
+of flows being tracked exceeds <i>max_flows</i> (default:
+8192). In this last case, flows are expired
+oldest-first.</p>
+
+<p style="margin-left:6%; margin-top: 1em">Upon expiry, the
+flow information is accumulated into statistics which may be
+viewed using softflowctl(8). If the <b>-n</b> option has
+been specified the flow information is formatted in a UDP
+datagram which is compatible with versions 1, 5 or 9 of
+Cisco&rsquo;s NetFlow(tm) accounting export format. These
+records are sent to the specified <i>host</i> and
+<i>port</i>. The host may represent a unicast host or a
+multicast group.</p>
+
+<p style="margin-left:6%; margin-top: 1em">The command-line
+options are as follows:</p>
+
+<p style="margin-top: 1em"><b>-n</b> <i>host:port</i></p>
+
+<p style="margin-left:17%;">Specify the <i>host</i> and
+<i>port</i> that the accounting datagrams are to be sent to.
+The host may be specified using a hostname or using a
+numeric IPv4 or IPv6 address. Numeric IPv6 addresses should
+be enclosed in square brackets to avoid ambiguity between
+the address and the port. The destination port may be a
+portname listed in services(5) or a numeric port. Comma can
+be used for specifying multiple destinations.</p>
+
+<p style="margin-top: 1em"><b>-N</b></p>
+
+<p style="margin-left:17%; margin-top: 1em">Do not put the
+interface into promiscuous mode. Note that the interface
+might be in promiscuous mode for some other reason.</p>
+
+<p style="margin-top: 1em"><b>-i</b> <br>
+[ <i><br>
+if_ndx</i>:]<i>interface</i></p>
+
+<p style="margin-left:17%;">Specify a network interface on
+which to listen for traffic. Either the <b>-i</b> or the
+<b>-r</b> options must be specified.</p>
+
+<p style="margin-top: 1em"><b>-r</b> <i>pcap_file</i></p>
+
+<p style="margin-left:17%;">Specify that <b>softflowd</b>
+should read from a pcap(3) packet capture file (such as one
+created with the <b>-w</b> option of tcpdump(8)) file rather
+than a network interface. <b>softflowd</b> processes the
+whole capture file and only expires flows when
+<i>max_flows</i> is exceeded. In this mode, <b>softflowd</b>
+will not fork and will automatically print summary
+statistics before exiting.</p>
+
+<p style="margin-top: 1em"><b>-p</b> <i>pidfile</i></p>
+
+<p style="margin-left:17%;">Specify an alternate location
+to store the process ID when in daemon mode. Default is
+<i>/var/run/softflowd.pid</i></p>
+
+<p style="margin-top: 1em"><b>-c</b> <i>ctlsock</i></p>
+
+<p style="margin-left:17%;">Specify an alternate location
+for the remote control socket in daemon mode. Default is
+<i>/var/run/softflowd.ctl</i></p>
+
+<p style="margin-top: 1em"><b>-m</b> <i>max_flows</i></p>
+
+<p style="margin-left:17%;">Specify the maximum number of
+flows to concurrently track. If this limit is exceeded, the
+flows which have least recently seen traffic are forcibly
+expired. In practice, the actual maximum may briefly exceed
+this limit by a small amount as expiry processing happens
+less frequently than traffic collection. The default is 8192
+flows, which corresponds to slightly less than 800k of
+working data.</p>
+
+<p style="margin-top: 1em"><b>-t</b>
+<i>timeout_name=time</i></p>
+
+<p style="margin-left:17%;">Set the timeout names
+<i>timeout_name</i> to <i>time</i>. Refer to the
+<i>Timeouts</i> section for the valid timeout names and
+their meanings. The <i>time</i> parameter may be specified
+using one of the formats explained in the <i>Time
+Formats</i> section below.</p>
+
+<p style="margin-top: 1em"><b>-d</b></p>
+
+<p style="margin-left:17%; margin-top: 1em">Specify that
+<b>softflowd</b> should not fork and daemonise itself.</p>
+
+<p style="margin-top: 1em"><b>-6</b></p>
+
+<p style="margin-left:17%; margin-top: 1em">Force
+<b>softflowd</b> to track IPv6 flows even if the NetFlow
+export protocol does not support reporting them. This is
+useful for debugging and statistics gathering only.</p>
+
+<p style="margin-top: 1em"><b>-D</b></p>
+
+<p style="margin-left:17%; margin-top: 1em">Places
+<b>softflowd</b> in a debugging mode. This implies the
+<b>-d</b> and <b>-6</b> flags and turns on additional
+debugging output.</p>
+
+<p style="margin-top: 1em"><b>-B</b> <i>size_bytes</i></p>
+
+<p style="margin-left:17%;">Libpcap buffer size in
+bytes</p>
+
+<p style="margin-top: 1em"><b>-b</b></p>
+
+<p style="margin-left:17%; margin-top: 1em">Bidirectional
+mode in IPFIX (-b work with -v 10)</p>
+
+<p style="margin-top: 1em"><b>-a</b></p>
+
+<p style="margin-left:17%; margin-top: 1em">Adjusting time
+for reading pcap file (-a work with -r)</p>
+
+<p style="margin-top: 1em"><b>-l</b></p>
+
+<p style="margin-left:17%; margin-top: 1em">Load balancing
+mode for multiple destinations which are specified with
+-n</p>
+
+<p style="margin-top: 1em"><b>-x</b>
+<i>number_of_mpls_labels</i></p>
+
+<p style="margin-left:17%;">specify number of mpls labels
+for export</p>
+
+<p style="margin-top: 1em"><b>-h</b></p>
+
+<p style="margin-left:17%; margin-top: 1em">Display
+command-line usage information.</p>
+
+<p style="margin-top: 1em"><b>-L</b> <i>hoplimit</i></p>
+
+<p style="margin-left:17%;">Set the IPv4 TTL or the IPv6
+hop limit to <i>hoplimit</i>. <b>softflowd</b> will use the
+default system TTL when exporting flows to a unicast host.
+When exporting to a multicast group, the default TTL will be
+1 (i.e. link-local).</p>
+
+<p style="margin-top: 1em"><b>-T</b> <i>track_level</i></p>
+
+<p style="margin-left:17%;">Specify which flow elements
+<b>softflowd</b> should be used to define a flow.
+<i>track_level</i> may be one of: &ldquo;ether&rdquo; (track
+everything including source and destination addresses,
+source and destination port, source and destination ethernet
+address, vlanid and protocol), &ldquo;vlan&rdquo; (track
+source and destination addresses, source and destination
+port, vlanid and protocol), &ldquo;full&rdquo; (track source
+and destination addresses, source and destination port and
+protocol in the flow, the default), &ldquo;proto&rdquo;
+(track source and destination addresses and protocol), or
+&ldquo;ip&rdquo; (only track source and destination
+addresses). Selecting either of the latter options will
+produce flows with less information in them (e.g. TCP/UDP
+ports will not be recorded). This will cause flows to be
+consolidated, reducing the quantity of output and CPU load
+that <b>softflowd</b> will place on the system at the cost
+of some detail being lost.</p>
+
+<p style="margin-top: 1em"><b>-v</b>
+<i>netflow_version</i></p>
+
+<p style="margin-left:17%;">Specify which version of the
+NetFlow(tm) protocol <b>softflowd</b> should use for export
+of the flow data. Supported versions are 1, 5, 9, 10(IPFIX),
+and psamp. Default is version 5.</p>
+
+<p style="margin-top: 1em"><b>-P</b>
+<i>transport_protocol</i></p>
+
+<p style="margin-left:17%;">Specify transport layer
+protocol for exporting packets. Supported transport layer
+protocols are udp, tcp, and sctp.</p>
+
+<p style="margin-top: 1em"><b>-A</b> <i>time_format</i></p>
+
+<p style="margin-left:17%;">Specify absolute time format
+form exporting records. Supported time formats are sec,
+milli, micro, and nano.</p>
+
+<p style="margin-top: 1em"><b>-s</b>
+<i>sampling_rate</i></p>
+
+<p style="margin-left:17%;">Specify periodical sampling
+rate (denominator).</p>
+
+<p style="margin-top: 1em"><b>-C</b>
+<i>capture_length</i></p>
+
+<p style="margin-left:17%;">Specify length for packet
+capture (snaplen).</p>
+
+<p style="margin-top: 1em"><b>-R</b>
+<i>receive_port</i></p>
+
+<p style="margin-left:17%;">Specify port number for PSAMP
+receive mode.</p>
+
+<p style="margin-top: 1em"><b>-S</b>
+<i>send_interface_name</i></p>
+
+<p style="margin-left:17%;">Specify send interface name.
+(This option works on Linux only because of use of
+SO_BINDTODEVICE for setsockopt.)</p>
+
+<p style="margin-left:6%; margin-top: 1em">Any further
+command-line arguments will be concatenated together and
+applied as a bpf(4) packet filter. This filter will cause
+<b>softflowd</b> to ignore the specified traffic.</p>
+
+<p style="margin-left:6%; margin-top: 1em"><b>Timeouts <br>
+softflowd</b> will expire quiescent flows after
+user-configurable periods. The exact timeout used depends on
+the nature of the flow. The various timeouts that may be set
+from the command-line (using the <b>-t</b> option) and their
+meanings are:</p>
+
+<p style="margin-top: 1em"><i>general</i></p>
+
+<p style="margin-left:17%;">This is the general timeout
+applied to all traffic unless overridden by one of the other
+timeouts.</p>
+
+<p style="margin-top: 1em"><i>tcp</i></p>
+
+<p style="margin-left:17%; margin-top: 1em">This is the
+general TCP timeout, applied to open TCP connections.</p>
+
+<p style="margin-top: 1em"><i>tcp.rst</i></p>
+
+<p style="margin-left:17%;">This timeout is applied to a
+TCP connection when a RST packet has been sent by one or
+both endpoints.</p>
+
+<p style="margin-top: 1em"><i>tcp.fin</i></p>
+
+<p style="margin-left:17%;">This timeout is applied to a
+TCP connection when a FIN packet has been sent by both
+endpoints.</p>
+
+<p style="margin-top: 1em"><i>udp</i></p>
+
+<p style="margin-left:17%; margin-top: 1em">This is the
+general UDP timeout, applied to all UDP connections.</p>
+
+<p style="margin-top: 1em"><i>maxlife</i></p>
+
+<p style="margin-left:17%;">This is the maximum lifetime
+that a flow may exist for. All flows are forcibly expired
+when they pass <i>maxlife</i> seconds. To disable this
+feature, specify a <i>maxlife</i> of 0.</p>
+
+<p style="margin-top: 1em"><i>expint</i></p>
+
+<p style="margin-left:17%; margin-top: 1em">Specify the
+interval between expiry checks. Increase this to group more
+flows into a NetFlow packet. To disable this feature,
+specify a <i>expint</i> of 0.</p>
+
+<p style="margin-left:6%; margin-top: 1em">Flows may also
+be expired if there are not enough flow entries to hold them
+or if their traffic exceeds 2 Gib in either direction.
+softflowctl(8) may be used to print information on the
+average lifetimes of flows and the reasons for their
+expiry.</p>
+
+<p style="margin-left:6%; margin-top: 1em"><b>Time Formats
+<br>
+softflowd</b> command-line arguments that specify time may
+be expressed using a sequence of the form:
+<i>time</i>[<i>qualifier</i>], where <i>time</i> is a
+positive integer value and <i>qualifier</i> is one of the
+following:</p>
+
+<p style="margin-top: 1em"><b>&lt;none&gt;</b></p>
+
+<p style="margin-left:24%; margin-top: 1em">seconds</p>
+
+<p><b>s</b> | <b>S</b></p>
+
+<p style="margin-left:24%; margin-top: 1em">seconds</p>
+
+<p><b>m</b> | <b>M</b></p>