Browse Source

First public version

Vitaly Lavrov 3 years ago
parent
commit
4b10824388
61 changed files with 7415 additions and 874 deletions
  1. 17 7
      .gitignore
  2. 7 2
      INSTALL
  3. 58 0
      README
  4. 347 0
      compile
  5. 228 55
      example/ndpiReader.c
  6. 2 0
      mstring/Makefile
  7. 605 0
      mstring/mstring.c
  8. 8 0
      ndpi-netfilter/.gitignore
  9. 2 0
      ndpi-netfilter/AUTHORS
  10. 339 0
      ndpi-netfilter/COPYING
  11. 229 0
      ndpi-netfilter/INSTALL
  12. 19 0
      ndpi-netfilter/Makefile
  13. 16 3
      ndpi-netfilter/README
  14. 59 0
      ndpi-netfilter/gen_protocols.pl
  15. 1 0
      ndpi-netfilter/include
  16. 18 0
      ndpi-netfilter/ipt/Makefile
  17. 385 0
      ndpi-netfilter/ipt/libxt_ndpi.c
  18. 199 0
      ndpi-netfilter/kernel-patch/v3.10.20.diff
  19. 199 0
      ndpi-netfilter/kernel-patch/v3.12.7.diff
  20. 199 0
      ndpi-netfilter/kernel-patch/v3.14.2.diff
  21. 188 0
      ndpi-netfilter/kernel-patch/v3.14.5.diff
  22. 1 0
      ndpi-netfilter/kernel-patch/v3.18.3.diff
  23. 188 0
      ndpi-netfilter/kernel-patch/v3.4.97.diff
  24. 188 0
      ndpi-netfilter/kernel-patch/v4.0.3.diff
  25. 1 0
      ndpi-netfilter/lib
  26. 172 0
      ndpi-netfilter/src/Makefile
  27. 1747 0
      ndpi-netfilter/src/main.c
  28. 92 0
      ndpi-netfilter/src/xt_ndpi.h
  29. 47 0
      ndpi-netfilter/src/xt_ndpi.h.src
  30. 1 6
      src/include/ndpi_define.h
  31. 1 1
      src/include/ndpi_protocols.h
  32. 13 4
      src/include/ndpi_typedefs.h
  33. 20 0
      src/lib/gen_string.sh
  34. 109 0
      src/lib/ndpi_http_hdr.c.inc
  35. 101 174
      src/lib/ndpi_main.c
  36. 11 9
      src/lib/protocols/aimini.c
  37. 1046 66
      src/lib/protocols/bittorrent.c
  38. 4 4
      src/lib/protocols/crossfire.c
  39. 270 268
      src/lib/protocols/directdownloadlink.c
  40. 2 2
      src/lib/protocols/fasttrack.c
  41. 8 8
      src/lib/protocols/gnutella.c
  42. 47 46
      src/lib/protocols/http.c
  43. 4 4
      src/lib/protocols/icecast.c
  44. 6 6
      src/lib/protocols/imesh.c
  45. 2 2
      src/lib/protocols/ipp.c
  46. 38 37
      src/lib/protocols/irc.c
  47. 1 1
      src/lib/protocols/kakaotalk_voice.c
  48. 48 47
      src/lib/protocols/mail_smtp.c
  49. 5 5
      src/lib/protocols/maplestory.c
  50. 12 12
      src/lib/protocols/meebo.c
  51. 20 20
      src/lib/protocols/msn.c
  52. 1 1
      src/lib/protocols/openft.c
  53. 15 12
      src/lib/protocols/oscar.c
  54. 5 5
      src/lib/protocols/qq.c
  55. 3 3
      src/lib/protocols/steam.c
  56. 9 9
      src/lib/protocols/thunder.c
  57. 2 2
      src/lib/protocols/tvuplayer.c
  58. 2 2
      src/lib/protocols/veohtv.c
  59. 5 5
      src/lib/protocols/world_of_warcraft.c
  60. 24 26
      src/lib/protocols/yahoo.c
  61. 19 20
      src/lib/protocols/zattoo.c

+ 17 - 7
.gitignore

@@ -2,21 +2,29 @@
 *~
 *o.cmd
 *.lo
-*.obj
-*o.cmd
-*.ko
 *.swp
-*.in
-*.la
+*.obj
+
+autom4te.cache
+config.log
+config.status
+example/ndpiReader
+libndpi.pc
+libtool
+/src/lib/Makefile
+/src/include/Makefile
+.deps
 .libs
 .dirstamp
+*.la
 stamp-h1
+/Makefile
+/config.h
+*.in
 /configure
 /config.guess
-/config.h
 /config.h.in
 /config.sub
-/config.log
 /config.status
 /depcomp
 /install-sh
@@ -35,3 +43,5 @@ stamp-h1
 /m4/ltsugar.m4
 /m4/ltversion.m4
 /m4/lt~obsolete.m4
+/aclocal.m4
+/mstring/mstring

+ 7 - 2
INSTALL

@@ -1,8 +1,8 @@
 Installation Instructions
 *************************
 
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
-2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
+Inc.
 
    Copying and distribution of this file, with or without modification,
 are permitted in any medium without royalty provided the copyright
@@ -226,6 +226,11 @@ 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 prerequisites, which makes it generally unusable when shipped
+generated files such as `configure' are involved.  Use GNU `make'
+instead.
+
    On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
 parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
 a workaround.  If GNU CC is not installed, it is therefore recommended

+ 58 - 0
README

@@ -0,0 +1,58 @@
+This directory contains a modified version of OpenDPI which
+includes ntop extensions. I have tried to push them into the
+OpenDPI source tree but nobody in answering emails so I have
+decided to create my own source tree
+
+==========
+
+In order to compile this library do
+
+# ./autogen.sh
+# ./configure
+# make
+
+Please note that the pre-requisites for compilation include:
+- GNU tools (autogen, automake, autoconf, libtool)
+- GNU C compiler (gcc)
+
+==========
+
+The entire procedure of adding new protocols in detail:
+
+1. Add new protocol together with its unique ID to:
+src/include/ndpi_protocols_osdpi.h
+
+2. Create a new protocol in:
+src/lib/protocols/
+
+3. Variables to be kept for the duration of the entire flow (as state variables) needs to be placed in:
+/include/ndpi_structs.h
+in ndpi_flow_tcp_struct (for TCP only), ndpi_flow_udp_struct (for UDP only), or ndpi_flow_struct (for both).
+
+4. Add a new entry for the search function for the new protocol in:
+src/include/ndpi_protocols.h
+
+5. Choose (do not change anything) a selection bitmask from:
+src/include/ndpi_define.h
+
+6. Add a new entry in ndpi_set_protocol_detection_bitmask2 in:
+src/lib/ndpi_main.c
+
+7. Set protocol default ports in ndpi_init_protocol_defaults in:
+src/lib/ndpi_main.c
+
+8. Add the new protocol file to:
+src/lib/Makefile.am
+
+9.  ./autogen.sh
+10. ./configure
+11. make
+
+==========
+
+If you want to distribute a source tar file of nDPI do:
+
+# make dist
+
+--------------------------
+April 2015 - ntop 

+ 347 - 0
compile

@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""	$nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv/,$2, in
+	*,$file_conv,*)
+	  ;;
+	mingw/*)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin/*)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine/*)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+	-o)
+	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
+	  eat=1
+	  case $2 in
+	    *.o | *.[oO][bB][jJ])
+	      func_file_conv "$2"
+	      set x "$@" -Fo"$file"
+	      shift
+	      ;;
+	    *)
+	      func_file_conv "$2"
+	      set x "$@" -Fe"$file"
+	      shift
+	      ;;
+	  esac
+	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-I*)
+	  func_file_conv "${1#-I}" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-l*)
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
+	-L*)
+	  func_cl_dashL "${1#-L}"
+	  ;;
+	-static)
+	  shared=false
+	  ;;
+	-Wl,*)
+	  arg=${1#-Wl,}
+	  save_ifs="$IFS"; IFS=','
+	  for flag in $arg; do
+	    IFS="$save_ifs"
+	    linker_opts="$linker_opts $flag"
+	  done
+	  IFS="$save_ifs"
+	  ;;
+	-Xlinker)
+	  eat=1
+	  linker_opts="$linker_opts $2"
+	  ;;
+	-*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+	  func_file_conv "$1"
+	  set x "$@" -Tp"$file"
+	  shift
+	  ;;
+	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+	  func_file_conv "$1" mingw
+	  set x "$@" "$file"
+	  shift
+	  ;;
+	*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as 'compile cc -o foo foo.c'.
+	# So we strip '-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# 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:

+ 228 - 55
example/ndpiReader.c

@@ -49,8 +49,11 @@
 #include <json.h>
 #endif
 
+#define BT_ANNOUNCE
+
 #include "ndpi_api.h"
 
+extern int bt_parse_debug;
 #include <sys/socket.h>
 
 #define MAX_NUM_READER_THREADS     16
@@ -148,10 +151,12 @@ static struct reader_thread ndpi_thread_info[MAX_NUM_READER_THREADS];
 /**
  * @brief ID tracking
  */
+#if 0
 typedef struct ndpi_id {
   u_int8_t ip[4];				//< Ip address
   struct ndpi_id_struct *ndpi_id;		//< nDpi worker structure
 } ndpi_id_t;
+#endif
 
 static u_int32_t size_id_struct = 0;		//< ID tracking structure size
 
@@ -159,16 +164,23 @@ static u_int32_t size_id_struct = 0;		//< ID tracking structure size
 #define ETH_P_IP 0x0800
 #endif
 
