diff options
Diffstat (limited to 'example')
-rw-r--r-- | example/Makefile.am | 12 | ||||
-rw-r--r-- | example/Win32/pcapExample.sln | 20 | ||||
-rw-r--r-- | example/Win32/pcapExample.suo | bin | 0 -> 306688 bytes | |||
-rw-r--r-- | example/Win32/pcapExample/pcapExample.cpp | 11 | ||||
-rw-r--r-- | example/Win32/pcapExample/pcapExample.vcxproj | 230 | ||||
-rw-r--r-- | example/Win32/pcapExample/pcapExample.vcxproj.filters | 462 | ||||
-rw-r--r-- | example/Win32/pcapExample/pcapExample.vcxproj.user | 3 | ||||
-rw-r--r-- | example/ndpiReader.c | 1788 | ||||
-rw-r--r-- | example/protos.txt | 18 |
9 files changed, 2544 insertions, 0 deletions
diff --git a/example/Makefile.am b/example/Makefile.am new file mode 100644 index 000000000..f98bae9ae --- /dev/null +++ b/example/Makefile.am @@ -0,0 +1,12 @@ +bin_PROGRAMS = ndpiReader + +AM_CPPFLAGS = -I$(top_srcdir)/src/include @PCAP_INC@ +AM_CFLAGS = @PTHREAD_CFLAGS@ + +LDADD = $(top_builddir)/src/lib/libndpi.la @JSON_C_LIB@ @PTHREAD_LIBS@ @PCAP_LIB@ +AM_LDFLAGS = -static + +ndpiReader_SOURCES = ndpiReader.c + +ndpiReader.o: ndpiReader.c + diff --git a/example/Win32/pcapExample.sln b/example/Win32/pcapExample.sln new file mode 100644 index 000000000..3c061ed01 --- /dev/null +++ b/example/Win32/pcapExample.sln @@ -0,0 +1,20 @@ +
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcapExample", "pcapExample\pcapExample.vcxproj", "{F6A2C0AE-2110-438A-87E4-7C1CFCE064C6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F6A2C0AE-2110-438A-87E4-7C1CFCE064C6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F6A2C0AE-2110-438A-87E4-7C1CFCE064C6}.Debug|Win32.Build.0 = Debug|Win32
+ {F6A2C0AE-2110-438A-87E4-7C1CFCE064C6}.Release|Win32.ActiveCfg = Release|Win32
+ {F6A2C0AE-2110-438A-87E4-7C1CFCE064C6}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/example/Win32/pcapExample.suo b/example/Win32/pcapExample.suo Binary files differnew file mode 100644 index 000000000..122e224b4 --- /dev/null +++ b/example/Win32/pcapExample.suo diff --git a/example/Win32/pcapExample/pcapExample.cpp b/example/Win32/pcapExample/pcapExample.cpp new file mode 100644 index 000000000..ad7655eea --- /dev/null +++ b/example/Win32/pcapExample/pcapExample.cpp @@ -0,0 +1,11 @@ +// pcapExample.cpp : Defines the entry point for the console application.
+//
+
+#include "stdafx.h"
+
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+ return 0;
+}
+
diff --git a/example/Win32/pcapExample/pcapExample.vcxproj b/example/Win32/pcapExample/pcapExample.vcxproj new file mode 100644 index 000000000..2b86797bd --- /dev/null +++ b/example/Win32/pcapExample/pcapExample.vcxproj @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{F6A2C0AE-2110-438A-87E4-7C1CFCE064C6}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>pcapExample</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>C:\ntop\nprobe\nprobe-win-32;C:\ntop\winpcap\Include;C:\ntop\dependencies\nDPI\src\lib\third_party\include;C:\ntop\dependencies\nDPI\src\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>Wsock32.lib;Ws2_32.lib;C:\ntop\winpcap\Lib\Packet.lib;C:\ntop\winpcap\Lib\wpcap.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\..\..\nprobe\nprobe-win-32\getopt.c" />
+ <ClCompile Include="..\..\..\..\..\nprobe\nprobe-win-32\getopt1.c" />
+ <ClCompile Include="..\..\..\src\lib\ndpi_main.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\afp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\aimini.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\applejuice.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\armagetron.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\battlefield.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\bgp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\bittorrent.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ciscovpn.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\citrix.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\corba.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\crossfire.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\dcerpc.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\dhcp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\dhcpv6.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\directconnect.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\directdownloadlink.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\dns.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\dofus.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\dropbox.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\edonkey.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\fasttrack.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\feidian.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\fiesta.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\filetopia.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\flash.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\florensia.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ftp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\gadu_gadu.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\gnutella.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\gtp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\guildwars.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\h323.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\halflife2_and_mods.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\http.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\http_activesync.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\i23v5.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\iax.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\icecast.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\imesh.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ipp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\irc.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\jabber.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\kerberos.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\kontiki.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ldap.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\lotus_notes.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\mail_imap.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\mail_pop.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\mail_smtp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\maplestory.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\mdns.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\meebo.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\mgcp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\mms.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\msn.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\mssql.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\mysql.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\netbios.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\netflow.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\nfs.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\noe.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\non_tcp_udp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ntp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\openft.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\openvpn.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\oracle.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\oscar.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\pando.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\pcanywhere.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\popo.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\postgres.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\pplive.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ppstream.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\pptp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\qq.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\quake.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\radius.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\rdp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\rsync.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\rtcp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\rtp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\rtsp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\sflow.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\shoutcast.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\sip.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\skinny.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\skype.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\smb.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\snmp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\socrates.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\sopcast.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\soulseek.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\spotify.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ssdp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ssh.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\ssl.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\stealthnet.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\steam.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\stun.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\syslog.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\tcp_udp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\tds.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\teamspeak.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\teamviewer.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\telnet.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\tftp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\thunder.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\tor.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\tvants.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\tvuplayer.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\usenet.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\veohtv.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\viber.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\vmware.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\vnc.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\warcraft3.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\winmx.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\world_of_kung_fu.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\world_of_warcraft.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\xbox.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\xdmcp.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\yahoo.c" />
+ <ClCompile Include="..\..\..\src\lib\protocols\zattoo.c" />
+ <ClCompile Include="..\..\..\src\lib\third_party\src\ahocorasick.c" />
+ <ClCompile Include="..\..\..\src\lib\third_party\src\node.c" />
+ <ClCompile Include="..\..\..\src\lib\third_party\src\sort.c" />
+ <ClCompile Include="..\..\pcapReader.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\..\..\nprobe\nprobe-win-32\getopt.h" />
+ <ClInclude Include="..\..\..\src\include\linux_compat.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_api.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_debug_functions.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_define.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_macros.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_main.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_protocols.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_protocols_osdpi.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_protocol_history.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_public_functions.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_structs.h" />
+ <ClInclude Include="..\..\..\src\include\ndpi_utils.h" />
+ <ClInclude Include="..\..\..\src\lib\third_party\include\actypes.h" />
+ <ClInclude Include="..\..\..\src\lib\third_party\include\ahocorasick.h" />
+ <ClInclude Include="..\..\..\src\lib\third_party\include\node.h" />
+ <ClInclude Include="..\..\..\src\lib\third_party\include\sort.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/example/Win32/pcapExample/pcapExample.vcxproj.filters b/example/Win32/pcapExample/pcapExample.vcxproj.filters new file mode 100644 index 000000000..394d9dc7a --- /dev/null +++ b/example/Win32/pcapExample/pcapExample.vcxproj.filters @@ -0,0 +1,462 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\pcapReader.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\ndpi_main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\zattoo.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\afp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\aimini.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\applejuice.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\armagetron.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\battlefield.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\bgp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\bittorrent.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ciscovpn.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\citrix.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\corba.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\crossfire.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\dcerpc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\dhcp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\dhcpv6.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\directconnect.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\directdownloadlink.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\dns.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\dofus.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\dropbox.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\edonkey.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\fasttrack.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\feidian.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\fiesta.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\filetopia.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\flash.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\florensia.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ftp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\gadu_gadu.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\gnutella.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\gtp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\guildwars.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\h323.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\halflife2_and_mods.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\http.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\http_activesync.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\i23v5.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\iax.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\icecast.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\imesh.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ipp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\irc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\jabber.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\kerberos.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\kontiki.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ldap.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\lotus_notes.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\mail_imap.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\mail_pop.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\mail_smtp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\maplestory.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\mdns.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\meebo.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\mgcp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\mms.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\msn.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\mssql.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\mysql.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\netbios.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\netflow.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\nfs.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\noe.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\non_tcp_udp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ntp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\openft.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\openvpn.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\oracle.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\oscar.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\pando.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\pcanywhere.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\popo.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\postgres.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\pplive.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ppstream.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\pptp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\qq.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\quake.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\radius.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\rdp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\rsync.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\rtcp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\rtp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\rtsp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\sflow.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\shoutcast.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\sip.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\skinny.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\skype.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\smb.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\snmp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\socrates.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\sopcast.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\soulseek.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\spotify.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ssdp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ssh.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\ssl.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\stealthnet.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\steam.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\stun.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\syslog.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\tcp_udp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\tds.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\teamspeak.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\teamviewer.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\telnet.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\tftp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\thunder.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\tor.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\tvants.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\tvuplayer.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\usenet.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\veohtv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\viber.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\vmware.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\vnc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\warcraft3.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\winmx.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\world_of_kung_fu.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\world_of_warcraft.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\xbox.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\xdmcp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\protocols\yahoo.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\third_party\src\ahocorasick.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\third_party\src\node.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\src\lib\third_party\src\sort.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\..\..\nprobe\nprobe-win-32\getopt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\..\..\nprobe\nprobe-win-32\getopt1.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\src\lib\third_party\include\actypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\lib\third_party\include\ahocorasick.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\lib\third_party\include\node.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\lib\third_party\include\sort.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_debug_functions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_define.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_macros.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_protocol_history.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_protocols.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_protocols_osdpi.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_public_functions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_structs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\ndpi_utils.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\src\include\linux_compat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\..\..\nprobe\nprobe-win-32\getopt.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
\ No newline at end of file diff --git a/example/Win32/pcapExample/pcapExample.vcxproj.user b/example/Win32/pcapExample/pcapExample.vcxproj.user new file mode 100644 index 000000000..695b5c78b --- /dev/null +++ b/example/Win32/pcapExample/pcapExample.vcxproj.user @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
\ No newline at end of file diff --git a/example/ndpiReader.c b/example/ndpiReader.c new file mode 100644 index 000000000..41a4b42ed --- /dev/null +++ b/example/ndpiReader.c @@ -0,0 +1,1788 @@ +/* + * ndpiReader.c + * + * Copyright (C) 2011-15 - ntop.org + * Copyright (C) 2009-2011 by ipoque GmbH + * Copyright (C) 2014 - Matteo Bogo <matteo.bogo@gmail.com> (JSON support) + * + * nDPI is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nDPI 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with nDPI. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifdef linux +#define _GNU_SOURCE +#include <sched.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#ifdef WIN32 +#include <winsock2.h> /* winsock.h is included automatically */ +#include <process.h> +#include <io.h> +#include <getopt.h> +#define getopt getopt____ +#else +#include <unistd.h> +#include <netinet/in.h> +#endif +#include <string.h> +#include <stdarg.h> +#include <search.h> +#include <pcap.h> +#include <signal.h> +#include <pthread.h> + +#include "../config.h" + +#ifdef HAVE_JSON_C +#include <json.h> +#endif + +#include "ndpi_api.h" + +#include <sys/socket.h> + +#define MAX_NUM_READER_THREADS 16 + +/** + * @brief Set main components necessary to the detection + * @details TODO + */ +static void setupDetection(u_int16_t thread_id); + +/** + * Client parameters + */ +static char *_pcap_file[MAX_NUM_READER_THREADS]; /**< Ingress pcap file/interafaces */ +static FILE *playlist_fp[MAX_NUM_READER_THREADS] = { NULL }; /**< Ingress playlist */ +static char *_bpf_filter = NULL; /**< bpf filter */ +static char *_protoFilePath = NULL; /**< Protocol file path */ +#ifdef HAVE_JSON_C +static char *_jsonFilePath = NULL; /**< JSON file path */ +#endif +#ifdef HAVE_JSON_C +static json_object *jArray_known_flows, *jArray_unknown_flows; +#endif +static u_int8_t live_capture = 0, full_http_dissection = 0; +static u_int8_t undetected_flows_deleted = 0; +/** + * User preferences + */ +static u_int8_t enable_protocol_guess = 1, verbose = 0, nDPI_traceLevel = 0, json_flag = 0; +static u_int16_t decode_tunnels = 0; +static u_int16_t num_loops = 1; +static u_int8_t shutdown_app = 0; +static u_int8_t num_threads = 1; +static u_int32_t current_ndpi_memory = 0, max_ndpi_memory = 0; +#ifdef linux +static int core_affinity[MAX_NUM_READER_THREADS]; +#endif + +static struct timeval pcap_start, pcap_end; + +/** + * Detection parameters + */ +static u_int32_t detection_tick_resolution = 1000; +static time_t capture_for = 0; +static time_t capture_until = 0; + +#define IDLE_SCAN_PERIOD 10 /* msec (use detection_tick_resolution = 1000) */ +#define MAX_IDLE_TIME 30000 +#define IDLE_SCAN_BUDGET 1024 + +#define NUM_ROOTS 512 + +static u_int32_t num_flows; + +struct thread_stats { + u_int32_t guessed_flow_protocols; + u_int64_t raw_packet_count; + u_int64_t ip_packet_count; + u_int64_t total_wire_bytes, total_ip_bytes, total_discarded_bytes; + u_int64_t protocol_counter[NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1]; + u_int64_t protocol_counter_bytes[NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1]; + u_int32_t protocol_flows[NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1]; + u_int32_t ndpi_flow_count; + u_int64_t tcp_count, udp_count; + u_int64_t mpls_count, pppoe_count, vlan_count, fragmented_count; + u_int64_t packet_len[6]; + u_int16_t max_packet_len; +}; + +struct reader_thread { + struct ndpi_detection_module_struct *ndpi_struct; + void *ndpi_flows_root[NUM_ROOTS]; + char _pcap_error_buffer[PCAP_ERRBUF_SIZE]; + pcap_t *_pcap_handle; + u_int64_t last_time; + u_int64_t last_idle_scan_time; + u_int32_t idle_scan_idx; + u_int32_t num_idle_flows; + pthread_t pthread; + int _pcap_datalink_type; + + /* TODO Add barrier */ + struct thread_stats stats; + + struct ndpi_flow *idle_flows[IDLE_SCAN_BUDGET]; +}; + +static struct reader_thread ndpi_thread_info[MAX_NUM_READER_THREADS]; + +#define GTP_U_V1_PORT 2152 +#define MAX_NDPI_FLOWS 200000000 +/** + * @brief ID tracking + */ +typedef struct ndpi_id { + u_int8_t ip[4]; //< Ip address + struct ndpi_id_struct *ndpi_id; //< nDpi worker structure +} ndpi_id_t; + +static u_int32_t size_id_struct = 0; //< ID tracking structure size + +#ifndef ETH_P_IP +#define ETH_P_IP 0x0800 +#endif + +// 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_int8_t detection_completed, protocol; + u_int16_t vlan_id; + struct ndpi_flow_struct *ndpi_flow; + char lower_name[32], upper_name[32]; + + u_int64_t last_seen; + + u_int64_t bytes; + u_int32_t packets; + + // result only, not used for flow identification + u_int32_t detected_protocol; + + char host_server_name[256]; + + struct { + char client_certificate[48], server_certificate[48]; + } ssl; + + void *src_id, *dst_id; +} ndpi_flow_t; + + +static u_int32_t size_flow_struct = 0; + +static void help(u_int long_help) { + printf("ndpiReader -i <file|device> [-f <filter>][-s <duration>]\n" + " [-p <protos>][-l <loops>[-d][-h][-t][-v <level>]\n" + " [-n <threads>] [-j <file>]\n\n" + "Usage:\n" + " -i <file.pcap|device> | Specify a pcap file/playlist to read packets from or a device for live capture (comma-separated list)\n" + " -f <BPF filter> | Specify a BPF filter for filtering selected traffic\n" + " -s <duration> | Maximum capture duration in seconds (live traffic capture only)\n" + " -p <file>.protos | Specify a protocol file (eg. protos.txt)\n" + " -l <num loops> | Number of detection loops (test only)\n" + " -n <num threads> | Number of threads. Default: number of interfaces in -i. Ignored with pcap files.\n" + " -j <file.json> | Specify a file to write the content of packets in .json format\n" +#ifdef linux + " -g <id:id...> | Thread affinity mask (one core id per thread)\n" +#endif + " -d | Disable protocol guess and use only DPI\n" + " -t | Dissect GTP tunnels\n" + " -h | This help\n" + " -v <1|2> | Verbose 'unknown protocol' packet print. 1=verbose, 2=very verbose\n"); + + if(long_help) { + printf("\n\nSupported protocols:\n"); + num_threads = 1; + setupDetection(0); + ndpi_dump_protocols(ndpi_thread_info[0].ndpi_struct); + } + + exit(!long_help); +} + +/* ***************************************************** */ + +static void parseOptions(int argc, char **argv) { + char *__pcap_file = NULL, *bind_mask = NULL; + int thread_id, opt; +#ifdef linux + u_int num_cores = sysconf( _SC_NPROCESSORS_ONLN ); +#endif + + while ((opt = getopt(argc, argv, "df:g:i:hp:l:s:tv:V:n:j:")) != EOF) { + switch (opt) { + case 'd': + enable_protocol_guess = 0; + break; + + case 'i': + _pcap_file[0] = optarg; + break; + + case 'f': + _bpf_filter = optarg; + break; + + case 'g': + bind_mask = optarg; + break; + + case 'l': + num_loops = atoi(optarg); + break; + + case 'n': + num_threads = atoi(optarg); + break; + + case 'p': + _protoFilePath = optarg; + break; + + case 's': + capture_for = atoi(optarg); + capture_until = capture_for + time(NULL); + break; + + case 't': + decode_tunnels = 1; + break; + + case 'v': + verbose = atoi(optarg); + break; + + case 'V': + printf("%d\n",atoi(optarg) ); + nDPI_traceLevel = atoi(optarg); + break; + + case 'h': + help(1); + break; + + case 'j': +#ifndef HAVE_JSON_C + printf("WARNING: this copy of ndpiReader has been compiled without JSON-C: json export disabled\n"); +#else + _jsonFilePath = optarg; + json_flag = 1; +#endif + break; + + default: + help(0); + break; + } + } + + // check parameters + if(_pcap_file[0] == NULL || strcmp(_pcap_file[0], "") == 0) { + help(0); + } + + if(strchr(_pcap_file[0], ',')) { /* multiple ingress interfaces */ + num_threads = 0; /* setting number of threads = number of interfaces */ + __pcap_file = strtok(_pcap_file[0], ","); + while (__pcap_file != NULL && num_threads < MAX_NUM_READER_THREADS) { + _pcap_file[num_threads++] = __pcap_file; + __pcap_file = strtok(NULL, ","); + } + } else { + if(num_threads > MAX_NUM_READER_THREADS) num_threads = MAX_NUM_READER_THREADS; + for(thread_id = 1; thread_id < num_threads; thread_id++) + _pcap_file[thread_id] = _pcap_file[0]; + } + +#ifdef linux + for(thread_id = 0; thread_id < num_threads; thread_id++) + core_affinity[thread_id] = -1; + + if(num_cores > 1 && bind_mask != NULL) { + char *core_id = strtok(bind_mask, ":"); + thread_id = 0; + while (core_id != NULL && thread_id < num_threads) { + core_affinity[thread_id++] = atoi(core_id) % num_cores; + core_id = strtok(NULL, ":"); + } + } +#endif +} + +/* ***************************************************** */ + +static void debug_printf(u_int32_t protocol, void *id_struct, + ndpi_log_level_t log_level, + const char *format, ...) { + va_list va_ap; +#ifndef WIN32 + struct tm result; +#endif + + if(log_level <= nDPI_traceLevel) { + char buf[8192], out_buf[8192]; + char theDate[32]; + const char *extra_msg = ""; + time_t theTime = time(NULL); + + va_start (va_ap, format); + + if(log_level == NDPI_LOG_ERROR) + extra_msg = "ERROR: "; + else if(log_level == NDPI_LOG_TRACE) + extra_msg = "TRACE: "; + else + extra_msg = "DEBUG: "; + + memset(buf, 0, sizeof(buf)); + strftime(theDate, 32, "%d/%b/%Y %H:%M:%S", localtime_r(&theTime,&result) ); + vsnprintf(buf, sizeof(buf)-1, format, va_ap); + + snprintf(out_buf, sizeof(out_buf), "%s %s%s", theDate, extra_msg, buf); + printf("%s", out_buf); + fflush(stdout); + } + + va_end(va_ap); +} + +/* ***************************************************** */ + +static void *malloc_wrapper(unsigned long size) { + current_ndpi_memory += size; + + if(current_ndpi_memory > max_ndpi_memory) + max_ndpi_memory = current_ndpi_memory; + + return malloc(size); +} + +/* ***************************************************** */ + +static void free_wrapper(void *freeable) { + free(freeable); +} + +/* ***************************************************** */ + +static char* ipProto2Name(u_short proto_id) { + static char proto[8]; + + switch(proto_id) { + case IPPROTO_TCP: + return("TCP"); + break; + case IPPROTO_UDP: + return("UDP"); + break; + case IPPROTO_ICMP: + return("ICMP"); + break; + case 112: + return("VRRP"); + break; + case IPPROTO_IGMP: + return("IGMP"); + break; + } + + snprintf(proto, sizeof(proto), "%u", proto_id); + return(proto); +} + +/* ***************************************************** */ + +/* + * A faster replacement for inet_ntoa(). + */ +char* intoaV4(unsigned int addr, char* buf, u_short bufLen) { + char *cp, *retStr; + uint byte; + int n; + + cp = &buf[bufLen]; + *--cp = '\0'; + + n = 4; + do { + byte = addr & 0xff; + *--cp = byte % 10 + '0'; + byte /= 10; + if(byte > 0) { + *--cp = byte % 10 + '0'; + byte /= 10; + if(byte > 0) + *--cp = byte + '0'; + } + *--cp = '.'; + addr >>= 8; + } while (--n > 0); + + /* Convert the string to lowercase */ + retStr = (char*)(cp+1); + + return(retStr); +} + +/* ***************************************************** */ + +static void printFlow(u_int16_t thread_id, struct ndpi_flow *flow) { +#ifdef HAVE_JSON_C + json_object *jObj; +#endif + + if(!json_flag) { +#if 0 + printf("\t%s [VLAN: %u] %s:%u <-> %s:%u\n", + ipProto2Name(flow->protocol), flow->vlan_id, + flow->lower_name, ntohs(flow->lower_port), + flow->upper_name, ntohs(flow->upper_port)); + +#else + printf("\t%u", ++num_flows); + + printf("\t%s %s:%u <-> %s:%u ", + ipProto2Name(flow->protocol), + flow->lower_name, ntohs(flow->lower_port), + flow->upper_name, ntohs(flow->upper_port)); + + if(flow->vlan_id > 0) printf("[VLAN: %u]", flow->vlan_id); + + printf("[proto: %u/%s][%u pkts/%llu bytes]", + flow->detected_protocol, + ndpi_get_proto_name(ndpi_thread_info[thread_id].ndpi_struct, flow->detected_protocol), + flow->packets, (long long unsigned int)flow->bytes); + + if(flow->host_server_name[0] != '\0') printf("[Host: %s]", flow->host_server_name); + if(flow->ssl.client_certificate[0] != '\0') printf("[SSL client: %s]", flow->ssl.client_certificate); + if(flow->ssl.server_certificate[0] != '\0') printf("[SSL server: %s]", flow->ssl.server_certificate); + + printf("\n"); +#endif + } else { +#ifdef HAVE_JSON_C + jObj = json_object_new_object(); + + json_object_object_add(jObj,"protocol",json_object_new_string(ipProto2Name(flow->protocol))); + json_object_object_add(jObj,"host_a.name",json_object_new_string(flow->lower_name)); + json_object_object_add(jObj,"host_a.port",json_object_new_int(ntohs(flow->lower_port))); + json_object_object_add(jObj,"host_b.name",json_object_new_string(flow->upper_name)); + json_object_object_add(jObj,"host_n.port",json_object_new_int(ntohs(flow->upper_port))); + json_object_object_add(jObj,"detected.protocol",json_object_new_int(flow->detected_protocol)); + json_object_object_add(jObj,"detected.protocol.name",json_object_new_string(ndpi_get_proto_name(ndpi_thread_info[thread_id].ndpi_struct, flow->detected_protocol))); + json_object_object_add(jObj,"packets",json_object_new_int(flow->packets)); + json_object_object_add(jObj,"bytes",json_object_new_int(flow->bytes)); + + if(flow->host_server_name[0] != '\0') + json_object_object_add(jObj,"host.server.name",json_object_new_string(flow->host_server_name)); + + if((flow->ssl.client_certificate[0] != '\0') || (flow->ssl.server_certificate[0] != '\0')) { + json_object *sjObj = json_object_new_object(); + + if(flow->ssl.client_certificate[0] != '\0') + json_object_object_add(sjObj, "client", json_object_new_string(flow->ssl.client_certificate)); + + if(flow->ssl.server_certificate[0] != '\0') + json_object_object_add(sjObj, "server", json_object_new_string(flow->ssl.server_certificate)); + + json_object_object_add(jObj, "ssl", sjObj); + } + + //flow->protos.ssl.client_certificate, flow->protos.ssl.server_certificate); + if(json_flag == 1) + json_object_array_add(jArray_known_flows,jObj); + else if(json_flag == 2) + json_object_array_add(jArray_unknown_flows,jObj); +#endif + } +} + +/* ***************************************************** */ + +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; } +} + +/* ***************************************************** */ + +static void ndpi_flow_freer(void *node) { + struct ndpi_flow *flow = (struct ndpi_flow*)node; + + free_ndpi_flow(flow); + ndpi_free(flow); +} + +/* ***************************************************** */ + +static void node_print_unknown_proto_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { + struct ndpi_flow *flow = *(struct ndpi_flow**)node; + u_int16_t thread_id = *((u_int16_t*)user_data); + + if(flow->detected_protocol != 0 /* UNKNOWN */) return; + + if((which == ndpi_preorder) || (which == ndpi_leaf)) /* Avoid walking the same node multiple times */ + printFlow(thread_id, flow); +} + +/* ***************************************************** */ + +static void node_print_known_proto_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { + struct ndpi_flow *flow = *(struct ndpi_flow**)node; + u_int16_t thread_id = *((u_int16_t*)user_data); + + if(flow->detected_protocol == 0 /* UNKNOWN */) return; + + if((which == ndpi_preorder) || (which == ndpi_leaf)) /* Avoid walking the same node multiple times */ + printFlow(thread_id, flow); +} + +/* ***************************************************** */ + +static unsigned int node_guess_undetected_protocol(u_int16_t thread_id, + struct ndpi_flow *flow) { + flow->detected_protocol = ndpi_guess_undetected_protocol(ndpi_thread_info[thread_id].ndpi_struct, + flow->protocol, + ntohl(flow->lower_ip), + ntohs(flow->lower_port), + ntohl(flow->upper_ip), + ntohs(flow->upper_port)); + // printf("Guess state: %u\n", flow->detected_protocol); + if(flow->detected_protocol != 0) + ndpi_thread_info[thread_id].stats.guessed_flow_protocols++; + + return flow->detected_protocol; +} + +/* ***************************************************** */ + +static void node_proto_guess_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { + struct ndpi_flow *flow = *(struct ndpi_flow **) node; + u_int16_t thread_id = *((u_int16_t *) user_data); + +#if 0 + printf("<%d>Walk on node %s (%p)\n", + depth, + which == preorder?"preorder": + which == postorder?"postorder": + which == endorder?"endorder": + which == leaf?"leaf": "unknown", + flow); +#endif + + if((which == ndpi_preorder) || (which == ndpi_leaf)) { /* Avoid walking the same node multiple times */ + if(enable_protocol_guess) { + if(flow->detected_protocol == 0 /* UNKNOWN */) { + node_guess_undetected_protocol(thread_id, flow); + // printFlow(thread_id, flow); + } + } + + ndpi_thread_info[thread_id].stats.protocol_counter[flow->detected_protocol] += flow->packets; + ndpi_thread_info[thread_id].stats.protocol_counter_bytes[flow->detected_protocol] += flow->bytes; + ndpi_thread_info[thread_id].stats.protocol_flows[flow->detected_protocol]++; + } +} + +/* ***************************************************** */ + +static void node_idle_scan_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { + struct ndpi_flow *flow = *(struct ndpi_flow **) node; + u_int16_t thread_id = *((u_int16_t *) user_data); + + if(ndpi_thread_info[thread_id].num_idle_flows == IDLE_SCAN_BUDGET) /* TODO optimise with a budget-based walk */ + return; + + if((which == ndpi_preorder) || (which == ndpi_leaf)) { /* Avoid walking the same node multiple times */ + if(flow->last_seen + MAX_IDLE_TIME < ndpi_thread_info[thread_id].last_time) { + + /* update stats */ + node_proto_guess_walker(node, which, depth, user_data); + + if (flow->detected_protocol == 0 /* UNKNOWN */ && !undetected_flows_deleted) + undetected_flows_deleted = 1; + + free_ndpi_flow(flow); + ndpi_thread_info[thread_id].stats.ndpi_flow_count--; + + /* adding to a queue (we can't delete it from the tree inline ) */ + ndpi_thread_info[thread_id].idle_flows[ndpi_thread_info[thread_id].num_idle_flows++] = flow; + } + } +} + +/* ***************************************************** */ + +static int node_cmp(const void *a, const void *b) { + struct ndpi_flow *fa = (struct ndpi_flow*)a; + struct ndpi_flow *fb = (struct ndpi_flow*)b; + + if(fa->vlan_id < fb->vlan_id ) return(-1); else { if(fa->vlan_id > fb->vlan_id ) return(1); } + if(fa->lower_ip < fb->lower_ip ) return(-1); else { if(fa->lower_ip > fb->lower_ip ) return(1); } + if(fa->lower_port < fb->lower_port) return(-1); else { if(fa->lower_port > fb->lower_port) return(1); } + if(fa->upper_ip < fb->upper_ip ) return(-1); else { if(fa->upper_ip > fb->upper_ip ) return(1); } + if(fa->upper_port < fb->upper_port) return(-1); else { if(fa->upper_port > fb->upper_port) return(1); } + if(fa->protocol < fb->protocol ) return(-1); else { if(fa->protocol > fb->protocol ) return(1); } + + return(0); +} + +/* ***************************************************** */ + +static struct ndpi_flow *get_ndpi_flow(u_int16_t thread_id, + const u_int8_t version, + u_int16_t vlan_id, + const struct ndpi_iphdr *iph, + u_int16_t ip_offset, + u_int16_t ipsize, + u_int16_t l4_packet_len, + struct ndpi_id_struct **src, + struct ndpi_id_struct **dst, + u_int8_t *proto, + const struct ndpi_ip6_hdr *iph6) { + 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; + struct ndpi_flow flow; + void *ret; + u_int8_t *l3; + + /* + Note: to keep things simple (ndpiReader is just a demo app) + we handle IPv6 a-la-IPv4. + */ + if(version == 4) { + if(ipsize < 20) + return NULL; + + if((iph->ihl * 4) > ipsize || ipsize < ntohs(iph->tot_len) + || (iph->frag_off & htons(0x1FFF)) != 0) + return NULL; + + l4_offset = iph->ihl * 4; + l3 = (u_int8_t*)iph; + } else { + l4_offset = sizeof(struct ndpi_ip6_hdr); + l3 = (u_int8_t*)iph6; + } + + if(l4_packet_len < 64) + ndpi_thread_info[thread_id].stats.packet_len[0]++; + else if(l4_packet_len >= 64 && l4_packet_len < 128) + ndpi_thread_info[thread_id].stats.packet_len[1]++; + else if(l4_packet_len >= 128 && l4_packet_len < 256) + ndpi_thread_info[thread_id].stats.packet_len[2]++; + else if(l4_packet_len >= 256 && l4_packet_len < 1024) + ndpi_thread_info[thread_id].stats.packet_len[3]++; + else if(l4_packet_len >= 1024 && l4_packet_len < 1500) + ndpi_thread_info[thread_id].stats.packet_len[4]++; + else if(l4_packet_len >= 1500) + ndpi_thread_info[thread_id].stats.packet_len[5]++; + + if(l4_packet_len > ndpi_thread_info[thread_id].stats.max_packet_len) + ndpi_thread_info[thread_id].stats.max_packet_len = l4_packet_len; + + if(iph->saddr < iph->daddr) { + lower_ip = iph->saddr; + upper_ip = iph->daddr; + } else { + lower_ip = iph->daddr; + upper_ip = iph->saddr; + } + + *proto = iph->protocol; + + if(iph->protocol == 6 && l4_packet_len >= 20) { + ndpi_thread_info[thread_id].stats.tcp_count++; + + // tcp + tcph = (struct ndpi_tcphdr *) ((u_int8_t *) l3 + l4_offset); + if(iph->saddr < iph->daddr) { + lower_port = tcph->source; + upper_port = tcph->dest; + } else { + lower_port = tcph->dest; + upper_port = tcph->source; + + if(iph->saddr == iph->daddr) { + if(lower_port > upper_port) { + u_int16_t p = lower_port; + + lower_port = upper_port; + upper_port = p; + } + } + } + } else if(iph->protocol == 17 && l4_packet_len >= 8) { + // udp + ndpi_thread_info[thread_id].stats.udp_count++; + + udph = (struct ndpi_udphdr *) ((u_int8_t *) l3 + l4_offset); + if(iph->saddr < iph->daddr) { + lower_port = udph->source; + upper_port = udph->dest; + } else { + lower_port = udph->dest; + upper_port = udph->source; + } + } else { + // non tcp/udp protocols + lower_port = 0; + upper_port = 0; + } + + flow.protocol = iph->protocol, flow.vlan_id = vlan_id; + flow.lower_ip = lower_ip, flow.upper_ip = upper_ip; + flow.lower_port = lower_port, flow.upper_port = upper_port; + + if(0) + printf("[NDPI] [%u][%u:%u <-> %u:%u]\n", + iph->protocol, lower_ip, ntohs(lower_port), upper_ip, ntohs(upper_port)); + + idx = (vlan_id + lower_ip + upper_ip + iph->protocol + lower_port + upper_port) % NUM_ROOTS; + ret = ndpi_tfind(&flow, &ndpi_thread_info[thread_id].ndpi_flows_root[idx], node_cmp); + + if(ret == NULL) { + if(ndpi_thread_info[thread_id].stats.ndpi_flow_count == MAX_NDPI_FLOWS) { + printf("ERROR: maximum flow count (%u) has been exceeded\n", MAX_NDPI_FLOWS); + exit(-1); + } else { + struct ndpi_flow *newflow = (struct ndpi_flow*)malloc(sizeof(struct ndpi_flow)); + + if(newflow == NULL) { + printf("[NDPI] %s(1): not enough memory\n", __FUNCTION__); + return(NULL); + } + + 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; + + if(version == 4) { + inet_ntop(AF_INET, &lower_ip, newflow->lower_name, sizeof(newflow->lower_name)); + inet_ntop(AF_INET, &upper_ip, newflow->upper_name, sizeof(newflow->upper_name)); + } else { + inet_ntop(AF_INET6, &iph6->ip6_src, newflow->lower_name, sizeof(newflow->lower_name)); + inet_ntop(AF_INET6, &iph6->ip6_dst, newflow->upper_name, sizeof(newflow->upper_name)); + } + + if((newflow->ndpi_flow = malloc_wrapper(size_flow_struct)) == NULL) { + printf("[NDPI] %s(2): not enough memory\n", __FUNCTION__); + 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__); + 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__); + return(NULL); + } else + memset(newflow->dst_id, 0, size_id_struct); + + 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); + } + } 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; + } +} + +/* ***************************************************** */ + +static struct ndpi_flow *get_ndpi_flow6(u_int16_t thread_id, + u_int16_t vlan_id, + const struct ndpi_ip6_hdr *iph6, + u_int16_t ip_offset, + struct ndpi_id_struct **src, + struct ndpi_id_struct **dst, + u_int8_t *proto) { + struct ndpi_iphdr iph; + + memset(&iph, 0, sizeof(iph)); + iph.version = 4; + iph.saddr = iph6->ip6_src.__u6_addr.__u6_addr32[2] + iph6->ip6_src.__u6_addr.__u6_addr32[3]; + iph.daddr = iph6->ip6_dst.__u6_addr.__u6_addr32[2] + iph6->ip6_dst.__u6_addr.__u6_addr32[3]; + iph.protocol = iph6->ip6_ctlun.ip6_un1.ip6_un1_nxt; + + if(iph.protocol == 0x3C /* IPv6 destination option */) { + u_int8_t *options = (u_int8_t*)iph6 + sizeof(const struct ndpi_ip6_hdr); + + iph.protocol = options[0]; + } + + 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)); +} + +/* ***************************************************** */ + +static void setupDetection(u_int16_t thread_id) { + NDPI_PROTOCOL_BITMASK all; + + memset(&ndpi_thread_info[thread_id], 0, sizeof(ndpi_thread_info[thread_id])); + + // init global detection structure + ndpi_thread_info[thread_id].ndpi_struct = ndpi_init_detection_module(detection_tick_resolution, + malloc_wrapper, free_wrapper, debug_printf); + if(ndpi_thread_info[thread_id].ndpi_struct == NULL) { + printf("ERROR: global structure initialization failed\n"); + exit(-1); + } + + if(full_http_dissection) + ndpi_thread_info[thread_id].ndpi_struct->http_dissect_response = 1; + + // enable all protocols + NDPI_BITMASK_SET_ALL(all); + ndpi_set_protocol_detection_bitmask2(ndpi_thread_info[thread_id].ndpi_struct, &all); + + // allocate memory for id and flow tracking + size_id_struct = ndpi_detection_get_sizeof_ndpi_id_struct(); + size_flow_struct = ndpi_detection_get_sizeof_ndpi_flow_struct(); + + // clear memory for results + memset(ndpi_thread_info[thread_id].stats.protocol_counter, 0, sizeof(ndpi_thread_info[thread_id].stats.protocol_counter)); + memset(ndpi_thread_info[thread_id].stats.protocol_counter_bytes, 0, sizeof(ndpi_thread_info[thread_id].stats.protocol_counter_bytes)); + memset(ndpi_thread_info[thread_id].stats.protocol_flows, 0, sizeof(ndpi_thread_info[thread_id].stats.protocol_flows)); + + if(_protoFilePath != NULL) + ndpi_load_protocols_file(ndpi_thread_info[thread_id].ndpi_struct, _protoFilePath); +} + +/* ***************************************************** */ + +static void terminateDetection(u_int16_t thread_id) { + int i; + + for(i=0; i<NUM_ROOTS; i++) { + ndpi_tdestroy(ndpi_thread_info[thread_id].ndpi_flows_root[i], ndpi_flow_freer); + ndpi_thread_info[thread_id].ndpi_flows_root[i] = NULL; + } + + ndpi_exit_detection_module(ndpi_thread_info[thread_id].ndpi_struct, free_wrapper); +} + +/* ***************************************************** */ + +// ipsize = header->len - ip_offset ; rawsize = header->len +static unsigned int packet_processing(u_int16_t thread_id, + const u_int64_t time, + u_int16_t vlan_id, + const struct ndpi_iphdr *iph, + struct ndpi_ip6_hdr *iph6, + u_int16_t ip_offset, + u_int16_t ipsize, u_int16_t rawsize) { + struct ndpi_id_struct *src, *dst; + struct ndpi_flow *flow; + struct ndpi_flow_struct *ndpi_flow = NULL; + 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); + else + flow = get_ndpi_flow6(thread_id, vlan_id, iph6, ip_offset, &src, &dst, &proto); + + if(flow != NULL) { + ndpi_thread_info[thread_id].stats.ip_packet_count++; + ndpi_thread_info[thread_id].stats.total_wire_bytes += rawsize + 24 /* CRC etc */, ndpi_thread_info[thread_id].stats.total_ip_bytes += rawsize; + ndpi_flow = flow->ndpi_flow; + flow->packets++, flow->bytes += rawsize; + flow->last_seen = time; + } else { + return(0); + } + + if(flow->detection_completed) return(0); + + protocol = (const u_int32_t)ndpi_detection_process_packet(ndpi_thread_info[thread_id].ndpi_struct, ndpi_flow, + iph ? (uint8_t *)iph : (uint8_t *)iph6, + ipsize, time, src, dst); + + flow->detected_protocol = protocol; + + if((flow->detected_protocol != NDPI_PROTOCOL_UNKNOWN) + || ((proto == IPPROTO_UDP) && (flow->packets > 8)) + || ((proto == IPPROTO_TCP) && (flow->packets > 10))) { + flow->detection_completed = 1; + + snprintf(flow->host_server_name, sizeof(flow->host_server_name), "%s", flow->ndpi_flow->host_server_name); + + if((proto == IPPROTO_TCP) && (flow->detected_protocol != NDPI_PROTOCOL_DNS)) { + snprintf(flow->ssl.client_certificate, sizeof(flow->ssl.client_certificate), "%s", flow->ndpi_flow->protos.ssl.client_certificate); + snprintf(flow->ssl.server_certificate, sizeof(flow->ssl.server_certificate), "%s", flow->ndpi_flow->protos.ssl.server_certificate); + } + + if(( + (flow->detected_protocol == NDPI_PROTOCOL_HTTP) + || (flow->detected_protocol == NDPI_SERVICE_FACEBOOK) + ) + && full_http_dissection) { + char *method; + + printf("[URL] %s\n", ndpi_get_http_url(ndpi_thread_info[thread_id].ndpi_struct, ndpi_flow)); + printf("[Content-Type] %s\n", ndpi_get_http_content_type(ndpi_thread_info[thread_id].ndpi_struct, ndpi_flow)); + + switch(ndpi_get_http_method(ndpi_thread_info[thread_id].ndpi_struct, ndpi_flow)) { + case HTTP_METHOD_OPTIONS: method = "HTTP_METHOD_OPTIONS"; break; + case HTTP_METHOD_GET: method = "HTTP_METHOD_GET"; break; + case HTTP_METHOD_HEAD: method = "HTTP_METHOD_HEAD"; break; + case HTTP_METHOD_POST: method = "HTTP_METHOD_POST"; break; + case HTTP_METHOD_PUT: method = "HTTP_METHOD_PUT"; break; + case HTTP_METHOD_DELETE: method = "HTTP_METHOD_DELETE"; break; + case HTTP_METHOD_TRACE: method = "HTTP_METHOD_TRACE"; break; + case HTTP_METHOD_CONNECT: method = "HTTP_METHOD_CONNECT"; break; + default: method = "HTTP_METHOD_UNKNOWN"; break; + } + + printf("[Method] %s\n", method); + } + + free_ndpi_flow(flow); + + if(verbose > 1) { + if(enable_protocol_guess) { + if(flow->detected_protocol == 0 /* UNKNOWN */) { + protocol = node_guess_undetected_protocol(thread_id, flow); + } + } + + printFlow(thread_id, flow); + } + } + +#if 0 + if(ndpi_flow->l4.tcp.host_server_name[0] != '\0') + printf("%s\n", ndpi_flow->l4.tcp.host_server_name); +#endif + + if(live_capture) { + if(ndpi_thread_info[thread_id].last_idle_scan_time + IDLE_SCAN_PERIOD < ndpi_thread_info[thread_id].last_time) { + /* scan for idle flows */ + ndpi_twalk(ndpi_thread_info[thread_id].ndpi_flows_root[ndpi_thread_info[thread_id].idle_scan_idx], node_idle_scan_walker, &thread_id); + + /* remove idle flows (unfortunately we cannot do this inline) */ + while (ndpi_thread_info[thread_id].num_idle_flows > 0) + ndpi_tdelete(ndpi_thread_info[thread_id].idle_flows[--ndpi_thread_info[thread_id].num_idle_flows], + &ndpi_thread_info[thread_id].ndpi_flows_root[ndpi_thread_info[thread_id].idle_scan_idx], node_cmp); + + if(++ndpi_thread_info[thread_id].idle_scan_idx == NUM_ROOTS) ndpi_thread_info[thread_id].idle_scan_idx = 0; + ndpi_thread_info[thread_id].last_idle_scan_time = ndpi_thread_info[thread_id].last_time; + } + } + + return 0; +} + +/* ****************************************************** */ + +char* formatTraffic(float numBits, int bits, char *buf) { + char unit; + + if(bits) + unit = 'b'; + else + unit = 'B'; + + if(numBits < 1024) { + snprintf(buf, 32, "%lu %c", (unsigned long)numBits, unit); + } else if(numBits < 1048576) { + snprintf(buf, 32, "%.2f K%c", (float)(numBits)/1024, unit); + } else { + float tmpMBits = ((float)numBits)/1048576; + + if(tmpMBits < 1024) { + snprintf(buf, 32, "%.2f M%c", tmpMBits, unit); + } else { + tmpMBits /= 1024; + + if(tmpMBits < 1024) { + snprintf(buf, 32, "%.2f G%c", tmpMBits, unit); + } else { + snprintf(buf, 32, "%.2f T%c", (float)(tmpMBits)/1024, unit); + } + } + } + + return(buf); +} + +/* ***************************************************** */ + +char* formatPackets(float numPkts, char *buf) { + if(numPkts < 1000) { + snprintf(buf, 32, "%.2f", numPkts); + } else if(numPkts < 1000000) { + snprintf(buf, 32, "%.2f K", numPkts/1000); + } else { + numPkts /= 1000000; + snprintf(buf, 32, "%.2f M", numPkts); + } + + return(buf); +} + +/* ***************************************************** */ + +#ifdef HAVE_JSON_C +static void json_init() { + jArray_known_flows = json_object_new_array(); + jArray_unknown_flows = json_object_new_array(); +} +#endif + +/* ***************************************************** */ + +char* formatBytes(u_int32_t howMuch, char *buf, u_int buf_len) { + char unit = 'B'; + + if(howMuch < 1024) { + snprintf(buf, buf_len, "%lu %c", (unsigned long)howMuch, unit); + } else if(howMuch < 1048576) { + snprintf(buf, buf_len, "%.2f K%c", (float)(howMuch)/1024, unit); + } else { + float tmpGB = ((float)howMuch)/1048576; + + if(tmpGB < 1024) { + snprintf(buf, buf_len, "%.2f M%c", tmpGB, unit); + } else { + tmpGB /= 1024; + + snprintf(buf, buf_len, "%.2f G%c", tmpGB, unit); + } + } + + return(buf); +} + +/* ***************************************************** */ + +static void printResults(u_int64_t tot_usec) { + u_int32_t i; + u_int64_t total_flow_bytes = 0; + u_int avg_pkt_size = 0; + struct thread_stats cumulative_stats; + int thread_id; + char buf[32]; +#ifdef HAVE_JSON_C + FILE *json_fp; + json_object *jObj_main, *jObj_trafficStats, *jArray_detProto, *jObj; +#endif + long long unsigned int breed_stats[NUM_BREEDS] = { 0 }; + + memset(&cumulative_stats, 0, sizeof(cumulative_stats)); + + for(thread_id = 0; thread_id < num_threads; thread_id++) { + if(ndpi_thread_info[thread_id].stats.total_wire_bytes == 0) continue; + + for(i=0; i<NUM_ROOTS; i++) + ndpi_twalk(ndpi_thread_info[thread_id].ndpi_flows_root[i], node_proto_guess_walker, &thread_id); + + /* Stats aggregation */ + cumulative_stats.guessed_flow_protocols += ndpi_thread_info[thread_id].stats.guessed_flow_protocols; + cumulative_stats.raw_packet_count += ndpi_thread_info[thread_id].stats.raw_packet_count; + cumulative_stats.ip_packet_count += ndpi_thread_info[thread_id].stats.ip_packet_count; + cumulative_stats.total_wire_bytes += ndpi_thread_info[thread_id].stats.total_wire_bytes; + cumulative_stats.total_ip_bytes += ndpi_thread_info[thread_id].stats.total_ip_bytes; + cumulative_stats.total_discarded_bytes += ndpi_thread_info[thread_id].stats.total_discarded_bytes; + + for(i = 0; i < ndpi_get_num_supported_protocols(ndpi_thread_info[0].ndpi_struct); i++) { + cumulative_stats.protocol_counter[i] += ndpi_thread_info[thread_id].stats.protocol_counter[i]; + cumulative_stats.protocol_counter_bytes[i] += ndpi_thread_info[thread_id].stats.protocol_counter_bytes[i]; + cumulative_stats.protocol_flows[i] += ndpi_thread_info[thread_id].stats.protocol_flows[i]; + } + + cumulative_stats.ndpi_flow_count += ndpi_thread_info[thread_id].stats.ndpi_flow_count; + cumulative_stats.tcp_count += ndpi_thread_info[thread_id].stats.tcp_count; + cumulative_stats.udp_count += ndpi_thread_info[thread_id].stats.udp_count; + cumulative_stats.mpls_count += ndpi_thread_info[thread_id].stats.mpls_count; + cumulative_stats.pppoe_count += ndpi_thread_info[thread_id].stats.pppoe_count; + cumulative_stats.vlan_count += ndpi_thread_info[thread_id].stats.vlan_count; + cumulative_stats.fragmented_count += ndpi_thread_info[thread_id].stats.fragmented_count; + for(i = 0; i < 6; i++) + cumulative_stats.packet_len[i] += ndpi_thread_info[thread_id].stats.packet_len[i]; + cumulative_stats.max_packet_len += ndpi_thread_info[thread_id].stats.max_packet_len; + } + + printf("\nnDPI Memory statistics:\n"); + printf("\tnDPI Memory (once): %-13s\n", formatBytes(sizeof(struct ndpi_detection_module_struct), buf, sizeof(buf))); + printf("\tFlow Memory (per flow): %-13s\n", formatBytes(size_flow_struct, buf, sizeof(buf))); + printf("\tActual Memory: %-13s\n", formatBytes(current_ndpi_memory, buf, sizeof(buf))); + printf("\tPeak Memory: %-13s\n", formatBytes(max_ndpi_memory, buf, sizeof(buf))); + + if(!json_flag) { + 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 = (float)(cumulative_stats.ip_packet_count*1000000)/(float)tot_usec; + float b = (float)(cumulative_stats.total_wire_bytes * 8 *1000000)/(float)tot_usec; + float traffic_duration; + if (live_capture) traffic_duration = tot_usec; + else traffic_duration = (pcap_end.tv_sec*1000000 + pcap_end.tv_usec) - (pcap_start.tv_sec*1000000 + 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*1000000)/(float)traffic_duration; + b = (float)(cumulative_stats.total_wire_bytes * 8 *1000000)/(float)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); + } + + if(enable_protocol_guess) + printf("\tGuessed flow protos: %-13u\n", cumulative_stats.guessed_flow_protocols); + } else { +#ifdef HAVE_JSON_C + if((json_fp = fopen(_jsonFilePath,"w")) == NULL) { + printf("Error create .json file\n"); + json_flag = 0; + } else { + jObj_main = json_object_new_object(); + jObj_trafficStats = json_object_new_object(); + jArray_detProto = json_object_new_array(); + + json_object_object_add(jObj_trafficStats,"ethernet.bytes",json_object_new_int64(cumulative_stats.total_wire_bytes)); + json_object_object_add(jObj_trafficStats,"discarded.bytes",json_object_new_int64(cumulative_stats.total_discarded_bytes)); + json_object_object_add(jObj_trafficStats,"ip.packets",json_object_new_int64(cumulative_stats.ip_packet_count)); + json_object_object_add(jObj_trafficStats,"total.packets",json_object_new_int64(cumulative_stats.raw_packet_count)); + json_object_object_add(jObj_trafficStats,"ip.bytes",json_object_new_int64(cumulative_stats.total_ip_bytes)); + json_object_object_add(jObj_trafficStats,"avg.pkt.size",json_object_new_int(cumulative_stats.total_ip_bytes/cumulative_stats.raw_packet_count)); + json_object_object_add(jObj_trafficStats,"unique.flows",json_object_new_int(cumulative_stats.ndpi_flow_count)); + json_object_object_add(jObj_trafficStats,"tcp.pkts",json_object_new_int64(cumulative_stats.tcp_count)); + json_object_object_add(jObj_trafficStats,"udp.pkts",json_object_new_int64(cumulative_stats.udp_count)); + json_object_object_add(jObj_trafficStats,"vlan.pkts",json_object_new_int64(cumulative_stats.vlan_count)); + json_object_object_add(jObj_trafficStats,"mpls.pkts",json_object_new_int64(cumulative_stats.mpls_count)); + json_object_object_add(jObj_trafficStats,"pppoe.pkts",json_object_new_int64(cumulative_stats.pppoe_count)); + json_object_object_add(jObj_trafficStats,"fragmented.pkts",json_object_new_int64(cumulative_stats.fragmented_count)); + json_object_object_add(jObj_trafficStats,"max.pkt.size",json_object_new_int(cumulative_stats.max_packet_len)); + json_object_object_add(jObj_trafficStats,"pkt.len_min64",json_object_new_int64(cumulative_stats.packet_len[0])); + json_object_object_add(jObj_trafficStats,"pkt.len_64_128",json_object_new_int64(cumulative_stats.packet_len[1])); + json_object_object_add(jObj_trafficStats,"pkt.len_128_256",json_object_new_int64(cumulative_stats.packet_len[2])); + json_object_object_add(jObj_trafficStats,"pkt.len_256_1024",json_object_new_int64(cumulative_stats.packet_len[3])); + json_object_object_add(jObj_trafficStats,"pkt.len_1024_1500",json_object_new_int64(cumulative_stats.packet_len[4])); + json_object_object_add(jObj_trafficStats,"pkt.len_grt1500",json_object_new_int64(cumulative_stats.packet_len[5])); + json_object_object_add(jObj_trafficStats,"guessed.flow.protos",json_object_new_int(cumulative_stats.guessed_flow_protocols)); + + json_object_object_add(jObj_main,"traffic.statistics",jObj_trafficStats); + } +#endif + } + + if(!json_flag) printf("\n\nDetected protocols:\n"); + for(i = 0; i <= ndpi_get_num_supported_protocols(ndpi_thread_info[0].ndpi_struct); i++) { + ndpi_protocol_breed_t breed = ndpi_get_proto_breed(ndpi_thread_info[0].ndpi_struct, i); + + if(cumulative_stats.protocol_counter[i] > 0) { + breed_stats[breed] += (long long unsigned int)cumulative_stats.protocol_counter_bytes[i]; + + if(!json_flag) { + printf("\t%-20s packets: %-13llu bytes: %-13llu " + "flows: %-13u\n", + ndpi_get_proto_name(ndpi_thread_info[0].ndpi_struct, i), + (long long unsigned int)cumulative_stats.protocol_counter[i], + (long long unsigned int)cumulative_stats.protocol_counter_bytes[i], + cumulative_stats.protocol_flows[i]); + } else { +#ifdef HAVE_JSON_C + jObj = json_object_new_object(); + + json_object_object_add(jObj,"name",json_object_new_string(ndpi_get_proto_name(ndpi_thread_info[0].ndpi_struct, i))); + json_object_object_add(jObj,"breed",json_object_new_string(ndpi_get_proto_breed_name(ndpi_thread_info[0].ndpi_struct, breed))); + json_object_object_add(jObj,"packets",json_object_new_int64(cumulative_stats.protocol_counter[i])); + json_object_object_add(jObj,"bytes",json_object_new_int64(cumulative_stats.protocol_counter_bytes[i])); + json_object_object_add(jObj,"flows",json_object_new_int(cumulative_stats.protocol_flows[i])); + + json_object_array_add(jArray_detProto,jObj); +#endif + } + + total_flow_bytes += cumulative_stats.protocol_counter_bytes[i]; + } + } + + if(!json_flag) { + printf("\n\nProtocol statistics:\n"); + + for(i=0; i < NUM_BREEDS; i++) { + if(breed_stats[i] > 0) { + printf("\t%-20s %13llu bytes\n", + ndpi_get_proto_breed_name(ndpi_thread_info[0].ndpi_struct, i), + breed_stats[i]); + } + } + } + + // printf("\n\nTotal Flow Traffic: %llu (diff: %llu)\n", total_flow_bytes, cumulative_stats.total_ip_bytes-total_flow_bytes); + + if(verbose) { + if(!json_flag) printf("\n"); + + num_flows = 0; + for(thread_id = 0; thread_id < num_threads; thread_id++) { + for(i=0; i<NUM_ROOTS; i++) + ndpi_twalk(ndpi_thread_info[thread_id].ndpi_flows_root[i], node_print_known_proto_walker, &thread_id); + } + + for(thread_id = 0; thread_id < num_threads; thread_id++) { + if(ndpi_thread_info[thread_id].stats.protocol_counter[0 /* 0 = Unknown */] > 0) { + if(!json_flag) { + printf("\n\nUndetected flows:%s\n", undetected_flows_deleted ? " (expired flows are not listed below)" : ""); + } + + if(json_flag) + json_flag = 2; + break; + } + } + + num_flows = 0; + for(thread_id = 0; thread_id < num_threads; thread_id++) { + if(ndpi_thread_info[thread_id].stats.protocol_counter[0] > 0) { + for(i=0; i<NUM_ROOTS; i++) + ndpi_twalk(ndpi_thread_info[thread_id].ndpi_flows_root[i], node_print_unknown_proto_walker, &thread_id); + } + } + } + + if(json_flag != 0) { +#ifdef HAVE_JSON_C + json_object_object_add(jObj_main,"detected.protos",jArray_detProto); + json_object_object_add(jObj_main,"known.flows",jArray_known_flows); + + if(json_object_array_length(jArray_unknown_flows) != 0) + json_object_object_add(jObj_main,"unknown.flows",jArray_unknown_flows); + + fprintf(json_fp,"%s\n",json_object_to_json_string(jObj_main)); + fclose(json_fp); +#endif + } +} + +/* ***************************************************** */ + +static void closePcapFile(u_int16_t thread_id) { + if(ndpi_thread_info[thread_id]._pcap_handle != NULL) { + pcap_close(ndpi_thread_info[thread_id]._pcap_handle); + } +} + +/* ***************************************************** */ + +static void breakPcapLoop(u_int16_t thread_id) { + if(ndpi_thread_info[thread_id]._pcap_handle != NULL) { + pcap_breakloop(ndpi_thread_info[thread_id]._pcap_handle); + } +} + +/* ***************************************************** */ + +// executed for each packet in the pcap file +void sigproc(int sig) { + static int called = 0; + int thread_id; + + if(called) return; else called = 1; + shutdown_app = 1; + + for(thread_id=0; thread_id<num_threads; thread_id++) + breakPcapLoop(thread_id); +} + +/* ***************************************************** */ + +static int getNextPcapFileFromPlaylist(u_int16_t thread_id, char filename[], u_int32_t filename_len) { + + if(playlist_fp[thread_id] == NULL) { + if((playlist_fp[thread_id] = fopen(_pcap_file[thread_id], "r")) == NULL) + return -1; + } + + next_line: + if(fgets(filename, filename_len, playlist_fp[thread_id])) { + int l = strlen(filename); + if(filename[0] == '\0' || filename[0] == '#') goto next_line; + if(filename[l-1] == '\n') filename[l-1] = '\0'; + return 0; + } else { + fclose(playlist_fp[thread_id]); + playlist_fp[thread_id] = NULL; + return -1; + } +} + +/* ***************************************************** */ + +static void configurePcapHandle(u_int16_t thread_id) { + ndpi_thread_info[thread_id]._pcap_datalink_type = pcap_datalink(ndpi_thread_info[thread_id]._pcap_handle); + + if(_bpf_filter != NULL) { + struct bpf_program fcode; + + if(pcap_compile(ndpi_thread_info[thread_id]._pcap_handle, &fcode, _bpf_filter, 1, 0xFFFFFF00) < 0) { + printf("pcap_compile error: '%s'\n", pcap_geterr(ndpi_thread_info[thread_id]._pcap_handle)); + } else { + if(pcap_setfilter(ndpi_thread_info[thread_id]._pcap_handle, &fcode) < 0) { + printf("pcap_setfilter error: '%s'\n", pcap_geterr(ndpi_thread_info[thread_id]._pcap_handle)); + } else + printf("Successfully set BPF filter to '%s'\n", _bpf_filter); + } + } +} + +/* ***************************************************** */ + +static void openPcapFileOrDevice(u_int16_t thread_id) { + u_int snaplen = 1536; + int promisc = 1; + char errbuf[PCAP_ERRBUF_SIZE]; + + /* trying to open a live interface */ + if((ndpi_thread_info[thread_id]._pcap_handle = pcap_open_live(_pcap_file[thread_id], snaplen, promisc, 500, errbuf)) == NULL) { + capture_for = capture_until = 0; + + live_capture = 0; + num_threads = 1; /* Open pcap files in single threads mode */ + + /* trying to open a pcap file */ + if((ndpi_thread_info[thread_id]._pcap_handle = pcap_open_offline(_pcap_file[thread_id], ndpi_thread_info[thread_id]._pcap_error_buffer)) == NULL) { + char filename[256]; + + /* trying to open a pcap playlist */ + if(getNextPcapFileFromPlaylist(thread_id, filename, sizeof(filename)) != 0 || + (ndpi_thread_info[thread_id]._pcap_handle = pcap_open_offline(filename, ndpi_thread_info[thread_id]._pcap_error_buffer)) == NULL) { + + printf("ERROR: could not open pcap file or playlist: %s\n", ndpi_thread_info[thread_id]._pcap_error_buffer); + exit(-1); + } else { + if(!json_flag) printf("Reading packets from playlist %s...\n", _pcap_file[thread_id]); + } + } else { + if(!json_flag) printf("Reading packets from pcap file %s...\n", _pcap_file[thread_id]); + } + } else { + live_capture = 1; + + if(!json_flag) printf("Capturing live traffic from device %s...\n", _pcap_file[thread_id]); + } + + configurePcapHandle(thread_id); + + if(capture_for > 0) { + if(!json_flag) printf("Capturing traffic up to %u seconds\n", (unsigned int)capture_for); + +#ifndef WIN32 + alarm(capture_for); + signal(SIGALRM, sigproc); +#endif + } +} + +/* ***************************************************** */ + +static void pcap_packet_callback(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { + const struct ndpi_ethhdr *ethernet; + struct ndpi_iphdr *iph; + struct ndpi_ip6_hdr *iph6; + u_int64_t time; + u_int16_t type, ip_offset, ip_len; + u_int16_t frag_off = 0, vlan_id = 0; + u_int8_t proto = 0, vlan_packet = 0; + u_int16_t thread_id = *((u_int16_t*)args); + + // 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++; + + if((capture_until != 0) && (header->ts.tv_sec >= capture_until)) { + if(ndpi_thread_info[thread_id]._pcap_handle != NULL) + pcap_breakloop(ndpi_thread_info[thread_id]._pcap_handle); + + return; + } + + if (!live_capture) { + if (!pcap_start.tv_sec) pcap_start.tv_sec = header->ts.tv_sec, pcap_start.tv_usec = header->ts.tv_usec; + pcap_end.tv_sec = header->ts.tv_sec, pcap_end.tv_usec = header->ts.tv_usec; + } + + time = ((uint64_t) header->ts.tv_sec) * detection_tick_resolution + + header->ts.tv_usec / (1000000 / detection_tick_resolution); + + if(ndpi_thread_info[thread_id].last_time > time) { /* safety check */ + // printf("\nWARNING: timestamp bug in the pcap file (ts delta: %llu, repairing)\n", ndpi_thread_info[thread_id].last_time - time); + time = ndpi_thread_info[thread_id].last_time; + } + ndpi_thread_info[thread_id].last_time = time; + + if(ndpi_thread_info[thread_id]._pcap_datalink_type == DLT_NULL) { + if(ntohl(*((u_int32_t*)packet)) == 2) + type = ETH_P_IP; + else + type = 0x86DD; /* IPv6 */ + + ip_offset = 4; + } else if(ndpi_thread_info[thread_id]._pcap_datalink_type == DLT_EN10MB) { + ethernet = (struct ndpi_ethhdr *) packet; + ip_offset = sizeof(struct ndpi_ethhdr); + type = ntohs(ethernet->h_proto); + } 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; + + while(1) { + if(type == 0x8100 /* VLAN */) { + vlan_id = ((packet[ip_offset] << 8) + packet[ip_offset+1]) & 0xFFF; + type = (packet[ip_offset+2] << 8) + packet[ip_offset+3]; + ip_offset += 4; + vlan_packet = 1; + } else if(type == 0x8847 /* MPLS */) { + u_int32_t label = ntohl(*((u_int32_t*)&packet[ip_offset])); + + ndpi_thread_info[thread_id].stats.mpls_count++; + type = 0x800, ip_offset += 4; + + while((label & 0x100) != 0x100) { + ip_offset += 4; + label = ntohl(*((u_int32_t*)&packet[ip_offset])); + } + } else if(type == 0x8864 /* PPPoE */) { + ndpi_thread_info[thread_id].stats.pppoe_count++; + type = 0x0800; + ip_offset += 8; + } else + break; + } + + ndpi_thread_info[thread_id].stats.vlan_count += vlan_packet; + + iph = (struct ndpi_iphdr *) &packet[ip_offset]; + + // just work on Ethernet packets that contain IP + if(type == ETH_P_IP && header->caplen >= ip_offset) { + frag_off = ntohs(iph->frag_off); + + proto = iph->protocol; + if(header->caplen < header->len) { + static u_int8_t cap_warning_used = 0; + + if(cap_warning_used == 0) { + if(!json_flag) printf("\n\nWARNING: packet capture size is smaller than packet size, DETECTION MIGHT NOT WORK CORRECTLY\n\n"); + cap_warning_used = 1; + } + } + } + + if(iph->version == 4) { + ip_len = ((u_short)iph->ihl * 4); + iph6 = NULL; + + if((frag_off & 0x3FFF) != 0) { + static u_int8_t ipv4_frags_warning_used = 0; + + ndpi_thread_info[thread_id].stats.fragmented_count++; + if(ipv4_frags_warning_used == 0) { + if(!json_flag) printf("\n\nWARNING: IPv4 fragments are not handled by this demo (nDPI supports them)\n"); + ipv4_frags_warning_used = 1; + } + + ndpi_thread_info[thread_id].stats.total_discarded_bytes += header->len; + return; + } + } else if(iph->version == 6) { + iph6 = (struct ndpi_ip6_hdr *)&packet[ip_offset]; + proto = iph6->ip6_ctlun.ip6_un1.ip6_un1_nxt; + ip_len = sizeof(struct ndpi_ip6_hdr); + + if(proto == 0x3C /* IPv6 destination option */) { + u_int8_t *options = (u_int8_t*)&packet[ip_offset+ip_len]; + + proto = options[0]; + ip_len += 8 * (options[1] + 1); + } + + iph = NULL; + } else { + static u_int8_t ipv4_warning_used = 0; + + v4_warning: + if(ipv4_warning_used == 0) { + if(!json_flag) printf("\n\nWARNING: only IPv4/IPv6 packets are supported in this demo (nDPI supports both IPv4 and IPv6), all other packets will be discarded\n\n"); + ipv4_warning_used = 1; + } + + ndpi_thread_info[thread_id].stats.total_discarded_bytes += header->len; + return; + } + + if(decode_tunnels && (proto == IPPROTO_UDP)) { + struct ndpi_udphdr *udp = (struct ndpi_udphdr *)&packet[ip_offset+ip_len]; + u_int16_t sport = ntohs(udp->source), dport = ntohs(udp->dest); + + if((sport == GTP_U_V1_PORT) || (dport == GTP_U_V1_PORT)) { + /* Check if it's GTPv1 */ + u_int offset = ip_offset+ip_len+sizeof(struct ndpi_udphdr); + u_int8_t flags = packet[offset]; + u_int8_t message_type = packet[offset+1]; + + if((((flags & 0xE0) >> 5) == 1 /* GTPv1 */) && (message_type == 0xFF /* T-PDU */)) { + ip_offset = ip_offset+ip_len+sizeof(struct ndpi_udphdr)+8 /* GTPv1 header len */; + + if(flags & 0x04) ip_offset += 1; /* next_ext_header is present */ + if(flags & 0x02) ip_offset += 4; /* sequence_number is present (it also includes next_ext_header and pdu_number) */ + if(flags & 0x01) ip_offset += 1; /* pdu_number is present */ + + iph = (struct ndpi_iphdr *) &packet[ip_offset]; + + if(iph->version != 4) { + // printf("WARNING: not good (packet_id=%u)!\n", (unsigned int)ndpi_thread_info[thread_id].stats.raw_packet_count); + goto v4_warning; + } + } + } + } + + // process the packet + packet_processing(thread_id, time, vlan_id, iph, iph6, + ip_offset, header->len - ip_offset, header->len); +} + +/* ******************************************************************** */ + +static void runPcapLoop(u_int16_t thread_id) { + if((!shutdown_app) && (ndpi_thread_info[thread_id]._pcap_handle != NULL)) + pcap_loop(ndpi_thread_info[thread_id]._pcap_handle, -1, &pcap_packet_callback, (u_char*)&thread_id); +} + +/* ******************************************************************** */ + +void *processing_thread(void *_thread_id) { + long thread_id = (long) _thread_id; + +#ifdef linux + if(core_affinity[thread_id] >= 0) { + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(core_affinity[thread_id], &cpuset); + + if(pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) + fprintf(stderr, "Error while binding thread %ld to core %d\n", thread_id, core_affinity[thread_id]); + else { + if(!json_flag) printf("Running thread %ld on core %d...\n", thread_id, core_affinity[thread_id]); + } + } else +#endif + if(!json_flag) printf("Running thread %ld...\n", thread_id); + + pcap_loop: + runPcapLoop(thread_id); + + if(playlist_fp[thread_id] != NULL) { /* playlist: read next file */ + char filename[256]; + + if(getNextPcapFileFromPlaylist(thread_id, filename, sizeof(filename)) == 0 && + (ndpi_thread_info[thread_id]._pcap_handle = pcap_open_offline(filename, ndpi_thread_info[thread_id]._pcap_error_buffer)) != NULL) { + configurePcapHandle(thread_id); + goto pcap_loop; + } + } + + return NULL; +} + +/* ******************************************************************** */ + +void test_lib() { + struct timeval begin, end; + u_int64_t tot_usec; + long thread_id; + +#ifdef HAVE_JSON_C + json_init(); +#endif + + for(thread_id = 0; thread_id < num_threads; thread_id++) { + setupDetection(thread_id); + openPcapFileOrDevice(thread_id); + } + + gettimeofday(&begin, NULL); + + /* Running processing threads */ + for(thread_id = 0; thread_id < num_threads; thread_id++) + pthread_create(&ndpi_thread_info[thread_id].pthread, NULL, processing_thread, (void *) thread_id); + + /* Waiting for completion */ + for(thread_id = 0; thread_id < num_threads; thread_id++) + pthread_join(ndpi_thread_info[thread_id].pthread, NULL); + + gettimeofday(&end, NULL); + tot_usec = end.tv_sec*1000000 + end.tv_usec - (begin.tv_sec*1000000 + begin.tv_usec); + + /* Printing cumulative results */ + printResults(tot_usec); + + for(thread_id = 0; thread_id < num_threads; thread_id++) { + closePcapFile(thread_id); + terminateDetection(thread_id); + } +} + +/* ***************************************************** */ + +int main(int argc, char **argv) { + int i; + + memset(ndpi_thread_info, 0, sizeof(ndpi_thread_info)); + memset(&pcap_start, 0, sizeof(pcap_start)); + memset(&pcap_end, 0, sizeof(pcap_end)); + + parseOptions(argc, argv); + + if(!json_flag) { + printf("\n-----------------------------------------------------------\n" + "* NOTE: This is demo app to show *some* nDPI features.\n" + "* In this demo we have implemented only some basic features\n" + "* just to show you what you can do with the library. Feel \n" + "* free to extend it and send us the patches for inclusion\n" + "------------------------------------------------------------\n\n"); + + printf("Using nDPI (%s) [%d thread(s)]\n", ndpi_revision(), num_threads); + } + + signal(SIGINT, sigproc); + + for(i=0; i<num_loops; i++) + test_lib(); + + return 0; +} + +/* ****************************************************** */ + +#ifdef WIN32 +#ifndef __GNUC__ +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + +struct timezone { + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +/* ***************************************************** */ + +#if 0 +int gettimeofday(struct timeval *tv, void *notUsed) { + tv->tv_sec = time(NULL); + tv->tv_usec = 0; + return(0); +} +#endif + +/* ***************************************************** */ + +int gettimeofday(struct timeval *tv, struct timezone *tz) { + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + static int tzflag; + + if(tv) { + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + } + + if(tz) { + if(!tzflag) { + _tzset(); + tzflag++; + } + + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} +#endif /* WIN32 */ diff --git a/example/protos.txt b/example/protos.txt new file mode 100644 index 000000000..722399da9 --- /dev/null +++ b/example/protos.txt @@ -0,0 +1,18 @@ +# Format: +# <tcp|udp>:<port>,<tcp|udp>:<port>,.....@<proto> + +tcp:81,tcp:8181@HTTP +udp:5061-5062@SIP +tcp:860,udp:860,tcp:3260,udp:3260@iSCSI +tcp:3000@ntop + +# Subprotocols +# Format: +# host:"<value>",host:"<value>",.....@<subproto> + +host:"googlesyndacation.com"@Google +host:"venere.com"@Venere +host:"kataweb.it",host:"repubblica.it"@Repubblica + + + |