+typedef struct node_id_hdr {
+	struct node_id_hdr *next;
+	struct ndpi_id_struct ndpi_id;
+	u_int32_t use;
+	u_int32_t ip; // + 3 for ipv6
+} ndpi_id_t;
+
 // flow tracking
 typedef struct ndpi_flow {
   u_int32_t lower_ip;
   u_int32_t upper_ip;
-  u_int16_t lower_port;
-  u_int16_t upper_port;
+  u_int16_t lower_port,s_port;
+  u_int16_t upper_port,d_port;
   u_int8_t detection_completed, protocol;
   u_int16_t vlan_id;
   struct ndpi_flow_struct *ndpi_flow;
-  char lower_name[32], upper_name[32];
+  char lower_name[48], upper_name[48]; // for ipv6
 
   u_int64_t last_seen;
 
@@ -180,11 +192,11 @@ typedef struct ndpi_flow {
 
   char host_server_name[256];
 
+  ndpi_id_t *src_id, *dst_id;
   struct {
     char client_certificate[48], server_certificate[48];
   } ssl;
 
-  void *src_id, *dst_id;
 } ndpi_flow_t;
 
 
@@ -433,6 +445,72 @@ static char* ipProto2Name(u_short proto_id) {
   return(proto);
 }
 
+/* ********* node_id alloc/free ************************ */
+
+ndpi_id_t *node_id_hash[256]={0,};
+
+ndpi_id_t *ndpi_id_alloc(u_int32_t ip) {
+ndpi_id_t *n;
+char buf[32];
+int idx = ip & 0xff;
+n = node_id_hash[idx];
+strcpy(buf,inet_ntoa(*((struct in_addr *)&ip)));
+while(n) {
+	if(n->ip == ip) {
+		n->use++;
+//		fprintf(stderr,"%s ip %s use %d\n",__func__,buf,n->use);
+		return n;
+	}
+	n = n->next;
+}
+n = malloc_wrapper(sizeof(ndpi_id_t));
+if(!n) return NULL;
+bzero((char *)n,sizeof(ndpi_id_t));
+n->ip = ip;
+n->use = 1;
+n->next = node_id_hash[idx];
+node_id_hash[idx] = n;
+//fprintf(stderr,"%s ip %s new\n",__func__,buf,n->use);
+return n;
+}
+
+ndpi_id_t *node_id6_hash[256]={0,};
+
+ndpi_id_t *ndpi_id6_alloc(const u_int32_t *ip) {
+ndpi_id_t *n;
+
+char buf[64];
+int idx = ip[3] & 0xff;
+n = node_id6_hash[idx];
+inet_ntop(AF_INET6,ip,buf,sizeof(buf));
+
+while(n) {
+	if(!memcmp(&n->ip,ip,16)) {
+		n->use++;
+//		fprintf(stderr,"%s ip %s use %d\n",__func__,buf,n->use);
+		return n;
+	}
+	n = n->next;
+}
+n = malloc_wrapper(sizeof(ndpi_id_t)+12);
+if(!n) return NULL;
+bzero((char *)n,sizeof(ndpi_id_t)+12);
+memcpy(&n->ip,ip,16);
+n->use = 1;
+n->next = node_id6_hash[idx];
+node_id6_hash[idx] = n;
+//fprintf(stderr,"%s ip %s new\n",__func__,buf,n->use);
+return n;
+}
+
+
+void ndpi_id_free(ndpi_id_t *node) {
+char buf[32];
+strcpy(buf,inet_ntoa(*((struct in_addr *)&(node->ip))));
+	node->use--;
+//fprintf(stderr,"%s ip %s use %d\n",__func__,buf,node->use);
+}
+
 /* ***************************************************** */
 
 /*
@@ -487,8 +565,8 @@ static void printFlow(u_int16_t thread_id, struct ndpi_flow *flow) {
 
     fprintf(out, "\t%s %s:%u <-> %s:%u ",
 	   ipProto2Name(flow->protocol),
-	   flow->lower_name, ntohs(flow->lower_port),
-	   flow->upper_name, ntohs(flow->upper_port));
+	   flow->lower_name, ntohs(flow->s_port),
+	   flow->upper_name, ntohs(flow->d_port));
 
     if(flow->vlan_id > 0) fprintf(out, "[VLAN: %u]", flow->vlan_id);
 
@@ -573,11 +651,11 @@ static void printFlow(u_int16_t thread_id, struct ndpi_flow *flow) {
 
 static void free_ndpi_flow(struct ndpi_flow *flow) {
   if(flow->ndpi_flow) { ndpi_free_flow(flow->ndpi_flow); flow->ndpi_flow = NULL; }
-  if(flow->src_id)    { ndpi_free(flow->src_id); flow->src_id = NULL;       }
-  if(flow->dst_id)    { ndpi_free(flow->dst_id); flow->dst_id = NULL;       }
-
+  if(flow->src_id)    { ndpi_id_free(flow->src_id); flow->src_id = NULL;       }
+  if(flow->dst_id)    { ndpi_id_free(flow->dst_id); flow->dst_id = NULL;       }
 }
 
+
 /* ***************************************************** */
 
 static void ndpi_flow_freer(void *node) {
@@ -712,14 +790,15 @@ static struct ndpi_flow *get_ndpi_flow(u_int16_t thread_id,
 				       struct ndpi_id_struct **src,
 				       struct ndpi_id_struct **dst,
 				       u_int8_t *proto,
-				       const struct ndpi_ip6_hdr *iph6) {
+				       const struct ndpi_ip6_hdr *iph6,
+				       int *dir) {
   u_int32_t idx, l4_offset;
   struct ndpi_tcphdr *tcph = NULL;
   struct ndpi_udphdr *udph = NULL;
   u_int32_t lower_ip;
   u_int32_t upper_ip;
-  u_int16_t lower_port;
-  u_int16_t upper_port;
+  u_int16_t lower_port,s_port=0;
+  u_int16_t upper_port,d_port=0;
   struct ndpi_flow flow;
   void *ret;
   u_int8_t *l3;
@@ -766,7 +845,7 @@ static struct ndpi_flow *get_ndpi_flow(u_int16_t thread_id,
     lower_ip = iph->daddr;
     upper_ip = iph->saddr;
   }
-
+  *dir = 0;
   *proto = iph->protocol;
 
   if(iph->protocol == 6 && l4_packet_len >= 20) {
@@ -774,6 +853,8 @@ static struct ndpi_flow *get_ndpi_flow(u_int16_t thread_id,
 
     // tcp
     tcph = (struct ndpi_tcphdr *) ((u_int8_t *) l3 + l4_offset);
+    s_port = tcph->source;
+    d_port = tcph->dest;
     if(iph->saddr < iph->daddr) {
       lower_port = tcph->source;
       upper_port = tcph->dest;
@@ -795,6 +876,8 @@ static struct ndpi_flow *get_ndpi_flow(u_int16_t thread_id,
     ndpi_thread_info[thread_id].stats.udp_count++;
 
     udph = (struct ndpi_udphdr *) ((u_int8_t *) l3 + l4_offset);
+    s_port = udph->source;
+    d_port = udph->dest;
     if(iph->saddr < iph->daddr) {
       lower_port = udph->source;
       upper_port = udph->dest;
@@ -832,9 +915,14 @@ static struct ndpi_flow *get_ndpi_flow(u_int16_t thread_id,
       }
 
       memset(newflow, 0, sizeof(struct ndpi_flow));
-      newflow->protocol = iph->protocol, newflow->vlan_id = vlan_id;
-      newflow->lower_ip = lower_ip, newflow->upper_ip = upper_ip;
-      newflow->lower_port = lower_port, newflow->upper_port = upper_port;
+      newflow->vlan_id = vlan_id;
+      newflow->protocol = iph->protocol;
+      newflow->lower_ip = lower_ip;
+      newflow->upper_ip = upper_ip;
+      newflow->lower_port = lower_port;
+      newflow->upper_port = upper_port;
+      newflow->s_port = s_port;
+      newflow->d_port = d_port;
 
       if(version == 4) {
 	inet_ntop(AF_INET, &lower_ip, newflow->lower_name, sizeof(newflow->lower_name));
@@ -850,41 +938,53 @@ static struct ndpi_flow *get_ndpi_flow(u_int16_t thread_id,
 	return(NULL);
       } else
 	memset(newflow->ndpi_flow, 0, size_flow_struct);
-
-      if((newflow->src_id = malloc_wrapper(size_id_struct)) == NULL) {
-	printf("[NDPI] %s(3): not enough memory\n", __FUNCTION__);
-	free(newflow);
-	return(NULL);
-      } else
-	memset(newflow->src_id, 0, size_id_struct);
-
-      if((newflow->dst_id = malloc_wrapper(size_id_struct)) == NULL) {
-	printf("[NDPI] %s(4): not enough memory\n", __FUNCTION__);
-	free(newflow);
-	return(NULL);
-      } else
-	memset(newflow->dst_id, 0, size_id_struct);
+      if(version == 4) {
+	      if((newflow->src_id = ndpi_id_alloc(iph->saddr)) == NULL) {
+		printf("[NDPI] %s(3): not enough memory\n", __FUNCTION__);
+		return(NULL);
+	      } 
+
+	      if((newflow->dst_id = ndpi_id_alloc(iph->daddr)) == NULL) {
+		printf("[NDPI] %s(4): not enough memory\n", __FUNCTION__);
+		return(NULL);
+	      }
+      } else {
+      	      if((newflow->src_id = ndpi_id6_alloc(&iph6->ip6_src.__u6_addr.__u6_addr32[0])) == NULL) {
+		printf("[NDPI] %s(3): not enough memory\n", __FUNCTION__);
+		return(NULL);
+	      } 
+
+	      if((newflow->dst_id = ndpi_id6_alloc(&iph6->ip6_dst.__u6_addr.__u6_addr32[0])) == NULL) {
+		printf("[NDPI] %s(4): not enough memory\n", __FUNCTION__);
+		return(NULL);
+	      }
+      }
 
       ndpi_tsearch(newflow, &ndpi_thread_info[thread_id].ndpi_flows_root[idx], node_cmp); /* Add */
       ndpi_thread_info[thread_id].stats.ndpi_flow_count++;
 
-      *src = newflow->src_id, *dst = newflow->dst_id;
-
-      // printFlow(thread_id, newflow);
-
-      return newflow ;
+      *src = &(newflow->src_id)->ndpi_id, *dst = &(newflow->dst_id)->ndpi_id;
+      return(newflow);
     }
   } else {
     struct ndpi_flow *flow = *(struct ndpi_flow**)ret;
-
-    if(flow->lower_ip == lower_ip && flow->upper_ip == upper_ip
-       && flow->lower_port == lower_port && flow->upper_port == upper_port)
-      *src = flow->src_id, *dst = flow->dst_id;
-    else
-      *src = flow->dst_id, *dst = flow->src_id;
-
-    return flow;
+	if(version == 4) {
+	    if(flow->src_id->ip == iph->saddr && flow->dst_id->ip == iph->daddr &&
+		flow->s_port == s_port && flow->d_port == d_port)
+	      *src = &(flow->src_id)->ndpi_id, *dst = &(flow->dst_id)->ndpi_id;
+	    else
+	      *src = &(flow->dst_id)->ndpi_id, *dst = &(flow->src_id)->ndpi_id, *dir = 1;
+	} else {
+	    if( !memcmp(&flow->src_id->ip,&iph6->ip6_src,16) && 
+		!memcmp(&flow->dst_id->ip,&iph6->ip6_dst,16) &&
+		flow->s_port == s_port && flow->d_port == d_port)
+	      *src = &(flow->src_id)->ndpi_id, *dst = &(flow->dst_id)->ndpi_id;
+	    else
+	      *src = &(flow->dst_id)->ndpi_id, *dst = &(flow->src_id)->ndpi_id, *dir = 1;
+	}
+	return flow;
   }
+
 }
 
 /* ***************************************************** */
@@ -895,7 +995,8 @@ static struct ndpi_flow *get_ndpi_flow6(u_int16_t thread_id,
 					u_int16_t ip_offset,
 					struct ndpi_id_struct **src,
 					struct ndpi_id_struct **dst,
-					u_int8_t *proto) {
+					u_int8_t *proto,
+					int *dir) {
   struct ndpi_iphdr iph;
 
   memset(&iph, 0, sizeof(iph));
@@ -913,7 +1014,7 @@ static struct ndpi_flow *get_ndpi_flow6(u_int16_t thread_id,
   return(get_ndpi_flow(thread_id, 6, vlan_id, &iph, ip_offset,
 		       sizeof(struct ndpi_ip6_hdr),
 		       ntohs(iph6->ip6_ctlun.ip6_un1.ip6_un1_plen),
-		       src, dst, proto, iph6));
+		       src, dst, proto, iph6, dir));
 }
 
 /* ***************************************************** */
@@ -930,6 +1031,7 @@ static void setupDetection(u_int16_t thread_id) {
     printf("ERROR: global structure initialization failed\n");
     exit(-1);
   }
+  ndpi_bittorrent_init(ndpi_thread_info[thread_id].ndpi_struct,0,0,0);
 
   /* ndpi_thread_info[thread_id].ndpi_struct->http_dont_dissect_response = 1; */
 
@@ -952,6 +1054,7 @@ static void setupDetection(u_int16_t thread_id) {
 
 /* ***************************************************** */
 
+
 static void terminateDetection(u_int16_t thread_id) {
   int i;
 
@@ -976,14 +1079,16 @@ static unsigned int packet_processing(u_int16_t thread_id,
   struct ndpi_id_struct *src, *dst;
   struct ndpi_flow *flow;
   struct ndpi_flow_struct *ndpi_flow = NULL;
+  int dir = 0;
+//  u_int32_t protocol = 0;
   u_int8_t proto;
 
   if(iph)
     flow = get_ndpi_flow(thread_id, 4, vlan_id, iph, ip_offset, ipsize,
 			 ntohs(iph->tot_len) - (iph->ihl * 4),
-			 &src, &dst, &proto, NULL);
+			 &src, &dst, &proto, NULL, &dir);
   else
-    flow = get_ndpi_flow6(thread_id, vlan_id, iph6, ip_offset, &src, &dst, &proto);
+    flow = get_ndpi_flow6(thread_id, vlan_id, iph6, ip_offset, &src, &dst, &proto, &dir);
 
   if(flow != NULL) {
     ndpi_thread_info[thread_id].stats.ip_packet_count++;
@@ -995,7 +1100,9 @@ static unsigned int packet_processing(u_int16_t thread_id,
     return(0);
   }
 
-  if(flow->detection_completed) return(0);
+  if(flow->detection_completed &&
+	flow->detected_protocol.protocol != NDPI_PROTOCOL_BITTORRENT)
+	return(0);
 
   flow->detected_protocol = ndpi_detection_process_packet(ndpi_thread_info[thread_id].ndpi_struct, ndpi_flow,
 							  iph ? (uint8_t *)iph : (uint8_t *)iph6,
@@ -1041,7 +1148,7 @@ static unsigned int packet_processing(u_int16_t thread_id,
     }
 #endif
 
-    free_ndpi_flow(flow);
+//    free_ndpi_flow(flow);
 
     if(verbose > 1) {
       if(enable_protocol_guess) {
@@ -1051,8 +1158,9 @@ static unsigned int packet_processing(u_int16_t thread_id,
 	}
       }
 
-      printFlow(thread_id, flow);
+//      printFlow(thread_id, flow);
     }
+//    free_ndpi_flow(flow);
   }
 
 #if 0
@@ -1258,7 +1366,50 @@ static void printResults(u_int64_t tot_usec) {
 	printf("\tTraffic throughput:    %s pps / %s/sec\n", formatPackets(t, buf), formatTraffic(b, 1, buf1));
 	printf("\tTraffic duration:      %.3f sec\n", traffic_duration/1000000);
       }
-
+    }
+    printf("\nTraffic statistics:\n");
+    printf("\tEthernet bytes:        %-13llu (includes ethernet CRC/IFC/trailer)\n",
+	   (long long unsigned int)cumulative_stats.total_wire_bytes);
+    printf("\tDiscarded bytes:       %-13llu\n",
+	   (long long unsigned int)cumulative_stats.total_discarded_bytes);
+    printf("\tIP packets:            %-13llu of %llu packets total\n",
+	   (long long unsigned int)cumulative_stats.ip_packet_count,
+	   (long long unsigned int)cumulative_stats.raw_packet_count);
+    /* In order to prevent Floating point exception in case of no traffic*/
+    if(cumulative_stats.total_ip_bytes && cumulative_stats.raw_packet_count)
+      avg_pkt_size = (unsigned int)(cumulative_stats.total_ip_bytes/cumulative_stats.raw_packet_count);
+    printf("\tIP bytes:              %-13llu (avg pkt size %u bytes)\n",
+	   (long long unsigned int)cumulative_stats.total_ip_bytes,avg_pkt_size);
+    printf("\tUnique flows:          %-13u\n", cumulative_stats.ndpi_flow_count);
+
+    printf("\tTCP Packets:           %-13lu\n", (unsigned long)cumulative_stats.tcp_count);
+    printf("\tUDP Packets:           %-13lu\n", (unsigned long)cumulative_stats.udp_count);
+    printf("\tVLAN Packets:          %-13lu\n", (unsigned long)cumulative_stats.vlan_count);
+    printf("\tMPLS Packets:          %-13lu\n", (unsigned long)cumulative_stats.mpls_count);
+    printf("\tPPPoE Packets:         %-13lu\n", (unsigned long)cumulative_stats.pppoe_count);
+    printf("\tFragmented Packets:    %-13lu\n", (unsigned long)cumulative_stats.fragmented_count);
+    printf("\tMax Packet size:       %-13u\n",   cumulative_stats.max_packet_len);
+    printf("\tPacket Len < 64:       %-13lu\n", (unsigned long)cumulative_stats.packet_len[0]);
+    printf("\tPacket Len 64-128:     %-13lu\n", (unsigned long)cumulative_stats.packet_len[1]);
+    printf("\tPacket Len 128-256:    %-13lu\n", (unsigned long)cumulative_stats.packet_len[2]);
+    printf("\tPacket Len 256-1024:   %-13lu\n", (unsigned long)cumulative_stats.packet_len[3]);
+    printf("\tPacket Len 1024-1500:  %-13lu\n", (unsigned long)cumulative_stats.packet_len[4]);
+    printf("\tPacket Len > 1500:     %-13lu\n", (unsigned long)cumulative_stats.packet_len[5]);
+
+    if(tot_usec > 0) {
+      char buf[32], buf1[32];
+      float t = (cumulative_stats.ip_packet_count*1000000ull)/(float)tot_usec;
+      float b = (cumulative_stats.total_wire_bytes * 8 *1000000ull)/(float)tot_usec;
+      u_int64_t traffic_duration;
+      if (live_capture) traffic_duration = tot_usec;
+      else traffic_duration = (pcap_end.tv_sec*1000000ull + pcap_end.tv_usec) - (pcap_start.tv_sec*1000000ull + pcap_start.tv_usec);
+      printf("\tnDPI throughput:       %s pps / %s/sec\n", formatPackets(t, buf), formatTraffic(b, 1, buf1));
+      t = (float)(cumulative_stats.ip_packet_count*1000000ull)/traffic_duration;
+      b = (float)(cumulative_stats.total_wire_bytes * 8 *1000000ull)/traffic_duration;
+      printf("\tTraffic throughput:    %s pps / %s/sec\n", formatPackets(t, buf), formatTraffic(b, 1, buf1));
+      printf("\tTraffic duration:      %.3f sec\n", traffic_duration/1000000.0);
+      if(!live_capture)
+        printf("\tTraffic process:       %.3f sec\n", tot_usec/1000000.0);
       if(enable_protocol_guess)
 	printf("\tGuessed flow protos:   %-13u\n", cumulative_stats.guessed_flow_protocols);
     }
@@ -1517,10 +1668,13 @@ static void openPcapFileOrDevice(u_int16_t thread_id) {
     if((!json_flag) && (!quiet_mode)) printf("Capturing traffic up to %u seconds\n", (unsigned int)capture_for);
 
 #ifndef WIN32
-    alarm(capture_for);
-    signal(SIGALRM, sigproc);
+      alarm(capture_for);
+      signal(SIGALRM, sigproc);
 #endif
   }
+
+  configurePcapHandle(thread_id);
+
 }
 
 /* ***************************************************** */
@@ -1535,6 +1689,10 @@ static void pcap_packet_callback(u_char *args, const struct pcap_pkthdr *header,
   u_int8_t proto = 0, vlan_packet = 0;
   u_int16_t thread_id = *((u_int16_t*)args);
 
+  if(!live_capture) {
+	  if(capture_for == 1 ) return;
+	  if(capture_for > 1) capture_for--;
+  }
   // printf("[ndpiReader] pcap_packet_callback : [%u.%u.%u.%u.%u -> %u.%u.%u.%u.%u]\n", ethernet->h_dest[1],ethernet->h_dest[2],ethernet->h_dest[3],ethernet->h_dest[4],ethernet->h_dest[5],ethernet->h_source[1],ethernet->h_source[2],ethernet->h_source[3],ethernet->h_source[4],ethernet->h_source[5]);
   ndpi_thread_info[thread_id].stats.raw_packet_count++;
 
@@ -1573,8 +1731,21 @@ static void pcap_packet_callback(u_char *args, const struct pcap_pkthdr *header,
   } else if(ndpi_thread_info[thread_id]._pcap_datalink_type == 113 /* Linux Cooked Capture */) {
     type = (packet[14] << 8) + packet[15];
     ip_offset = 16;
-  } else
-    return;
+  } else if(ndpi_thread_info[thread_id]._pcap_datalink_type == 239 /* Linux NFLOG */) {
+    u_int32_t * data = (void *)packet;
+    int xc;
+    ip_offset = 108;
+    type = ETH_P_IP;
+/*    for(xc=0; xc < 48; xc++) {
+	    printf(" %08x%s",htonl(data[xc]),(xc & 7) == 7 ? "\n":"");
+	
+    }
+	  printf("nflog ip_offset %d, type %04x\n",
+			  ip_offset,type); */
+  } else {
+	  printf("unknown link type %02x\n",ndpi_thread_info[thread_id]._pcap_datalink_type);
+    	return;
+  }
 
   while(1) {
     if(type == 0x8100 /* VLAN */) {
@@ -1785,6 +1956,8 @@ int main(int argc, char **argv) {
 
   parseOptions(argc, argv);
 
+  bt_parse_debug = 0;
+
   if((!json_flag) && (!quiet_mode)) {
     printf("\n-----------------------------------------------------------\n"
 	   "* NOTE: This is demo app to show *some* nDPI features.\n"

+ 2 - 0
mstring/Makefile

@@ -0,0 +1,2 @@
+mstring: mstring.c
+	gcc -Wall -g -o $@ $<

+ 605 - 0
mstring/mstring.c

@@ -0,0 +1,605 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef unsigned char u_int8_t;
+typedef unsigned short int u_int16_t;
+
+struct mstring_node {
+	u_int16_t	n, /* N-char cmp */
+				s, /* offset in sbuf */
+				e, /* eq    node */
+				l, /* left  node */
+				r; /* right node */
+};
+#define MAX_MSTR 64
+#define MAX_SBUF 256
+struct mstring_parse {
+	u_int16_t	smin;		/* min string length */
+	u_int16_t	start,last;	/* start node, last node */
+	u_int16_t	ri;			/* index of second char */
+	char		sbuf[MAX_SBUF];	/* all string */
+	u_int16_t	sbuf_len;
+	u_int16_t	nstr;		/* number of strings */
+	u_int16_t	soffs[MAX_MSTR];/* start offset in sbuf */
+	struct mstring_node N[256+MAX_SBUF];
+};
+
+struct mstring_source {
+	char		*str;
+	u_int16_t	value;
+};
+
+static void n_p(struct mstring_parse *s,int i) {
+struct mstring_node *j;
+	j = &s->N[i];
+//	if(!j->s) abort();
+	if(j->n) { 
+		char buf[8];
+		if(s->last && j->e > s->last) sprintf(buf,"(%d)",j->e - s->last);
+		 else sprintf(buf,"%d",j->e);
+		printf("%3d %2d:'%-18.*s' e %4s l %3d r %3d\n",i,j->n,j->n,&s->sbuf[j->s],buf,j->l,j->r);
+	} else
+		printf("%3d %d\n",i,j->s - s->last);
+}
+#if 0
+
+static void n_p_a(struct mstring_parse *s,int c) {
+	int i;
+	printf("---------\n");
+	for(i=1;i < c; i++) {
+		n_p(s,i);
+	}
+}
+
+static void f_print(struct mstring_parse *s,int i,char *str,int last) {
+struct mstring_node *pt;
+	pt = &s->N[i];
+
+//	printf("f_print %d %d %s\n",i,last,str);
+
+	if(pt->l) f_print(s,pt->l,str,last);
+
+	if(pt->e >= last)
+		printf("%s%.*s %d\n",str,pt->n,&s->sbuf[pt->s],pt->e - last);
+	else {
+		if(pt->e) {
+		char buf[128];
+		snprintf(buf,sizeof(buf),"%s%.*s",str,pt->n,&s->sbuf[pt->s]);
+		f_print(s,pt->e,buf,last);
+		}
+	}
+	if(pt->r) f_print(s,pt->r,str,last);
+}
+#endif
+
+static int f_lr(struct mstring_parse *s,int i,int j) {
+	int m;
+	if(i >= j) return i;
+	m = (i+j)/2;
+	if(i < m)
+		s->N[m].l = f_lr(s,i,m);
+
+	if(m+1 < j)
+		s->N[m].r = f_lr(s,m+1,j);
+
+	return m;
+}
+
+static void f_sq(struct mstring_parse *s,int m) {
+	struct mstring_node *j,*n;
+
+	j = &s->N[m];
+	if( !j->n ) return;
+	while(j->e) {
+		n = &s->N[j->e];
+		if( n->l || n->r || !n->n) break;
+		if(j->s + j->n != n->s) {
+				printf("f_sq! m %d e %d s+n %d != %d\n",
+								m,j->e,j->s + j->n , n->s);
+				n_p(s,j->e);
+				abort();
+		}
+		j->n += n->n;
+		j->e = n->e;
+		n->n = 0;
+		n->s = 0;
+		n->e = 0;
+	}
+	if(j->l)
+		f_sq(s,j->l);
+	if(j->r)
+		f_sq(s,j->r);
+	if(j->e && j->n && j->e != m)
+		f_sq(s,j->e);
+}
+
+static void f_eq(struct mstring_parse *s,int m,int p) {
+	struct mstring_node *j,*T;
+	int l=0,r=0,t,t1;
+
+	j = &s->N[m];
+	if( !j->n ) return;
+
+	T = &s->N[0];
+	if(j->l) f_eq(s,j->l,m);
+	if(j->e) f_eq(s,j->e,m);
+	if(j->r) f_eq(s,j->r,m);
+
+	if(m >= s->ri && p >= s->ri) {
+//		printf("f_eq: %d p=%d %s\n",m,p);
+		t = m;
+		while(T[t].l) {
+			l++;
+			t = T[t].l;
+		}
+		t = m;
+		while(T[t].r) {
+			r++;
+			t = T[t].r;
+		}
+		if(abs(l-r) > 1) {
+//			printf("f_eq: l %d r %d\n",l,r);
+//			n_p(s,m);
+			t = m;
+			if(l > r) {
+				while(l > r && r-l > 1) {
+					t1 = T[t].l;
+					l--; r++;
+					if(T[t1].r) break; /* L+R */
+					T[t1].r = t;
+					T[t].l = 0;
+//					printf("f_eq: L  %d -> %d\n",t,t1);
+					t = t1;
+				}
+			} else {
+				while(r > l && r-l > 1) {
+					t1 = T[t].r;
+					r--; l++;
+					if(T[t1].l)  break; /* L+R */
+					T[t1].l = t;
+					T[t].r = 0;
+//					printf("f_eq: R  %d -> %d\n",t,t1);
+					t = t1;
+				}
+			}
+			if(t == m) return; /* L+R ? */
+			do {
+				if(T[p].e == m) {
+//						printf("f_eq: p %d m %d e -> %d\n",p,m,t);
+						T[p].e = t;
+						break;
+				}
+				if(T[p].l == m) {
+//						printf("f_eq: p %d m %d l -> %d\n",p,m,t);
+						T[p].l = t;
+						break;
+				}
+				if(T[p].r == m) {
+//						printf("f_eq: p %d m %d r -> %d\n",p,m,t);
+						T[p].r = t;
+						break;
+				}
+				fprintf(stderr,"%s:%d BUG!\n",__func__,__LINE__);
+				abort();
+			} while(0);
+		}
+	}
+}
+
+int mstring_compile(struct mstring_source *src,size_t nstr,
+				struct mstring_parse *s,
+				char *prefix) {
+u_int8_t NT[256],c;
+struct mstring_node *T,*pt;
+char *B;
+char *sptr;
+
+int i,l,offs,t,j,I,RI,x,n,k;
+
+memset((char *)s,0,sizeof(*s));
+
+T = &s->N[0];
+B = &s->sbuf[0];
+I = 256;
+for(i=0,offs=1; i < nstr; i++) {
+	if(i >= MAX_MSTR) return 1;
+	sptr = src[i].str;
+	if(!sptr) break;
+	l = strlen(sptr);
+	if(!l) return 2;
+
+	if(!s->smin || l < s->smin) s->smin = l;
+
+	/* copy string to sbuf in lowercase */
+	s->soffs[i] = offs;
+	t = 0;
+
+	for(j=0; j < l; j++,offs++) {
+		if(offs >= sizeof(s->sbuf)) return 3;
+		c = *sptr++;
+		if(c >= 'A' && c <= 'Z') c |= 0x20;
+		s->sbuf[offs] = c;
+//		printf("%d:%c t=%d I=%d\n",offs,c,t,I);
+		if(!t) { /* first char in string */
+			if(!T[c].n) {
+				T[c].n = 1;
+				T[c].s = offs;
+				T[c].e = I;
+				t = I;
+			} else {
+				t = T[c].e;
+			}
+			continue;
+		}
+		if(t >= I) { /* append node */
+			I++;
+			T[t].n = 1;
+			T[t].s = offs;
+			T[t].e = I;
+			t = I;
+			continue;
+		}
+		x = (int)c - (int)B[T[t].s];
+		while(1) {
+			if(!x) {
+				t = T[t].e;
+				break;
+			}
+			if(x < 0) {
+				n = T[t].l;
+				if(!n) {
+					T[t].l = I+1;
+				} else {
+					x = (int)c  - (int)B[T[n].s];
+					if(x <= 0) {
+						t = n;
+						continue;
+					}
+					I++;
+					T[I].l = n;
+					T[I].e = I+1;
+					T[I].n = 1;
+					T[I].s = offs;
+					T[t].l = I;
+					t = ++I;
+					break;
+				}
+			} else {
+				n = T[t].r;
+				if(!n) {
+					T[t].r = I+1;
+				} else {
+					x = (int)c - (int)B[T[n].s];
+					if(x >= 0) {
+						t = n;
+						continue;
+					}
+					I++;
+					T[I].r = n;
+					T[I].e = I+1;
+					T[I].n = 1;
+					T[I].s = offs;
+					T[t].r = I;
+					t = ++I;
+					break;
+				}
+			}
+			I++;
+			T[I].e = I+1;
+			T[I].n = 1;
+			T[I].s = offs;
+			t = ++I;
+			break;
+		} /* while(1) */
+	} /* EOL */
+//	printf("EOL t=%d I=%d\n",t,I);
+	T[t].n = 0;
+	T[t].s = src[i].value;
+	if(!T[t].s) T[t].s = i+1;
+	I++;
+} /* strings */
+I++;
+s->nstr = i-1;
+s->sbuf_len=offs;
+s->soffs[i]=offs;
+for(c=1,i=1;i < 256; i++) {
+	if(T[i].n) {
+			T[c++] = T[i];
+	}
+}
+RI = c;
+n = 256-c;
+// printf("RI=%d n = %d\n",RI,n);
+
+for(i=1 ;i < RI; i++) {
+		T[i].e -= n;
+}
+for(i=256; i < I; i++) {
+	T[c] = T[i];
+	if(T[c].n) {
+		if(T[c].e) T[c].e -= n;
+		if(T[c].l) T[c].l -= n;
+		if(T[c].r) T[c].r -= n;
+	}
+	c++;
+}
+I=c;
+
+s->ri = RI;
+s->start = RI >> 1;
+
+if(RI > 2) {
+//	printf("f_lr %d\n",RI-1);
+	f_lr(s,1,RI-1);
+	T[RI-2].r = RI-1;
+}
+
+// n_p_a(s,c);
+
+f_sq(s,s->start);
+
+for(i=1,k=1; i < I; i++) {
+	if(T[i].s) NT[i]=k++;
+}
+
+k = 0;
+for(i=1; i < I; i++) {
+	if(!T[i].s) continue;
+	k = NT[i];
+	T[k] = T[i];
+	pt = &T[k];
+
+	if(pt->l) pt->l = NT[pt->l];
+	if(pt->e) pt->e = NT[pt->e];
+	if(pt->r) pt->r = NT[pt->r];
+}
+I = n = k;
+
+//n_p_a(s,n+1);
+
+//printf("--- RI %d I %d\n",RI,I);
+
+f_eq(s,s->start,0);
+//n_p_a(s,n+1);
+
+for(i=RI,j=I; i < j; i++) {
+	if(T[i].n) continue;
+	while(i < j && !T[j].n) j--;
+	if(i >= j) break;
+//	printf("%d <-> %d\n",i,j);
+	pt = &T[1];
+	for(k=1; k <= j; k++,pt++) {
+		if(pt->e == j) {
+			pt->e = i;
+		} else {
+			if(pt->e == i) pt->e = j;
+		}
+		if(pt->l == j) {
+			pt->l = i;
+		} else {
+			if(pt->l == i) pt->l = j;
+		}
+		if(pt->r == j) {
+			pt->r = i;
+		} else {
+			if(pt->r == i) pt->r = j;
+		}
+	}
+	k = T[i].s;
+	T[i] = T[j];
+	T[j].l = T[j].r = T[j].e = T[j].n = 0;
+	T[j].s = k;
+}
+
+while(i <= I) {
+	if(!T[i].n) break;
+}
+s->last = i;
+//printf("Last %d\n",i);
+for(k=1; k < i; k++) {
+	if(T[k].e >= i) {
+		j = T[ T[k].e ].s;
+		T[k].e = i+j;
+	}
+}
+// n_p_a(s,i);
+//f_print(s,s->start,"",i);
+
+printf(
+"#ifndef MSTRING_ENGINE\n"
+"#define MSTRING_ENGINE\n\n"
+"// typedef unsigned char u_int8_t;\n"
+"// typedef unsigned short int u_int16_t;\n\n"
+"struct mstring_node {\n"
+"	u_int16_t	n, /* N-char cmp */\n"
+"			s, /* offset in sbuf */\n"
+"			l, /* left  node */\n"
+"			r; /* right node */\n"
+"	u_int16_t	e; /* eq    node or exit code */\n"
+"};\n"
+"struct mstring_exec {\n"
+"	u_int16_t	smin;		/* min string length */\n"
+"	u_int16_t	start,last;	/* start node, last node */\n"
+"	u_int16_t	sbuf_len;\n"
+"	u_int16_t	nstr;		/* number of strings */\n"
+"	char		*sbuf;\n"
+"	u_int16_t	*soffs;		/* start offset in sbuf */\n"
+"	struct mstring_node *N;\n"
+"};\n"
+"int mstring_find(struct mstring_exec *s,char *str,int l) {\n"
+"	int c,i,n,x;\n"
+"	char *cs;\n"
+"	struct mstring_node *p;\n"
+"\n"
+"	if(!l) l = strlen(str);\n"
+"	if(l < s->smin) return 0;\n"
+"	i = s->start;\n"
+"	if(!i) return 0;\n"
+"\n"
+"	p = &s->N[i];\n"
+"	n = p->n;\n"
+"	cs = &s->sbuf[p->s];\n"
+"	while(l > 0 && n > 0) {\n"
+"		c = *str++; l--;\n"
+"		if(c >= 'A' && c <= 'Z') c |= 0x20;\n"
+"		do {\n"
+"			x = c  - (int)*cs;\n"
+"			if(!x) {\n"
+"				cs++; n--;\n"
+"				if(n > 0) break;\n"
+"				if( p->e >= s->last) return p->e - s->last;\n"
+"				i = p->e;\n"
+"			} else {\n"
+"				if(n != p->n) return 0;\n"
+"				i = x < 0 ? p->l : p->r;\n"
+"			}\n"
+"			if(!i) return 0;\n"
+"			p = &s->N[i];\n"
+"			n = p->n;\n"
+"			cs = &s->sbuf[p->s];\n"
+"		} while(x);	\n"
+"	}\n"
+"	return 0;\n"
+"}\n"
+"#endif\n"
+);
+printf("/* Source %s\n  mstring %s ",prefix,prefix);
+
+j = 12+strlen(prefix);
+
+for(i=0; i <= s->nstr; i++) {
+	k = s->soffs[i+1]-s->soffs[i];
+	if(j + k+3 > 68 && k < 68-3) {
+			printf("\\\n\t");
+			j = 8;
+	}
+	printf("\"%.*s\" ", k, &s->sbuf[s->soffs[i]]);
+	j += k+3;
+}
+printf("\n\n");
+for(i=0; i <= s->nstr; i++) {
+	printf("\t\"%.*s\",%d\n",
+				s->soffs[i+1]-s->soffs[i],
+				&s->sbuf[s->soffs[i]],
+				src[i].value ? src[i].value:i+1);
+}
+printf(" */\n");
+printf("static char mstring_sbuf_%s[] = \"#%.*s\";\n",prefix,s->sbuf_len,&s->sbuf[1]);
+printf("static u_int16_t mstring_soffs_%s[%d] = {\n\t0,",prefix,s->nstr+3);
+for(k=0; k <= s->nstr+1; k++) {
+	printf("%d%c",s->soffs[k],k == s->nstr+1 ? ' ':',');
+}
+printf("\n};\n");
+printf("static struct mstring_node mstring_node_%s[%d] = {\n\t{0,},\n",prefix,s->last+1);
+
+for(k=1; k < s->last; k++) {
+	printf("\t{ .n = %d, .s = %d, .l = %d, .r = %d, .e = %d }%c\n",
+		T[k].n, T[k].s, T[k].l, T[k].r, T[k].e,
+		k == s->last-1 ? ' ':',');
+}
+printf("};\n");
+printf("struct mstring_exec mstring_data_%s = {\n"
+		"\t.smin = %d,\n"
+		"\t.start = %d, .last = %d,\n"
+		"\t.sbuf_len = %d,\n" 
+		"\t.sbuf = &mstring_sbuf_%s[0],\n"
+		"\t.soffs = mstring_soffs_%s,\n"
+		"\t.N = &mstring_node_%s[0]\n};\n",
+		prefix, s->smin,
+		s->start, s->last,
+		s->sbuf_len,
+		prefix,prefix,prefix);
+
+return 0;
+}
+
+int mstring_find(struct mstring_parse *s,char *str) {
+	int c,l,i,n,x;
+	char *cs;
+
+	l = strlen(str);
+	if(l < s->smin) return 0;
+	i = s->start;
+
+	n = s->N[i].n;
+	cs = &s->sbuf[s->N[i].s];
+
+	while(l > 0 && n > 0) {
+		c = *str++; l--;
+		if(c >= 'A' && c <= 'Z') c |= 0x20;
+		while(1) {	
+			x = c  - (int)*cs;
+			if(!x) {
+				cs++; n--;
+				if(n > 0) break;
+				if(s->N[i].e >= s->last) return s->N[i].e - s->last;
+				i = s->N[i].e;
+			} else {
+				if(n != s->N[i].n) return 0;
+				i = x < 0 ? s->N[i].l : s->N[i].r;
+			}
+			if(!i) return 0;
+			n = s->N[i].n;
+			cs = &s->sbuf[s->N[i].s];
+			if(!x) break;
+		}	
+	}
+	return 0;
+}
+
+struct mstring_source A[]= {
+		{"Content-Encoding:",0},
+		{"Content-Encoder:",0},
+		{"Content-Mime:",0},
+		{"Content-Length:",0},
+		{"Content-Xscope:",0},
+		{"Content-Type:",0},
+		{"Cookie:",0},
+		{"Host:",0},
+		{"Referer:",0},
+		{"Server:",0},
+		{"Transfer-Encoding:",0},
+		{"User-agent:",0},
+		{"X-Forwarded-For:",0},
+		{"X-Session-Type:",0},
+		{"YHost:",0}
+};
+
+
+int main(int argc,char **argv) {
+int i;
+struct mstring_parse s;
+
+if(argc > 3) {
+	struct mstring_source *S = calloc(argc-1,sizeof(struct mstring_source));
+	for(i=2; i < argc; i++) {
+		S[i-2].str = argv[i];
+		S[i-2].value = 0;
+		fprintf(stderr,"%d %s\n",i-1,argv[i]);
+	}
+	i = mstring_compile(S,i-1,&s,argv[1]);
+	if(i)
+		fprintf(stderr,"error: mstring_compile:%d\n",i);
+	exit(i != 0);
+}
+fprintf(stderr,"%s prefix word1 word2 ....\n",argv[0]);
+
+#if 0
+i = argv[1] ? atoi(argv[1]) : 1;
+if(i > sizeof(A)/sizeof(A[0])) i = sizeof(A)/sizeof(A[0]);
+printf("//ret %d\n",mstring_compile(A,i,&s,"hdr")); //sizeof(A)/sizeof(A[0])));
+
+if(argv[2]) {
+	printf("ret %d for %s\n",mstring_find(&s,argv[2]),argv[2]);
+}
+#endif
+
+return 1;
+
+}
+
+
+/* vim: set ts=4: */
+

+ 8 - 0
ndpi-netfilter/.gitignore

@@ -0,0 +1,8 @@
+*.[oa]
+*~
+*o.cmd
+*.[ks]o
+*.mod.c
+/src/.tmp_versions/
+/src/Module.symvers
+/src/modules.order

+ 2 - 0
ndpi-netfilter/AUTHORS

@@ -0,0 +1,2 @@
+G. Elian Gidoni <geg@gnu.org>
+Vitaly Lavrov <vel21ripn@gmail.com>

+ 339 - 0
ndpi-netfilter/COPYING

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 229 - 0
ndpi-netfilter/INSTALL

@@ -0,0 +1,229 @@
+-----------------
+1. Kernel patches
+-----------------
+
+You _must_ apply the patch to the kernel in two cases:
+- Kernel version 3.2 or 3.4.
+- Kernel version 3.10 or higher and requires using extension NF_CONNLABEL.
+In other cases kernel patches not requhired!
+
+Patches are located in the kernel-patch/*.diff
+
+V3.4.97  patch can be applied for 3.4 kernels (tested on 3.4.97+) and possibly to 3.2.
+V3.10.20 patch can be applied to kernel 3.10 (3.11).
+V3.12.7  patch can be applied to kernel 3.12.
+V3.14.4  patch can be applied to kernel 3.14.2-3.14.4
+V3.14.5  patch can be applied to kernel 3.14.5 and higher (3.18 including).
+
+--------------------------------------------------------
+2. The minimum requirements for the kernel configuration
+--------------------------------------------------------
+
+Kernel version >= 3.4 (3.2 not tested)
+
+Networking support  --->
+  Networking options  --->
+  [*] Network packet filtering framework (Netfilter)  --->
+        Core Netfilter Configuration  --->
+          Netfilter connection tracking support (M/Y)
+          Number of custom extend (1) (if patched kernel)
+	  "connlabel" match support (M)
+
+Check your kernel configuration file. For patched kernel there should be:
+
+CONFIG_NF_CONNTRACK=m or y
+CONFIG_NF_CONNTRACK_CUSTOM=1
+
+For non-patched kernel there should be:
+
+CONFIG_NF_CONNTRACK=m or y
+CONFIG_NF_CONNTRACK_LABELS=y
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+
+----------------------
+3. Compile and install
+----------------------
+
+The install the modules follow these steps, always from the modules package
+root (i.e. where this file is located)
+
+Add option KERNEL_DIR=/path/to/kernel if the kernel sources have non-standard location,
+or if you want to compile the module to another kernel configuration.
+
+- To compile the modules first type:
+
+	./autogen.sh
+	cd  ndpi-netfilter
+	make
+
+- Then, as root, type:
+
+        make modules_install
+
+That would install the nDPI module for the given Linux kernel.
+(default /lib/modules/`uname -r`/extra/xt_ndpi.ko)
+
+- Finally, also as root, you should copy the iptables module into the
+  corresponding directory. Usually this is "/lib/xtables" or
+  "/usr/lib/xtables".
+
+        make install
+
+Now you can read the following section to learn how to use it.
+
+---------------
+4. Module usage
+---------------
+
+Once you have installed modules ("libxt_ndpi.so" and "xt_ndpi.ko")
+you should type (as root):
+
+        modprobe xt_ndpi
+
+If the module has been successfully loaded you shouldn't see any message
+(see dmesg for additional info). After loading the kernel module you can
+use iptables to add a rule. To see available protocols you can match for
+in every packet, type:
+
+        iptables -m ndpi --help
+
+Note that the list is long, you best try: "iptables -m ndpi --help | more"
+
+An example rule would be (as root):
+
+        iptables -A OUTPUT -m ndpi --http -j REJECT
+
+This wouldn't allow any HTTP traffic that originates from the machine where the
+rule was added.
+
+------------------------------------------------------------------
+BIG FAT WARNING!
+
+Do not discard all the unknown traffic. Tcp-syn packets are always treated as an
+unknown protocol.
+------------------------------------------------------------------
+
+Using NDPI target. To see available options type:
+
+        iptables -j NDPI --help
+
+NDPI target may be using for packet marking (see MARK target) or packet classify (see CLASSIFY target).
+Values for mark or class may be give from /proc/net/xt_ndpi/proto (see procfs section below) or specified in netfilter rules (--values).
+
+Example (traffic shaper)
+
+-----------------------------------------------------------------
+#
+# HTB setup
+#
+
+/etc/htb/eth0
+DEFAULT=30
+R2Q=160
+DCACHE=no
+
+/etc/htb/eth0-2.root
+RATE=210Mbit
+BURST=20k
+
+/etc/htb/eth0-2:10.high
+RATE=100Mbit
+CEIL=205Mbit
+LEAF=sfq
+
+/etc/htb/eth0-2:20.slow
+RATE=20Mbit
+CEIL=100Mbit
+LEAF=sfq
+
+/etc/htb/eth0-2:30.default
+RATE=80Mbit
+CEIL=210Mbit
+LEAF=sfq
+
+/etc/htb/eth0-2:40.unknown
+RATE=1Mbit
+CEIL=2Mbit
+LEAF=sfq
+-----------------------------------------------------------------
+modprobe xt_ndpi
+# default class 1:30
+echo "all 10030/ffffff" >/proc/net/xt_ndpi/proto
+for i in ssh mail_pop mail_imap mail_smtp mail_pops mail_smtps mail_imaps dns; do
+# high speed class 1:10
+	echo "$i 10010" >/proc/net/xt_ndpi/proto
+done
+for i in bittorrent edonkey ftp_data ; do
+# low speed class 1:20
+	echo "$i 10020" >/proc/net/xt_ndpi/proto
+done
+echo "unknown 10040" >/proc/net/xt_ndpi/proto
+
+#detect incoming traffic
+iptables -t mangle -A PREROUTING -m ndpi --all
+#detect outgoing local traffic
+iptables -t mangle -A OUTPUT -m ndpi --all
+
+#traffic classification
+iptables -t mangle -A POSTROUTING -o eth0 -j NDPI --ndpi-id --set-clsf
+
+----------------
+5. Module unload
+----------------
+
+In case you want to stop using the nDPI kernel module, first remove every
+iptables rule for nDPI and then type (as root):
+
+        conntrack -F && rmmod xt_ndpi
+
+--------------------
+6. Module parameters
+--------------------
+
+log_debug[0]: enable/disable nDPI debug. For developers only!
+
+log_trace[0]: enable/disable nDPI trace. For developers only!
+
+mtu[1520]:    Skip non-linear skb (GRO/LRO) if size > mtu.
+
+bt_log_size[128]: size of log BT announces (kb). 192 bytes per announce.
+
+bt_hash_size[0]:  size of BT hash (2-32) entry*1024
+
+bt_hash_timeout[1200]: Storage time of history BT peers
+                       (not used if bt_hash_size = 0).
+
+---------------
+7. procfs files
+---------------
+
+/proc/net/xt_ndpi/proto - show ID, mark and mask of protocols.
+  Use command "cp /proc/net/xt_ndpi/proto ndpi-proto.setup" for save settings,
+  and "cat ndpi-proto.setup >/proc/net/xt_ndpi/proto" for restore.
+
+  "echo init >/proc/net/xt_ndpi/proto" enable all protocols and set mark by ID and mask 0xff.
+
+  Change mark/mask for protocols:
+  "echo '(protoid|protoname|all|any) mark[/mask]' >/proc/net/xt_ndpi/proto"
+
+  The prohibition detection protocol:
+  "echo '(protoid|protoname) disable' >/proc/net/xt_ndpi/proto"
+
+  protoid, mark and mask is hex-value.
+
+  !!! We must disable protocols before first using it in netfilter !!!
+
+  Examples:
+  echo all 0/ff >/proc/net/xt_ndpi/proto
+  echo http 1 >/proc/net/xt_ndpi/proto
+  echo http_proxy 1 >/proc/net/xt_ndpi/proto
+  echo 83 1 >/proc/net/xt_ndpi/proto
+
+/proc/net/xt_ndpi/announce - show BT announces (parse DHT)
+
+/proc/net/xt_ndpi/info[6] - statistics about BT hash. For debug and development.
+
+  "cat /proc/net/xt_ndpi/info" show number of elements in hash list.
+  "echo XXX >/proc/net/xt_ndpi/info && cat /proc/net/xt_ndpi/info" - show ip/port in selected hash list"
+  "echo -1 >/proc/net/xt_ndpi/info" - restore view common info
+

+ 19 - 0
ndpi-netfilter/Makefile

@@ -0,0 +1,19 @@
+all:
+	$(MAKE) -C ipt
+	$(MAKE) -C src
+incl:	src/xt_ndpi.h
+
+
+src/xt_ndpi.h: include/ndpi_protocol_ids.h src/xt_ndpi.h.src 
+	perl ./gen_protocols.pl $@ $^ 
+
+modules_install:
+	$(MAKE) -C src modules_install
+install:
+	$(MAKE) -C ipt install
+clean:
+	$(MAKE) -C src clean
+	$(MAKE) -C ipt clean
+distclean:
+	$(MAKE) clean
+	$(MAKE) -C src distclean

+ 16 - 3
ndpi-netfilter/README

@@ -1,4 +1,17 @@
-This package is a GPL implementation of an iptables and netfilter module for
-nDPI integration into the Linux kernel.
+The major differences
+
+1. The change in the structure of "ndpi_int_one_line_struct" field "u8 * ptr" to "u16 offs".
+This allows you to make the size of the data structure of 4 bytes, regardless of bit processors.
+If we use the pointer, the size of the structure will increase to 8 bytes for x86 and up to 16 bytes for x86_64.
+This allows reducing the size of the structure ndpi_flow_struct 27% for x86 or 53% for x86_64.
+This is big changes of code!
+
+2. Sequential string comparisons in the search replaced by a finite automaton.
+In the catalog ../mstring source code generator is the search tree.
+Script "../src/lib/gen_string.sh" creates a data structure to search for these keywords.
+
+3. Using the tracking system connections (flows) conntrack/netfilter instead of a similar system in nDPI. The tracking system connections implemented in the conntrack/netfilter more accurate.  
+
+4. Added the ability to parse the DHT messages BitTorrent protocol to detect connections with encryption. It uses hash-table. To enable analysis of DHT messages, when the module is loaded xt_ndpi specify two parameters: bt_hash_size and bt_hash_timeout.
+By default analysis DHT messages off.
 
-https://github.com/ewildgoose/ndpi-netfilter

+ 59 - 0
ndpi-netfilter/gen_protocols.pl

@@ -0,0 +1,59 @@
+#!/usr/bin/perl -w
+use English;
+
+my @P;
+my %N;
+my $m=0;
+my ($n,$p);
+die "$PROGRAM_NAME dstfile src.h .h.src\n" 
+  if !defined $ARGV[0] || !defined $ARGV[1] || !defined $ARGV[2] ||
+ ! -f $ARGV[1] || ! -f $ARGV[2];
+
+die "BUG1" if !open(F,'<'.$ARGV[1]);
+
+while(<F>) {
+	next if !/^\s*#define\s+NDPI_(CONTENT|SERVICE|PROTOCOL)_(\S+)\s+(\d+)(\s+|$)/;
+	next if $2 eq "HISTORY_SIZE";
+	($p,$n) = ($2,$3);
+#	print "$p $n\n";
+	die "BUG! $p ($n) redefined $P[$n]" if defined $P[$n];
+	$P[$n]=$p;
+	$N{$p}=$n;
+	$m = $n if $n > $m;
+}
+
+my @L=(0,0,0,0,0,0);
+for($n=0; $n <= $m; $n++) {
+	$i = !$n ? 0 : ($n % 5);
+	$p = defined $P[$n] ? lc($P[$n]):"badproto_${n}";
+	$p =~ s/http_application_/http_app_/;
+	$P[$n] = $p;
+	$p = length($p);
+	$L[$i] = $p if $p > $L[$i];
+}
+close(F);
+die "BUG2" if !open(F,'<'.$ARGV[2]);
+die "BUG3" if !open(O,'>'.$ARGV[0]);
+print O "/*  Don't edit this file! Source file $ARGV[2] */\n\n";
+while(<F>) {
+	if(!/__SUB__/) {
+		print O $_;;
+		next;
+	}
+	print O "#define NDPI_PROTOCOL_SHORT_STRING \"unknown\",	";
+	for($n=1; $n <= $m; $n++) {
+		$i = !$n ? 0 : ($n % 5);
+		$s = '"'.$P[$n].'"';
+		if($n == $m) {
+			$s .= "\n";
+		} else {
+			$s .= "," . ($i ? sprintf("%.*s",$L[$i]+3-length($s),"                   "):"\\\n");
+		}
+
+		print O $s;
+	}
+	print O "#define NDPI_PROTOCOL_MAXNUM $m\n";
+}
+close(O);
+close(F);
+exit(0);

+ 1 - 0
ndpi-netfilter/include

@@ -0,0 +1 @@
+../src/include/

+ 18 - 0
ndpi-netfilter/ipt/Makefile

@@ -0,0 +1,18 @@
+NDPI_PATH2 := ${NDPI_PATH}/src
+NDPI_SRC := ..
+NDPI_PRO := ${NDPI_SRC}/lib/protocols
+XTBL := $(shell pkg-config --variable=xtlibdir xtables)
+
+CFLAGS = -fPIC -I${NDPI_SRC}/include -I${NDPI_SRC}/lib -I../src -DOPENDPI_NETFILTER_MODULE -O2 -Wall
+
+all:  libxt_ndpi.so
+install:  libxt_ndpi.so
+	if [ -d $(DESTDIR)$(XTBL) ]; then install libxt_ndpi.so $(DESTDIR)$(XTBL); ln -fs libxt_ndpi.so $(DESTDIR)$(XTBL)/libxt_NDPI.so ; else echo "No pkg-config --variable=xtlibdir xtables"; fi
+
+lib%.so: lib%.o
+	$(CC) -shared -o $@ $^;
+lib%.o: lib%.c ../src/xt_ndpi.h
+	$(CC) ${CFLAGS} -D_INIT=lib$*_init -c -o $@ $<;
+clean:
+	rm -rf libxt_ndpi.so
+

+ 385 - 0
ndpi-netfilter/ipt/libxt_ndpi.c

@@ -0,0 +1,385 @@
+/* 
+ * libxt_ndpi.c
+ * Copyright (C) 2010-2012 G. Elian Gidoni <geg@gnu.org>
+ *               2012 Ed Wildgoose <lists@wildgooses.com>
+ * 
+ * This file is part of nDPI, an open source deep packet inspection
+ * library based on the PACE technology by ipoque GmbH
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the License.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <arpa/inet.h>
+#include <xtables.h>
+
+#include <linux/version.h>
+
+#define NDPI_IPTABLES_EXT
+#include "xt_ndpi.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+#endif
+
+static char *prot_short_str[] = { NDPI_PROTOCOL_SHORT_STRING };
+
+static void 
+ndpi_mt4_save(const void *entry, const struct xt_entry_match *match)
+{
+	const struct xt_ndpi_mtinfo *info = (const void *)match->data;
+        int i,c,l,t;
+
+        for (t = l = c = i = 0; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++) {
+		if(!strncmp(prot_short_str[i],"badproto_",9)) continue;
+		if(i) t++; // skip unknown
+		if (NDPI_COMPARE_PROTOCOL_TO_BITMASK(info->flags, i) != 0) {
+			if(!l) l = i; c++;
+		}
+	}
+	if(!c) return; // BUG?
+	if( c == 1) {
+		printf(" %s --%s ",info->invert ? "! ":"", prot_short_str[l]);
+		return;
+	}
+	if( c == t ) { // all
+		printf(" %s --all ",info->invert ? "! ":"");
+		return;
+	}
+	printf(" %s --proto ",info->invert ? "! ":"" );
+        for (l = i = 0; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++) {
+                if (NDPI_COMPARE_PROTOCOL_TO_BITMASK(info->flags, i) != 0) {
+			printf("%s%s",l++ ? ",":"", prot_short_str[i]);
+			
+                }
+        }
+}
+
+
+static void 
+ndpi_mt4_print(const void *entry, const struct xt_entry_match *match,
+                  int numeric)
+{
+	const struct xt_ndpi_mtinfo *info = (const void *)match->data;
+        int i,c,l,t;
+
+        for (t = c = i = 0; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++) {
+		if(!strncmp(prot_short_str[i],"badproto_",9)) continue;
+		if(i) t++; // skip unknown
+		if (NDPI_COMPARE_PROTOCOL_TO_BITMASK(info->flags, i) != 0) c++;
+	}
+	if(!c) return;
+	if( c == t ) {
+		printf(" %sndpi protocol all",info->invert ? "! ":"");
+		return;
+	}
+
+	printf(" %sndpi protocol%s ",info->invert ? "! ":"",c > 1 ? "s":"");
+
+        for (l = i = 0; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++) {
+                if (NDPI_COMPARE_PROTOCOL_TO_BITMASK(info->flags, i) != 0) {
+                        printf("%s%s",l++ ? ",":"", prot_short_str[i]);
+                }
+        }
+}
+
+
+static int 
+ndpi_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
+                  const void *entry, struct xt_entry_match **match)
+{
+	struct xt_ndpi_mtinfo *info = (void *)(*match)->data;
+        int i;
+
+        *flags = 0;
+	info->invert = invert;
+	if(c == NDPI_LAST_IMPLEMENTED_PROTOCOL+1) {
+		char *np = optarg,*n;
+		int num;
+		while((n = strtok(np,",")) != NULL) {
+			num = -1;
+			for (i = 0; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++) {
+			    if(!strcmp(prot_short_str[i],n)) {
+				    num = i;
+				    break; 
+			    }
+			}
+			if(num < 0) {
+				printf("Unknown proto '%s'\n",n);
+				return false;
+			}
+			NDPI_ADD_PROTOCOL_TO_BITMASK(info->flags,num);
+        		*flags |= 1;
+			np = NULL;
+		}
+		return *flags != 0;
+	}
+	if(c == NDPI_LAST_IMPLEMENTED_PROTOCOL+2) { // all
+		for (i = 1; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++) {
+	    	    if(strncmp(prot_short_str[i],"badproto_",9))
+			NDPI_ADD_PROTOCOL_TO_BITMASK(info->flags,i);
+		}
+        	*flags |= 1;
+		return true;
+	}
+	if(c > NDPI_LAST_IMPLEMENTED_PROTOCOL+2) {
+		printf("BUG! c > NDPI_LAST_IMPLEMENTED_PROTOCOL+1\n");
+		return false;
+	}
+        for (i = 0; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++){
+                if (c == i){
+                        NDPI_ADD_PROTOCOL_TO_BITMASK(info->flags, i);
+                        *flags = 1;
+                        return true;
+                }
+        }
+
+	return false;
+}
+
+#ifndef xtables_error
+#define xtables_error exit_error
+#endif
+
+static void
+ndpi_mt_check (unsigned int flags)
+{
+	if (flags == 0){
+		xtables_error(PARAMETER_PROBLEM, "xt_ndpi: You need to "
+                              "specify at least one protocol");
+	}
+}
+
+
+static void
+ndpi_mt_help(void)
+{
+        int i;
+
+	printf("ndpi match options:\n--all Match any known protocol\n");
+        for (i = 0; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++){
+	    if(strncmp(prot_short_str[i],"badproto_",9))
+                printf("--%-16s (0x%x) Match for %s protocol packets.\n",
+                       prot_short_str[i],i, prot_short_str[i]);
+        }
+}
+
+
+static void 
+ndpi_mt_init (struct xt_entry_match *match)
+{
+	/* struct xt_ndpi_mtinfo *info = (void *)match->data; */
+	/* inet_pton(PF_INET, "192.0.2.137", &info->dst.in); */
+}
+
+/*
+ * NDPI_LAST_IMPLEMENTED_PROTOCOL
+ * + --unknown
+ * + --all
+ * + --proto lists_comma_separated
+ * + NULL
+ */
+static struct option ndpi_mt_opts[NDPI_LAST_IMPLEMENTED_PROTOCOL+4];
+
+static struct xtables_match
+ndpi_mt4_reg = {
+	.version = XTABLES_VERSION,
+	.name = "ndpi",
+	.revision = 0,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	.family = AF_INET,
+#else
+	.family = NFPROTO_UNSPEC,
+#endif
+	.size = XT_ALIGN(sizeof(struct xt_ndpi_mtinfo)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_ndpi_mtinfo)),
+	.help = ndpi_mt_help,
+	.init = ndpi_mt_init,
+	.parse = ndpi_mt4_parse,
+	.final_check = ndpi_mt_check,
+	.print = ndpi_mt4_print,
+	.save = ndpi_mt4_save,
+	.extra_opts = ndpi_mt_opts,
+};
+/* target NDPIMARK */
+enum {
+        O_SET_VALUE=0,
+        O_SET_NDPI,
+        O_SET_MARK,
+        O_SET_CLSF,
+        O_ACCEPT,
+        F_SET_VALUE = 1 << O_SET_VALUE,
+        F_SET_NDPI = 1 << O_SET_NDPI,
+        F_SET_MARK = 1 << O_SET_MARK,
+        F_SET_CLSF = 1 << O_SET_CLSF,
+        F_ACCEPT = 1 << O_ACCEPT,
+        F_ANY       = F_SET_VALUE | F_SET_NDPI |
+			F_SET_MARK | F_SET_CLSF |
+			F_ACCEPT,
+};
+
+static void NDPI_help(void)
+{
+        printf(
+"NDPI target options:\n"
+"  --value value/mask                  Set value = (value & ~mask) | value\n"
+"  --ndpi-id                           Set value = (value & ~proto_mask) | proto_mark\n"
+"  --set-mark                          Set nfmark = value\n"
+"  --set-clsf                          Set priority = value\n"
+"  --accept                            -j ACCEPT\n"
+);
+}
+
+static const struct xt_option_entry NDPI_opts[] = {
+        {.name = "value",    .id = O_SET_VALUE,.type = XTTYPE_MARKMASK32},
+        {.name = "ndpi-id",  .id = O_SET_NDPI, .type = XTTYPE_NONE},
+        {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_NONE},
+        {.name = "set-clsf", .id = O_SET_CLSF, .type = XTTYPE_NONE},
+        {.name = "accept",   .id = O_ACCEPT,   .type = XTTYPE_NONE},
+        XTOPT_TABLEEND,
+};
+static void NDPI_parse_v0(struct xt_option_call *cb)
+{
+        struct xt_ndpi_tginfo *markinfo = cb->data;
+
+        xtables_option_parse(cb);
+        switch (cb->entry->id) {
+        case O_SET_VALUE:
+                markinfo->mark = cb->val.mark;
+                markinfo->mask = ~cb->val.mask;
+                break;
+	case O_SET_NDPI:
+		markinfo->proto_id = 1;
+		break;
+	case O_SET_MARK:
+		markinfo->t_mark = 1;
+		break;
+	case O_SET_CLSF:
+		markinfo->t_clsf = 1;
+		break;
+	case O_ACCEPT:
+		markinfo->t_accept = 1;
+		break;
+        default:
+                xtables_error(PARAMETER_PROBLEM,
+                           "NDPI target: unknown --%s",
+                           cb->entry->name);
+        }
+}
+
+static void NDPI_print_v0(const void *ip,
+                          const struct xt_entry_target *target, int numeric)
+{
+        const struct xt_ndpi_tginfo *info =
+                (const struct xt_ndpi_tginfo *)target->data;
+char buf[128];
+int l;
+        l = snprintf(buf,sizeof(buf)-1," NDPI");
+	if(info->t_mark)
+	     l += snprintf(&buf[l],sizeof(buf)-l-1, " set MARK ");
+	if(info->t_clsf)
+	     l += snprintf(&buf[l],sizeof(buf)-l-1, " set CLSF ");
+	if(info->mask || info->mark) {
+	     if(info->mask)
+		l += snprintf(&buf[l],sizeof(buf)-l-1," and 0x%x or 0x%x",
+				info->mask,info->mark);
+	     else
+	        l += snprintf(&buf[l],sizeof(buf)-l-1," set 0x%x", info->mark);
+	}
+	if(info->proto_id)
+	     l += snprintf(&buf[l],sizeof(buf)-l-1,
+			     " by ndpi-id");
+	if(info->t_accept)
+	     l += snprintf(&buf[l],sizeof(buf)-l-1," ACCEPT");
+	printf(buf);
+}
+
+static void NDPI_save_v0(const void *ip, const struct xt_entry_target *target)
+{
+        const struct xt_ndpi_tginfo *info =
+                (const struct xt_ndpi_tginfo *)target->data;
+	char buf[128];
+	int l = 0;
+	if(info->mask || info->mark) {
+	     l += snprintf(&buf[l],sizeof(buf)-l-1," --value 0x%x", info->mark);
+	     if(info->mask)
+		l += snprintf(&buf[l],sizeof(buf)-l-1,"/0x%x",~info->mask);
+	}
+	if(info->proto_id)
+	     l += snprintf(&buf[l],sizeof(buf)-l-1, " --ndpi-id");
+	if(info->t_mark)
+	     l += snprintf(&buf[l],sizeof(buf)-l-1, " --set-mark");
+	if(info->t_clsf)
+	     l += snprintf(&buf[l],sizeof(buf)-l-1, " --set-clsf");
+	if(info->t_accept)
+	     l += snprintf(&buf[l],sizeof(buf)-l-1," --accept");
+	printf(buf);
+
+}
+
+static void NDPI_check(struct xt_fcheck_call *cb)
+{
+        if (!(cb->xflags & (F_SET_VALUE|F_SET_NDPI)))
+                xtables_error(PARAMETER_PROBLEM,
+                           "NDPI target: Parameter --set-mark or --ndpi-id"
+                           " is required %x",cb->xflags);
+}
+
+static struct xtables_target ndpi_tg_reg[] = {
+        {
+                .family        = NFPROTO_UNSPEC,
+                .name          = "NDPI",
+                .version       = XTABLES_VERSION,
+                .revision      = 0,
+                .size          = XT_ALIGN(sizeof(struct xt_ndpi_tginfo)),
+                .userspacesize = XT_ALIGN(sizeof(struct xt_ndpi_tginfo)),
+                .help          = NDPI_help,
+                .print         = NDPI_print_v0,
+                .save          = NDPI_save_v0,
+                .x6_parse      = NDPI_parse_v0,
+                .x6_fcheck     = NDPI_check,
+                .x6_options    = NDPI_opts,
+        },
+};
+
+void _init(void)
+{
+        int i;
+
+        for (i = 0; i <= NDPI_LAST_IMPLEMENTED_PROTOCOL; i++){
+                ndpi_mt_opts[i].name = prot_short_str[i];
+                ndpi_mt_opts[i].flag = NULL;
+		ndpi_mt_opts[i].has_arg = 0;
+                ndpi_mt_opts[i].val = i;
+        }
+	ndpi_mt_opts[i].name = "proto";
+	ndpi_mt_opts[i].flag = NULL;
+	ndpi_mt_opts[i].has_arg = 1;
+	ndpi_mt_opts[i].val = i;
+	i++;
+	ndpi_mt_opts[i].name = "all";
+	ndpi_mt_opts[i].flag = NULL;
+	ndpi_mt_opts[i].has_arg = 0;
+	ndpi_mt_opts[i].val = i;
+	i++;
+	ndpi_mt_opts[i].name = NULL;
+	ndpi_mt_opts[i].flag = NULL;
+	ndpi_mt_opts[i].has_arg = 0;
+	ndpi_mt_opts[i].val = 0;
+
+	xtables_register_match(&ndpi_mt4_reg);
+	xtables_register_targets(ndpi_tg_reg, ARRAY_SIZE(ndpi_tg_reg));
+}

+ 199 - 0
ndpi-netfilter/kernel-patch/v3.10.20.diff

@@ -0,0 +1,199 @@
+diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
+index 977bc8a..720f699 100644
+--- a/include/net/netfilter/nf_conntrack_extend.h
++++ b/include/net/netfilter/nf_conntrack_extend.h
+@@ -26,7 +26,8 @@ enum nf_ct_ext_id {
+ #ifdef CONFIG_NF_CONNTRACK_LABELS
+ 	NF_CT_EXT_LABELS,
+ #endif
+-	NF_CT_EXT_NUM,
++	NF_CT_EXT_CUSTOM,
++	NF_CT_EXT_NUM=NF_CT_EXT_CUSTOM+CONFIG_NF_CONNTRACK_CUSTOM,
+ };
+ 
+ #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help
+@@ -41,8 +42,8 @@ enum nf_ct_ext_id {
+ /* Extensions: optional stuff which isn't permanently in struct. */
+ struct nf_ct_ext {
+ 	struct rcu_head rcu;
+-	u8 offset[NF_CT_EXT_NUM];
+-	u8 len;
++	u16 offset[NF_CT_EXT_NUM];
++	u16 len;
+ 	char data[0];
+ };
+ 
+@@ -94,12 +95,16 @@ void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id,
+ 
+ #define NF_CT_EXT_F_PREALLOC	0x0001
+ 
++struct seq_file;
++
+ struct nf_ct_ext_type {
+ 	/* Destroys relationships (can be NULL). */
+ 	void (*destroy)(struct nf_conn *ct);
+ 	/* Called when realloacted (can be NULL).
+ 	   Contents has already been moved. */
+ 	void (*move)(void *new, void *old);
++	/* Print custom info (can be NULL) */
++	unsigned int (*seq_print)(struct seq_file *s, const struct nf_conn *ct, int dir);
+ 
+ 	enum nf_ct_ext_id id;
+ 
+@@ -112,6 +117,8 @@ struct nf_ct_ext_type {
+ 	u8 alloc_size;
+ };
+ 
++unsigned int nf_ct_ext_seq_print(struct seq_file *s, const struct nf_conn *ct, int dir);
+ int nf_ct_extend_register(struct nf_ct_ext_type *type);
++int nf_ct_extend_custom_register(struct nf_ct_ext_type *type,unsigned long int cid);
+ void nf_ct_extend_unregister(struct nf_ct_ext_type *type);
+ #endif /* _NF_CONNTRACK_EXTEND_H */
+diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
+index 9e7732d..75c8a5d 100644
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -70,6 +70,16 @@ config NF_CONNTRACK_SECMARK
+ 
+ 	  If unsure, say 'N'.
+ 
++config NF_CONNTRACK_CUSTOM
++	int "Number of custom extend"
++	range 0 8
++	depends on NETFILTER_ADVANCED
++	default "4"
++	help
++	  This parameter specifies how many custom extensions can be registered.
++
++	  The default value is 4.
++
+ config NF_CONNTRACK_ZONES
+ 	bool  'Connection tracking zones'
+ 	depends on NETFILTER_ADVANCED
+diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
+index 2d3030a..7f97126 100644
+--- a/net/netfilter/nf_conntrack_acct.c
++++ b/net/netfilter/nf_conntrack_acct.c
+@@ -52,6 +52,7 @@ seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
+ EXPORT_SYMBOL_GPL(seq_print_acct);
+ 
+ static struct nf_ct_ext_type acct_extend __read_mostly = {
++	.seq_print = seq_print_acct,
+ 	.len	= sizeof(struct nf_conn_counter[IP_CT_DIR_MAX]),
+ 	.align	= __alignof__(struct nf_conn_counter[IP_CT_DIR_MAX]),
+ 	.id	= NF_CT_EXT_ACCT,
+diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
+index 1a95459..28499ae 100644
+--- a/net/netfilter/nf_conntrack_extend.c
++++ b/net/netfilter/nf_conntrack_extend.c
+@@ -43,6 +43,30 @@ void __nf_ct_ext_destroy(struct nf_conn *ct)
+ }
+ EXPORT_SYMBOL(__nf_ct_ext_destroy);
+ 
++struct seq_file;
++
++unsigned int nf_ct_ext_seq_print(struct seq_file *s, const struct nf_conn *ct, int dir)
++{
++	unsigned int i,ret=0;
++	struct nf_ct_ext_type *t;
++	struct nf_ct_ext *ext = ct->ext;
++
++	for (i = 0; i < NF_CT_EXT_NUM; i++) {
++		if (!__nf_ct_ext_exist(ext, i))
++			continue;
++
++		rcu_read_lock(); // FIXME
++		t = rcu_dereference(nf_ct_ext_types[i]);
++		if (t && t->seq_print)
++			ret = t->seq_print(s,ct,dir);
++		rcu_read_unlock();
++		if(ret)
++			return ret;
++	}
++	return ret;
++}
++EXPORT_SYMBOL(nf_ct_ext_seq_print);
++
+ static void *
+ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id,
+ 		 size_t var_alloc_len, gfp_t gfp)
+@@ -156,6 +180,24 @@ static void update_alloc_size(struct nf_ct_ext_type *type)
+ 	}
+ }
+ 
++static unsigned long int nf_ct_ext_cust_id[CONFIG_NF_CONNTRACK_CUSTOM];
++static enum nf_ct_ext_id 
++nf_ct_extend_get_custom_id(unsigned long int ext_id)
++{
++	enum nf_ct_ext_id ret = 0;
++	int i;
++	mutex_lock(&nf_ct_ext_type_mutex);
++	for(i = 0; i < CONFIG_NF_CONNTRACK_CUSTOM; i++) {
++		if(!nf_ct_ext_cust_id[i]) {
++			nf_ct_ext_cust_id[i] = ext_id;
++			ret = i+NF_CT_EXT_CUSTOM;
++			break;
++		}
++	}
++	mutex_unlock(&nf_ct_ext_type_mutex);
++	return ret;
++}
++
+ /* This MUST be called in process context. */
+ int nf_ct_extend_register(struct nf_ct_ext_type *type)
+ {
+@@ -179,12 +221,32 @@ out:
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_extend_register);
+ 
++int nf_ct_extend_custom_register(struct nf_ct_ext_type *type,
++				 unsigned long int cid)
++{
++	int ret;
++	enum nf_ct_ext_id new_id = nf_ct_extend_get_custom_id(cid);
++	if(!new_id)
++		return -EBUSY;
++	type->id = new_id;
++	ret = nf_ct_extend_register(type);
++	if(ret < 0) {
++		mutex_lock(&nf_ct_ext_type_mutex);
++		nf_ct_ext_cust_id[new_id - NF_CT_EXT_CUSTOM] = 0;
++		mutex_unlock(&nf_ct_ext_type_mutex);
++	}
++	return ret;
++}
++EXPORT_SYMBOL_GPL(nf_ct_extend_custom_register);
++
+ /* This MUST be called in process context. */
+ void nf_ct_extend_unregister(struct nf_ct_ext_type *type)
+ {
+ 	mutex_lock(&nf_ct_ext_type_mutex);
+ 	RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL);
+ 	update_alloc_size(type);
++	if(type->id >= NF_CT_EXT_CUSTOM && type->id < NF_CT_EXT_NUM)
++		nf_ct_ext_cust_id[type->id-NF_CT_EXT_CUSTOM] = 0;