├── TODO ├── .gitignore ├── Makefile ├── protos.txt ├── README.md ├── AppCat.csv ├── linux_compat.h ├── pcapReader.c └── nDPI.html /TODO: -------------------------------------------------------------------------------- 1 | TODO-list: 2 | Enhance the live detection function to output flow results as detection 3 | finishes. 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | 4 | # Libraries 5 | *.lib 6 | *.a 7 | 8 | # Shared objects (inc. Windows DLLs) 9 | *.dll 10 | *.so 11 | *.so.* 12 | *.dylib 13 | 14 | # Executables 15 | *.exe 16 | *.out 17 | *.app 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## A simple makefile 2 | # Extra headers and libraries from env vars 3 | INC=-I/usr/local/include/libndpi/ -I. -I$(INCLUDE_PATH) -I$(C_INCLUDE_PATH) 4 | LIB=-L$(LIBRARY_PATH) 5 | 6 | all: pcapDPI 7 | 8 | pcapDPI: pcapReader.c 9 | gcc -g pcapReader.c -o pcapDPI $(INC) $(LIB) -lpcap -lndpi 10 | 11 | clean: 12 | \/bin/rm -f pcapDPI 13 | -------------------------------------------------------------------------------- /protos.txt: -------------------------------------------------------------------------------- 1 | # Format: 2 | # :,:,.....@ 3 | 4 | tcp:81,tcp:8181@HTTP 5 | udp:5061-5062@SIP 6 | tcp:860,udp:860,tcp:3260,udp:3260@iSCSI 7 | tcp:3000@ntop 8 | 9 | # Subprotocols 10 | # Format: 11 | # host:"",host:"",.....@ 12 | 13 | host:"googlesyndacation.com"@Google 14 | host:"venere.com"@Venere 15 | host:"kataweb.it",host:"repubblica.it"@Repubblica 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pcapDPI 2 | ======= 3 | 4 | A program modified based on the nDPI example in the source package 5 | to use nDPI (openDPI) interfaces to detect flow protocols. 6 | 7 | Modifications 8 | ----------- 9 | 10 | Add a `-w` option to the example program in nDPI. 11 | 12 | Add a simple tree walker of the internal search tree implemented 13 | by nDPI to index flows efficiently. 14 | 15 | Output file has a .csv format which is accepted directly by plenty 16 | of data processing softwares. A piece of text for ex. 17 | 18 | source_ip source_port dest_ip dest_port l4_proto detect_proto packets bytes 19 | 202.233.233.233 27753 114.112.67.195 80 TCP 7/HTTP 7 751 20 | 192.88.99.1 0 202.233.233.233 0 41 0/Unknown 485 64975 21 | 210.46.79.1 51752 202.233.233.233 27955 TCP 0/Unknown 3 194 22 | 192.88.99.1 0 202.233.233.233 0 41 0/Unknown 485 64975 23 | 24 | How To Install 25 | ------------ 26 | 27 | Users can make pcapDPI work following two steps: 28 | 29 | 30 | First, you must have nDPI installed. nDPI can be obtained from its website: http://www.ntop.org/products/ndpi/ and 31 | a standard linux package installation operation can be made to install it on your system. 32 | 33 | 34 | * COPY HEADER FILES MANUALLY: some header files like `linux_compact.h` are not installed by default when installing 35 | nDPI with command `make install`. You should copy them into your local include path manually. E.g., on my computer 36 | running Ubuntu 12.04 32bit, run following commands to get there: 37 | 38 | 39 | $cd nDPI 40 | $cp src/include/*.h /usr/local/include/libndpi-1.4/libndpi/ 41 | 42 | 43 | Second, download pcapDPI from https://github.com/caesar0301/pcapDPI and simply run `make` to compile it. 44 | 45 | 46 | * NOTE: if the `make` command raises errors about finding header files and/or libraries in your system 47 | envirement variables, you can edit the Makefile with `INC` and/or `LIB` variables to search 48 | your local folders. 49 | 50 | 51 | AppCat.csv 52 | -------------- 53 | 54 | A manual classification of application protocols identified by nDPI. 55 | The application ID comes from nDPIsrc/include/ndpi_protocols_osdpi.h 56 | 57 | 58 | Enjoy. 59 | 60 | 61 | by chenxm 62 | 2013-03-16 63 | -------------------------------------------------------------------------------- /AppCat.csv: -------------------------------------------------------------------------------- 1 | ID ShortDesp Category 2 | 0 Unknown Other 3 | 1 FTP FileService 4 | 2 POP Mail 5 | 3 SMTP Mail 6 | 4 IMAP Mail 7 | 5 DNS NetMan 8 | 6 IPP Netman 9 | 7 HTTP HTTP 10 | 8 MDNS NetMan 11 | 9 NTP NetMan 12 | 10 NETBIOS NetMan 13 | 11 NFS FileService 14 | 12 SSDP NetMan 15 | 13 BGP NetMan 16 | 14 SNMP NetMan 17 | 15 XDMCP RemoteLogin 18 | 16 SMB FileService 19 | 17 SYSLOG NetMan 20 | 18 DHCP NetMan 21 | 19 PostgreSQL Database 22 | 20 MySQL Database 23 | 21 TDS FileService 24 | 22 DirectDownloadLink FileService 25 | 23 I23V5 Other 26 | 24 AppleJuice P2P 27 | 25 DirectConnect P2P 28 | 26 Socrates P2P 29 | 27 WinMX P2P 30 | 28 VMware Other 31 | 29 PANDO P2P 32 | 30 Filetopia FileService 33 | 31 iMESH P2P 34 | 32 Kontiki P2P 35 | 33 OpenFT P2P 36 | 34 KazaaFasttrack P2P 37 | 35 Gnutella P2P 38 | 36 eDonkey P2P 39 | 37 Bittorrent P2P 40 | 38 OFF Other 41 | 39 AVI Streaming 42 | 40 Flash Streaming 43 | 41 OGG Streaming 44 | 42 MPEG Streaming 45 | 43 QuickTime Streaming 46 | 44 RealMedia Streaming 47 | 45 Windowsmedia Streaming 48 | 46 MMS Streaming 49 | 47 XBOX Gaming 50 | 48 QQ IM 51 | 49 MOVE Streaming 52 | 50 RTSP Streaming 53 | 51 Feidian Streaming 54 | 52 Icecast Streaming 55 | 53 PPLive Streaming 56 | 54 PPStream Streaming 57 | 55 Zattoo Streaming 58 | 56 SHOUTCast Streaming 59 | 57 SopCast Streaming 60 | 58 TVAnts Streaming 61 | 59 TVUplayer Streaming 62 | 60 VeohTV Streaming 63 | 61 QQLive Streaming 64 | 62 Thunder P2P 65 | 63 Soulseek P2P 66 | 64 GaduGadu IM 67 | 65 IRC IM 68 | 66 Popo IM 69 | 67 Jabber IM 70 | 68 MSN IM 71 | 69 Oscar IM 72 | 70 Yahoo IM 73 | 71 Battlefield Gaming 74 | 72 Quake Gaming 75 | 73 VRRP NetMan 76 | 74 Steam Gaming 77 | 75 Halflife2 Gaming 78 | 76 WorldofWarcraft Gaming 79 | 77 Telnet RemoteLogin 80 | 78 STUN NetMan 81 | 79 IPSEC NetMan 82 | 80 GRE NetMan 83 | 81 ICMP NetMan 84 | 82 IGMP NetMan 85 | 83 EGP NetMan 86 | 84 SCTP NetMan 87 | 85 OSPF NetMan 88 | 86 IPinIP NetMan 89 | 87 RTP NetMan 90 | 88 RDP RemoteLogin 91 | 89 VNC RemoteLogin 92 | 90 PCAnywhere RemoteLogin 93 | 91 SSL NetMan 94 | 92 SSH RemoteLogin 95 | 93 USENET News 96 | 94 MGCP NetMan 97 | 95 IAX VoIP 98 | 96 TFTP FileService 99 | 97 AFP FileService 100 | 98 StealthNet P2P 101 | 99 Aimini Streaming 102 | 100 SIP IM 103 | 101 Truphone IM 104 | 102 ICMPv6 NetMan 105 | 103 DHCPv6 NetMan 106 | 104 Armagetron Gaming 107 | 105 CrossFire Gaming 108 | 106 Dofus Gaming 109 | 107 Fiesta Gaming 110 | 108 Florensia Gaming 111 | 109 Guildwars Gaming 112 | 110 HTTPApplicationActiveSync NetMan 113 | 111 Kerberos Authentication 114 | 112 LDAP Authentication 115 | 113 MapleStory Gaming 116 | 114 msSQL Database 117 | 115 PPTP Privacy 118 | 116 WARCRAFT3 Gaming 119 | 117 WorldofKungFu Gaming 120 | 118 MEEBO Social 121 | 119 FaceBook Social 122 | 120 Twitter Social 123 | 121 DropBox FileService 124 | 122 Gmail Mail 125 | 123 GoogleMaps Maps 126 | 124 YouTube Streaming 127 | 125 Skype IM 128 | 126 Google Google 129 | 127 DCERPC NetMan 130 | 128 NetFlowIPFIX NetMan 131 | 129 sFlow NetMan 132 | 130 HTTPConnect HTTP 133 | 131 HTTPProxy HTTP 134 | 132 Citrix IM 135 | 133 Netflix Streaming 136 | 134 LastFM Streaming 137 | 135 GrooveShark Streaming 138 | 136 SkyfilePrepaid Streaming 139 | 137 SkyfileRudics Streaming 140 | 138 SkyfilePostpaid Streaming 141 | 139 CitrixOnline IM 142 | 140 Apple IM 143 | 141 Webex IM 144 | 142 WhatsApp IM 145 | 143 AppleiCloud FileService 146 | 144 Viber IM 147 | 145 AppleiTunes Streaming 148 | 146 Radius Authentication 149 | 147 WindowsUpdate Update 150 | 148 TeamViewer IM 151 | 149 Tuenti Social 152 | 150 LotusNotes IM 153 | 151 SAP NetMan 154 | 152 GTP NetMan 155 | 153 UPnP NetMan 156 | 154 LLMNR NetMan 157 | 155 RemoteScan NetMan 158 | 156 Spotify Streaming 159 | 157 WebM Streaming 160 | 158 H323 Streaming 161 | 159 OpenVPN Privacy 162 | 160 NOE Streaming 163 | 161 CiscoVPN Privacy 164 | 162 TeamSpeak IM 165 | 163 Tor Privacy 166 | 164 CiscoSkinny IM 167 | 165 RTCP NetMan 168 | 166 RSYNC FileService 169 | 167 Oracle Database 170 | 168 Corba NetMan 171 | 169 UbuntuONE FileService 172 | -------------------------------------------------------------------------------- /linux_compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * linux_compat.h 3 | * 4 | * Copyright (C) 2009-2011 by ipoque GmbH 5 | * Copyright (C) 2011-13 - ntop.org 6 | * 7 | * This file is part of nDPI, an open source deep packet inspection 8 | * library based on the OpenDPI and PACE technology by ipoque GmbH 9 | * 10 | * nDPI is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Lesser General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * nDPI is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public License 21 | * along with nDPI. If not, see . 22 | * 23 | */ 24 | 25 | 26 | #ifndef __NDPI_LINUX_COMPAT_H__ 27 | #define __NDPI_LINUX_COMPAT_H__ 28 | 29 | #include "ndpi_define.h" 30 | 31 | #if defined(__FreeBSD__) || defined(__NetBSD__) 32 | #include 33 | 34 | #if _BYTE_ORDER == _LITTLE_ENDIAN 35 | #define __LITTLE_ENDIAN__ 1 36 | #else 37 | #define __BIG_ENDIAN__ 1 38 | #endif 39 | #endif 40 | 41 | #pragma pack(push) /* push current alignment to stack */ 42 | #pragma pack(1) /* set alignment to 1 byte boundary */ 43 | 44 | #pragma pack(pop) /* restore original alignment from stack */ 45 | 46 | struct ndpi_ethhdr { 47 | u_char h_dest[6]; /* destination eth addr */ 48 | u_char h_source[6]; /* source ether addr */ 49 | u_int16_t h_proto; /* packet type ID field */ 50 | }; 51 | 52 | struct ndpi_80211q { 53 | u_int16_t vlanId; 54 | u_int16_t protoType; 55 | }; 56 | 57 | struct ndpi_iphdr { 58 | #if defined(__LITTLE_ENDIAN__) 59 | u_int8_t ihl:4, version:4; 60 | #elif defined(__BIG_ENDIAN__) 61 | u_int8_t version:4, ihl:4; 62 | #else 63 | # error "Byte order must be defined" 64 | #endif 65 | u_int8_t tos; 66 | u_int16_t tot_len; 67 | u_int16_t id; 68 | u_int16_t frag_off; 69 | u_int8_t ttl; 70 | u_int8_t protocol; 71 | u_int16_t check; 72 | u_int32_t saddr; 73 | u_int32_t daddr; 74 | }; 75 | 76 | 77 | #ifdef WIN32 78 | 79 | typedef unsigned char u_char; 80 | typedef unsigned short u_short; 81 | typedef unsigned int uint; 82 | typedef unsigned long u_long; 83 | typedef u_char u_int8_t; 84 | typedef u_short u_int16_t; 85 | typedef uint u_int32_t; 86 | 87 | #define _WS2TCPIP_H_ /* Avoid compilation problems */ 88 | #define HAVE_SIN6_LEN 89 | 90 | 91 | /* IPv6 address */ 92 | /* Already defined in WS2tcpip.h */ 93 | struct ndpi_win_in6_addr 94 | { 95 | union 96 | { 97 | u_int8_t u6_addr8[16]; 98 | u_int16_t u6_addr16[8]; 99 | u_int32_t u6_addr32[4]; 100 | } in6_u; 101 | #ifdef s6_addr 102 | #undef s6_addr 103 | #endif 104 | 105 | #ifdef s6_addr16 106 | #undef s6_addr16 107 | #endif 108 | 109 | #ifdef s6_addr32 110 | #undef s6_addr32 111 | #endif 112 | 113 | #define s6_addr in6_u.u6_addr8 114 | // #define s6_addr16 in6_u.u6_addr16 115 | // #define s6_addr32 in6_u.u6_addr32 116 | 117 | }; 118 | 119 | #define in6_addr win_in6_addr 120 | 121 | /* Generic extension header. */ 122 | struct ndpi_ip6_ext 123 | { 124 | u_int8_t ip6e_nxt; /* next header. */ 125 | u_int8_t ip6e_len; /* length in units of 8 octets. */ 126 | }; 127 | 128 | #define s6_addr16 __u6_addr.__u6_addr16 129 | #define s6_addr32 __u6_addr.__u6_addr32 130 | #else 131 | #ifndef __KERNEL__ 132 | #include 133 | #endif 134 | #endif 135 | 136 | 137 | 138 | struct ndpi_in6_addr { 139 | union { 140 | u_int8_t __u6_addr8[16]; 141 | u_int16_t __u6_addr16[8]; 142 | u_int32_t __u6_addr32[4]; 143 | } __u6_addr; /* 128-bit IP6 address */ 144 | }; 145 | 146 | struct ndpi_ip6_hdr { 147 | union { 148 | struct ndpi_ip6_hdrctl { 149 | u_int32_t ip6_un1_flow; 150 | u_int16_t ip6_un1_plen; 151 | u_int8_t ip6_un1_nxt; 152 | u_int8_t ip6_un1_hlim; 153 | } ip6_un1; 154 | u_int8_t ip6_un2_vfc; 155 | } ip6_ctlun; 156 | struct ndpi_in6_addr ip6_src; 157 | struct ndpi_in6_addr ip6_dst; 158 | }; 159 | 160 | struct ndpi_tcphdr { 161 | u_int16_t source; 162 | u_int16_t dest; 163 | u_int32_t seq; 164 | u_int32_t ack_seq; 165 | #if defined(__LITTLE_ENDIAN__) 166 | u_int16_t res1:4, doff:4, fin:1, syn:1, rst:1, psh:1, ack:1, urg:1, ece:1, cwr:1; 167 | #elif defined(__BIG_ENDIAN__) 168 | u_int16_t doff:4, res1:4, cwr:1, ece:1, urg:1, ack:1, psh:1, rst:1, syn:1, fin:1; 169 | #else 170 | # error "Byte order must be defined" 171 | #endif 172 | u_int16_t window; 173 | u_int16_t check; 174 | u_int16_t urg_ptr; 175 | }; 176 | 177 | struct ndpi_udphdr { 178 | u_int16_t source; 179 | u_int16_t dest; 180 | u_int16_t len; 181 | u_int16_t check; 182 | }; 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /pcapReader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pcapReader.c 3 | * 4 | * Copyright (C) 2013 by chenxm 5 | * Copyright (C) 2011-13 - ntop.org 6 | * Copyright (C) 2009-2011 by ipoque GmbH 7 | * 8 | * nDPI is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * nDPI is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with nDPI. If not, see . 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "linux_compat.h" 34 | #include "ndpi_main.h" 35 | 36 | static void setupDetection(void); 37 | 38 | // cli options 39 | static char *_pcap_file = NULL; 40 | static char *_bpf_filter = NULL; 41 | static char *_protoFilePath = NULL; 42 | 43 | // pcap 44 | static char _pcap_error_buffer[PCAP_ERRBUF_SIZE]; 45 | static pcap_t *_pcap_handle = NULL; 46 | static int _pcap_datalink_type = 0; 47 | static u_int8_t enable_protocol_guess = 1, verbose = 0; 48 | static u_int32_t guessed_flow_protocols = 0; 49 | static u_int16_t decode_tunnels = 0; 50 | static u_int16_t num_loops = 1; 51 | static u_int8_t shutdown_app = 0; 52 | 53 | // detection 54 | static struct ndpi_detection_module_struct *ndpi_struct = NULL; 55 | static u_int32_t detection_tick_resolution = 1000; 56 | static time_t capture_until = 0; 57 | 58 | // results 59 | static u_int64_t raw_packet_count = 0; 60 | static u_int64_t ip_packet_count = 0; 61 | static u_int64_t total_bytes = 0; 62 | static u_int64_t protocol_counter[NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1]; 63 | static u_int64_t protocol_counter_bytes[NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1]; 64 | static u_int32_t protocol_flows[NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1] = { 0 }; 65 | 66 | // log file 67 | static FILE *flow_info_file; 68 | static char *flow_info_file_name; 69 | 70 | #define GTP_U_V1_PORT 2152 71 | #define MAX_NDPI_FLOWS 20000000 72 | // id tracking 73 | typedef struct ndpi_id { 74 | u_int8_t ip[4]; 75 | struct ndpi_id_struct *ndpi_id; 76 | } ndpi_id_t; 77 | 78 | static u_int32_t size_id_struct = 0; 79 | 80 | #ifndef ETH_P_IP 81 | #define ETH_P_IP 0x0800 82 | #endif 83 | 84 | // flow tracking 85 | typedef struct ndpi_flow { 86 | u_int32_t lower_ip; 87 | u_int32_t upper_ip; 88 | u_int16_t lower_port; 89 | u_int16_t upper_port; 90 | u_int32_t first_packet_time_sec; 91 | u_int32_t first_packet_time_usec; 92 | u_int8_t detection_completed, protocol; 93 | struct ndpi_flow_struct *ndpi_flow; 94 | 95 | u_int16_t packets, bytes; 96 | // result only, not used for flow identification 97 | u_int16_t detected_protocol; 98 | 99 | void *src_id, *dst_id; 100 | } ndpi_flow_t; 101 | 102 | static u_int32_t size_flow_struct = 0; 103 | static struct ndpi_flow *ndpi_flows_root = NULL; 104 | static u_int32_t ndpi_flow_count = 0; 105 | 106 | 107 | static void help(u_int long_help) { 108 | printf("pcapReader -i [-f ][-s ]\n" 109 | " [-p ][-w ][-l [-d][-h][-t][-v]\n\n" 110 | "Usage:\n" 111 | " -i | Specify a pcap file to read packets from or a device for live capture\n" 112 | " -f | Specify a BPF filter for filtering selected traffic\n" 113 | " -s | Maximum capture duration in seconds (live traffic capture only)\n" 114 | " -p .protos | Specify a protocol file (eg. protos.txt)\n" 115 | " -w | Specify a output file (default: out.dpi.csv) to save detectd result for each flow\n" 116 | " -l | Number of detection loops (test only)\n" 117 | " -d | Disable protocol guess and use only DPI\n" 118 | " -t | Dissect GTP tunnels\n" 119 | " -h | This help\n" 120 | " -v | Verbose 'unknown protocol' packet print\n"); 121 | 122 | if(long_help) { 123 | printf("\n\nSupported protocols:\n"); 124 | setupDetection(); 125 | ndpi_dump_protocols(ndpi_struct); 126 | } 127 | 128 | exit(-1); 129 | } 130 | 131 | static void parseOptions(int argc, char **argv) 132 | { 133 | int opt; 134 | 135 | while ((opt = getopt(argc, argv, "df:i:hp:w:l:s:tv")) != EOF) { 136 | switch (opt) { 137 | case 'd': 138 | enable_protocol_guess = 0; 139 | break; 140 | 141 | case 'i': 142 | _pcap_file = optarg; 143 | break; 144 | 145 | case 'f': 146 | _bpf_filter = optarg; 147 | break; 148 | 149 | case 'l': 150 | num_loops = atoi(optarg); 151 | break; 152 | 153 | case 'p': 154 | _protoFilePath = optarg; 155 | break; 156 | 157 | case 'w': 158 | flow_info_file_name = optarg; 159 | break; 160 | 161 | case 's': 162 | capture_until = atoi(optarg); 163 | break; 164 | 165 | case 't': 166 | decode_tunnels = 1; 167 | break; 168 | 169 | case 'v': 170 | verbose = 1; 171 | break; 172 | 173 | case 'h': 174 | help(1); 175 | break; 176 | 177 | default: 178 | help(0); 179 | break; 180 | } 181 | } 182 | 183 | // check parameters 184 | if (_pcap_file == NULL || strcmp(_pcap_file, "") == 0) help(0); 185 | if (flow_info_file_name == NULL || strcmp(flow_info_file_name, "") == 0) 186 | flow_info_file_name = "out.dpi.csv"; // default 187 | } 188 | 189 | static void debug_printf(u_int32_t protocol, void *id_struct, 190 | ndpi_log_level_t log_level, 191 | const char *format, ...) { 192 | } 193 | 194 | static void *malloc_wrapper(unsigned long size) 195 | { 196 | return malloc(size); 197 | } 198 | 199 | static void free_wrapper(void *freeable) 200 | { 201 | free(freeable); 202 | } 203 | 204 | 205 | static char* ipProto2Name(u_short proto_id) { 206 | static char proto[8]; 207 | 208 | switch(proto_id) { 209 | case IPPROTO_TCP: 210 | return("TCP"); 211 | break; 212 | case IPPROTO_UDP: 213 | return("UDP"); 214 | break; 215 | case IPPROTO_ICMP: 216 | return("ICMP"); 217 | break; 218 | case 112: 219 | return("VRRP"); 220 | break; 221 | } 222 | 223 | snprintf(proto, sizeof(proto), "%u", proto_id); 224 | return(proto); 225 | } 226 | 227 | /* 228 | * A faster replacement for inet_ntoa(). 229 | */ 230 | char* intoaV4(unsigned int addr, char* buf, u_short bufLen) { 231 | char *cp, *retStr; 232 | uint byte; 233 | int n; 234 | 235 | cp = &buf[bufLen]; 236 | *--cp = '\0'; 237 | 238 | n = 4; 239 | do { 240 | byte = addr & 0xff; 241 | *--cp = byte % 10 + '0'; 242 | byte /= 10; 243 | if (byte > 0) { 244 | *--cp = byte % 10 + '0'; 245 | byte /= 10; 246 | if (byte > 0) 247 | *--cp = byte + '0'; 248 | } 249 | *--cp = '.'; 250 | addr >>= 8; 251 | } while (--n > 0); 252 | 253 | /* Convert the string to lowercase */ 254 | retStr = (char*)(cp+1); 255 | 256 | return(retStr); 257 | } 258 | 259 | static void printFlow(struct ndpi_flow *flow) { 260 | char buf1[32], buf2[32]; 261 | 262 | printf("\t%s %s:%u > %s:%u [proto: %u/%s][%u pkts/%u bytes]\n", 263 | ipProto2Name(flow->protocol), 264 | intoaV4(ntohl(flow->lower_ip), buf1, sizeof(buf1)), 265 | ntohs(flow->lower_port), 266 | intoaV4(ntohl(flow->upper_ip), buf2, sizeof(buf2)), 267 | ntohs(flow->upper_port), 268 | flow->detected_protocol, 269 | ndpi_get_proto_name(ndpi_struct, flow->detected_protocol), 270 | flow->packets, flow->bytes); 271 | } 272 | 273 | static void fPrintFlow(FILE *stream, struct ndpi_flow *flow) { 274 | char buf1[32], buf2[32]; 275 | 276 | fprintf(stream, "%s %u %s %u %.6f %s %u/%s %u %u\n", 277 | intoaV4(ntohl(flow->lower_ip), buf1, sizeof(buf1)), 278 | ntohs(flow->lower_port), 279 | intoaV4(ntohl(flow->upper_ip), buf2, sizeof(buf2)), 280 | ntohs(flow->upper_port), 281 | flow->first_packet_time_sec + flow->first_packet_time_usec/1000000.0, 282 | ipProto2Name(flow->protocol), 283 | flow->detected_protocol, 284 | ndpi_get_proto_name(ndpi_struct, flow->detected_protocol), 285 | flow->packets, flow->bytes); 286 | } 287 | 288 | static void node_print_unknown_proto_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { 289 | struct ndpi_flow *flow = *(struct ndpi_flow**)node; 290 | 291 | if (flow->detected_protocol != 0 /* UNKNOWN */) return; 292 | 293 | if((which == preorder) || (which == leaf)) /* Avoid walking the same node multiple times */ 294 | printFlow(flow); 295 | } 296 | 297 | static void node_proto_guess_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { 298 | struct ndpi_flow *flow = *(struct ndpi_flow**)node; 299 | char buf1[32], buf2[32]; 300 | 301 | #if 0 302 | printf("<%d>Walk on node %s (%p)\n", 303 | depth, 304 | which == preorder?"preorder": 305 | which == postorder?"postorder": 306 | which == endorder?"endorder": 307 | which == leaf?"leaf": "unknown", 308 | flow); 309 | #endif 310 | 311 | if((which == preorder) || (which == leaf)) { /* Avoid walking the same node multiple times */ 312 | if(enable_protocol_guess) { 313 | if (flow->detected_protocol == 0 /* UNKNOWN */) { 314 | ndpi_protocol guessed = ndpi_guess_undetected_protocol(ndpi_struct, 315 | flow->protocol, 316 | ntohl(flow->lower_ip), 317 | ntohs(flow->lower_port), 318 | ntohl(flow->upper_ip), 319 | ntohs(flow->upper_port)); 320 | flow->detected_protocol = guessed.master_protocol; 321 | 322 | if (flow->detected_protocol != 0) 323 | guessed_flow_protocols++; 324 | 325 | // printFlow(flow); 326 | } 327 | } 328 | 329 | protocol_counter[flow->detected_protocol] += flow->packets; 330 | protocol_counter_bytes[flow->detected_protocol] += flow->bytes; 331 | protocol_flows[flow->detected_protocol]++; 332 | } 333 | } 334 | 335 | // 2013-03-16: added by chenxm to log detected results 336 | static void node_output_flow_info_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { 337 | struct ndpi_flow *flow = *(struct ndpi_flow**)node; 338 | if ( flow_info_file != NULL){ 339 | if ((which == preorder) || (which == leaf)) fPrintFlow(flow_info_file, flow); 340 | } 341 | else {printf("Invalid file stream!\n"); exit(-1);} 342 | } 343 | 344 | static int node_cmp(const void *a, const void *b) { 345 | struct ndpi_flow *fa = (struct ndpi_flow*)a; 346 | struct ndpi_flow *fb = (struct ndpi_flow*)b; 347 | 348 | if(fa->lower_ip < fb->lower_ip) return(-1); else { if(fa->lower_ip > fb->lower_ip) return(1); } 349 | if(fa->lower_port < fb->lower_port) return(-1); else { if(fa->lower_port > fb->lower_port) return(1); } 350 | if(fa->upper_ip < fb->upper_ip) return(-1); else { if(fa->upper_ip > fb->upper_ip) return(1); } 351 | if(fa->upper_port < fb->upper_port) return(-1); else { if(fa->upper_port > fb->upper_port) return(1); } 352 | if(fa->protocol < fb->protocol) return(-1); else { if(fa->protocol > fb->protocol) return(1); } 353 | 354 | return(0); 355 | } 356 | 357 | 358 | static struct ndpi_flow *get_ndpi_flow(const struct pcap_pkthdr *header, 359 | const struct ndpi_iphdr *iph, u_int16_t ipsize) 360 | { 361 | u_int32_t i; 362 | u_int16_t l4_packet_len; 363 | struct ndpi_tcphdr *tcph = NULL; 364 | struct ndpi_udphdr *udph = NULL; 365 | u_int32_t lower_ip; 366 | u_int32_t upper_ip; 367 | u_int16_t lower_port; 368 | u_int16_t upper_port; 369 | struct ndpi_flow flow; 370 | void *ret; 371 | 372 | if (ipsize < 20) 373 | return NULL; 374 | 375 | if ((iph->ihl * 4) > ipsize || ipsize < ntohs(iph->tot_len) 376 | || (iph->frag_off & htons(0x1FFF)) != 0) 377 | return NULL; 378 | 379 | l4_packet_len = ntohs(iph->tot_len) - (iph->ihl * 4); 380 | 381 | if (iph->saddr < iph->daddr) { 382 | lower_ip = iph->saddr; 383 | upper_ip = iph->daddr; 384 | } else { 385 | lower_ip = iph->daddr; 386 | upper_ip = iph->saddr; 387 | } 388 | 389 | if (iph->protocol == 6 && l4_packet_len >= 20) { 390 | // tcp 391 | tcph = (struct ndpi_tcphdr *) ((u_int8_t *) iph + iph->ihl * 4); 392 | if (iph->saddr < iph->daddr) { 393 | lower_port = tcph->source; 394 | upper_port = tcph->dest; 395 | } else { 396 | lower_port = tcph->dest; 397 | upper_port = tcph->source; 398 | } 399 | } else if (iph->protocol == 17 && l4_packet_len >= 8) { 400 | // udp 401 | udph = (struct ndpi_udphdr *) ((u_int8_t *) iph + iph->ihl * 4); 402 | if (iph->saddr < iph->daddr) { 403 | lower_port = udph->source; 404 | upper_port = udph->dest; 405 | } else { 406 | lower_port = udph->dest; 407 | upper_port = udph->source; 408 | } 409 | } else { 410 | // non tcp/udp protocols 411 | lower_port = 0; 412 | upper_port = 0; 413 | } 414 | 415 | flow.protocol = iph->protocol; 416 | flow.lower_ip = lower_ip; 417 | flow.upper_ip = upper_ip; 418 | flow.lower_port = lower_port; 419 | flow.upper_port = upper_port; 420 | flow.first_packet_time_sec = header->ts.tv_sec; 421 | flow.first_packet_time_usec = header->ts.tv_usec; 422 | 423 | ret = ndpi_tfind(&flow, (void*)&ndpi_flows_root, node_cmp); 424 | 425 | if(ret == NULL) { 426 | if (ndpi_flow_count == MAX_NDPI_FLOWS) { 427 | printf("ERROR: maximum flow count (%u) has been exceeded\n", MAX_NDPI_FLOWS); 428 | exit(-1); 429 | } else { 430 | struct ndpi_flow *newflow = (struct ndpi_flow*)malloc(sizeof(struct ndpi_flow)); 431 | 432 | if(newflow == NULL) { 433 | printf("[NDPI] %s(1): not enough memory\n", __FUNCTION__); 434 | return(NULL); 435 | } 436 | 437 | memset(newflow, 0, sizeof(struct ndpi_flow)); 438 | newflow->protocol = iph->protocol; 439 | newflow->lower_ip = lower_ip, newflow->upper_ip = upper_ip; 440 | newflow->lower_port = lower_port, newflow->upper_port = upper_port; 441 | newflow->first_packet_time_sec = header->ts.tv_sec; 442 | newflow->first_packet_time_usec = header->ts.tv_usec; 443 | 444 | if((newflow->ndpi_flow = calloc(1, size_flow_struct)) == NULL) { 445 | printf("[NDPI] %s(2): not enough memory\n", __FUNCTION__); 446 | return(NULL); 447 | } 448 | 449 | if((newflow->src_id = calloc(1, size_id_struct)) == NULL) { 450 | printf("[NDPI] %s(3): not enough memory\n", __FUNCTION__); 451 | return(NULL); 452 | } 453 | 454 | if((newflow->dst_id = calloc(1, size_id_struct)) == NULL) { 455 | printf("[NDPI] %s(4): not enough memory\n", __FUNCTION__); 456 | return(NULL); 457 | } 458 | 459 | ndpi_tsearch(newflow, (void*)&ndpi_flows_root, node_cmp); /* Add */ 460 | 461 | ndpi_flow_count += 1; 462 | 463 | //printFlow(newflow); 464 | return(newflow); 465 | } 466 | } else 467 | return *(struct ndpi_flow**)ret; 468 | } 469 | 470 | static void setupDetection(void) 471 | { 472 | u_int32_t i; 473 | NDPI_PROTOCOL_BITMASK all; 474 | 475 | // init global detection structure 476 | ndpi_struct = ndpi_init_detection_module(detection_tick_resolution, malloc_wrapper, free_wrapper, debug_printf); 477 | if (ndpi_struct == NULL) { 478 | printf("ERROR: global structure initialization failed\n"); 479 | exit(-1); 480 | } 481 | // enable all protocols 482 | NDPI_BITMASK_SET_ALL(all); 483 | ndpi_set_protocol_detection_bitmask2(ndpi_struct, &all); 484 | 485 | // allocate memory for id and flow tracking 486 | size_id_struct = ndpi_detection_get_sizeof_ndpi_id_struct(); 487 | size_flow_struct = ndpi_detection_get_sizeof_ndpi_flow_struct(); 488 | 489 | // clear memory for results 490 | memset(protocol_counter, 0, sizeof(protocol_counter)); 491 | memset(protocol_counter_bytes, 0, sizeof(protocol_counter_bytes)); 492 | memset(protocol_flows, 0, sizeof(protocol_flows)); 493 | 494 | if(_protoFilePath != NULL) 495 | ndpi_load_protocols_file(ndpi_struct, _protoFilePath); 496 | 497 | raw_packet_count = ip_packet_count = total_bytes = 0; 498 | ndpi_flow_count = 0; 499 | } 500 | 501 | static void free_ndpi_flow(struct ndpi_flow *flow) { 502 | if(flow->ndpi_flow) { ndpi_free(flow->ndpi_flow); flow->ndpi_flow = NULL; } 503 | if(flow->src_id) { ndpi_free(flow->src_id); flow->src_id = NULL; } 504 | if(flow->dst_id) { ndpi_free(flow->dst_id); flow->dst_id = NULL; } 505 | } 506 | 507 | static void ndpi_flow_freer(void *node) { 508 | struct ndpi_flow *flow = (struct ndpi_flow*)node; 509 | free_ndpi_flow(flow); 510 | ndpi_free(flow); 511 | } 512 | 513 | 514 | static void terminateDetection(void) 515 | { 516 | ndpi_tdestroy(ndpi_flows_root, ndpi_flow_freer); 517 | ndpi_flows_root = NULL; 518 | ndpi_exit_detection_module(ndpi_struct, free_wrapper); 519 | } 520 | 521 | static unsigned int packet_processing(const u_int64_t time, const struct pcap_pkthdr *header, 522 | const struct ndpi_iphdr *iph, u_int16_t ipsize, u_int16_t rawsize) 523 | { 524 | struct ndpi_id_struct *src, *dst; 525 | struct ndpi_flow *flow; 526 | struct ndpi_flow_struct *ndpi_flow = NULL; 527 | u_int16_t protocol = 0; 528 | u_int16_t frag_off = ntohs(iph->frag_off); 529 | 530 | flow = get_ndpi_flow(header, iph, ipsize); 531 | if (flow != NULL) { 532 | ndpi_flow = flow->ndpi_flow; 533 | flow->packets++, flow->bytes += rawsize; 534 | src = flow->src_id, dst = flow->dst_id; 535 | } else 536 | return; 537 | 538 | ip_packet_count++; 539 | total_bytes += rawsize; 540 | 541 | if(flow->detection_completed) return; 542 | 543 | // only handle unfragmented packets 544 | if ((frag_off & 0x3FFF) == 0) { 545 | // here the actual detection is performed 546 | ndpi_protocol detected = ndpi_detection_process_packet(ndpi_struct, ndpi_flow, (uint8_t *) iph, ipsize, time, src, dst); 547 | protocol = detected.master_protocol; 548 | } else { 549 | static u_int8_t frag_warning_used = 0; 550 | 551 | if (frag_warning_used == 0) { 552 | printf("\n\nWARNING: fragmented ip packets are not supported and will be skipped \n\n"); 553 | frag_warning_used = 1; 554 | } 555 | 556 | return 0; 557 | } 558 | 559 | #if 0 560 | if(verbose && (protocol == 0)) { 561 | char buf1[32], buf2[32]; 562 | 563 | printf("%s %s:%u > %s:%u [proto: %u/%s]\n", 564 | ipProto2Name(flow->protocol), 565 | intoaV4(ntohl(flow->lower_ip), buf1, sizeof(buf1)), ntohs(flow->lower_port), 566 | intoaV4(ntohl(flow->upper_ip), buf2, sizeof(buf2)), ntohs(flow->upper_port), 567 | protocol, ndpi_get_proto_name(ndpi_struct, protocol)); 568 | } 569 | #endif 570 | 571 | flow->detected_protocol = protocol; 572 | 573 | if((flow->detected_protocol != NDPI_PROTOCOL_UNKNOWN) 574 | || (iph->protocol == IPPROTO_UDP) 575 | || ((iph->protocol == IPPROTO_TCP) && (flow->packets > 10))) { 576 | flow->detection_completed = 1; 577 | 578 | #if 0 579 | if(flow->ndpi_flow->l4.tcp.host_server_name[0] != '\0') 580 | printf("%s\n", flow->ndpi_flow->l4.tcp.host_server_name); 581 | #endif 582 | 583 | free_ndpi_flow(flow); 584 | } 585 | 586 | #if 0 587 | if(ndpi_flow->l4.tcp.host_server_name[0] != '\0') 588 | printf("%s\n", ndpi_flow->l4.tcp.host_server_name); 589 | #endif 590 | 591 | return 0; 592 | } 593 | 594 | static void printResults(void) 595 | { 596 | u_int32_t i, j; 597 | 598 | printf("\x1b[2K\n"); 599 | printf("pcap file contains\n"); 600 | printf("\tip packets: \x1b[33m%-13llu\x1b[0m of %llu packets total\n", 601 | (long long unsigned int)ip_packet_count, 602 | (long long unsigned int)raw_packet_count); 603 | printf("\tip bytes: \x1b[34m%-13llu\x1b[0m\n", 604 | (long long unsigned int)total_bytes); 605 | printf("\tunique flows: \x1b[36m%-13u\x1b[0m\n", ndpi_flow_count); 606 | 607 | ndpi_twalk(ndpi_flows_root, node_proto_guess_walker, NULL); 608 | if(enable_protocol_guess) 609 | printf("\tguessed flow protocols: \x1b[35m%-13u\x1b[0m\n", guessed_flow_protocols); 610 | 611 | printf("\n\ndetected protocols:\n"); 612 | for (i = 0; i <= ndpi_get_num_supported_protocols(ndpi_struct); i++) { 613 | if (protocol_counter[i] > 0) { 614 | printf("\t\x1b[31m%-20s\x1b[0m packets: \x1b[33m%-13llu\x1b[0m bytes: \x1b[34m%-13llu\x1b[0m " 615 | "flows: \x1b[36m%-13u\x1b[0m\n", 616 | ndpi_get_proto_name(ndpi_struct, i), (long long unsigned int)protocol_counter[i], 617 | (long long unsigned int)protocol_counter_bytes[i], protocol_flows[i]); 618 | } 619 | } 620 | 621 | if(verbose && (protocol_counter[0] > 0)) { 622 | printf("\n\nundetected flows:\n"); 623 | ndpi_twalk(ndpi_flows_root, node_print_unknown_proto_walker, NULL); 624 | } 625 | 626 | if (1) { 627 | flow_info_file = fopen(flow_info_file_name, "wb"); 628 | fputs("source_ip source_port dest_ip dest_port first_packet_time l4_proto detect_proto packets bytes\n", flow_info_file); 629 | ndpi_twalk(ndpi_flows_root, node_output_flow_info_walker, NULL); 630 | fclose(flow_info_file); 631 | } 632 | 633 | printf("\n\n"); 634 | } 635 | 636 | static void openPcapFileOrDevice(void) 637 | { 638 | u_int snaplen = 1514; 639 | int promisc = 1; 640 | char errbuf[PCAP_ERRBUF_SIZE]; 641 | 642 | if((_pcap_handle = pcap_open_live(_pcap_file, snaplen, promisc, 500, errbuf)) == NULL) { 643 | _pcap_handle = pcap_open_offline(_pcap_file, _pcap_error_buffer); 644 | capture_until = 0; 645 | 646 | if (_pcap_handle == NULL) { 647 | printf("ERROR: could not open pcap file: %s\n", _pcap_error_buffer); 648 | exit(-1); 649 | } else 650 | printf("Reading packets from pcap file %s...\n", _pcap_file); 651 | } else 652 | printf("Capturing live traffic from device %s...\n", _pcap_file); 653 | 654 | _pcap_datalink_type = pcap_datalink(_pcap_handle); 655 | 656 | if(_bpf_filter != NULL) { 657 | struct bpf_program fcode; 658 | 659 | if(pcap_compile(_pcap_handle, &fcode, _bpf_filter, 1, 0xFFFFFF00) < 0) { 660 | printf("pcap_compile error: '%s'\n", pcap_geterr(_pcap_handle)); 661 | } else { 662 | if(pcap_setfilter(_pcap_handle, &fcode) < 0) { 663 | printf("pcap_setfilter error: '%s'\n", pcap_geterr(_pcap_handle)); 664 | } else 665 | printf("Succesfully set BPF filter to '%s'\n", _bpf_filter); 666 | } 667 | } 668 | 669 | if(capture_until > 0) { 670 | printf("Capturing traffic up to %u seconds\n", (unsigned int)capture_until); 671 | capture_until += time(NULL); 672 | } 673 | } 674 | 675 | static void closePcapFile(void) 676 | { 677 | if (_pcap_handle != NULL) { 678 | pcap_close(_pcap_handle); 679 | } 680 | } 681 | 682 | void sigproc(int sig) { 683 | static int called = 0; 684 | 685 | if(called) return; else called = 1; 686 | shutdown_app = 1; 687 | 688 | closePcapFile(); 689 | printResults(); 690 | terminateDetection(); 691 | exit(0); 692 | } 693 | 694 | 695 | // executed for each packet in the pcap file 696 | static void pcap_packet_callback(u_char * args, const struct pcap_pkthdr *header, const u_char * packet) 697 | { 698 | const struct ndpi_ethhdr *ethernet = (struct ndpi_ethhdr *) packet; 699 | struct ndpi_iphdr *iph = (struct ndpi_iphdr *) &packet[sizeof(struct ndpi_ethhdr)]; 700 | u_int64_t time; 701 | static u_int64_t lasttime = 0; 702 | u_int16_t type, ip_offset; 703 | 704 | raw_packet_count++; 705 | 706 | if((capture_until != 0) && (header->ts.tv_sec >= capture_until)) { 707 | sigproc(0); 708 | return; 709 | } 710 | 711 | time = ((uint64_t) header->ts.tv_sec) * detection_tick_resolution + 712 | header->ts.tv_usec / (1000000 / detection_tick_resolution); 713 | if (lasttime > time) { 714 | // printf("\nWARNING: timestamp bug in the pcap file (ts delta: %llu, repairing)\n", lasttime - time); 715 | time = lasttime; 716 | } 717 | lasttime = time; 718 | 719 | 720 | type = ethernet->h_proto; 721 | 722 | // just work on Ethernet packets that contain IP 723 | if (_pcap_datalink_type == DLT_EN10MB && type == htons(ETH_P_IP) 724 | && header->caplen >= sizeof(struct ndpi_ethhdr)) { 725 | u_int16_t frag_off = ntohs(iph->frag_off); 726 | 727 | if(header->caplen < header->len) { 728 | static u_int8_t cap_warning_used = 0; 729 | if (cap_warning_used == 0) { 730 | printf("\n\nWARNING: packet capture size is smaller than packet size, DETECTION MIGHT NOT WORK CORRECTLY\n\n"); 731 | cap_warning_used = 1; 732 | } 733 | } 734 | 735 | if (iph->version != 4) { 736 | static u_int8_t ipv4_warning_used = 0; 737 | 738 | v4_warning: 739 | if (ipv4_warning_used == 0) { 740 | printf("\n\nWARNING: only IPv4 packets are supported in this demo (nDPI supports both IPv4 and IPv6), all other packets will be discarded\n\n"); 741 | ipv4_warning_used = 1; 742 | } 743 | return; 744 | } 745 | 746 | ip_offset = sizeof(struct ndpi_ethhdr); 747 | if(decode_tunnels && (iph->protocol == IPPROTO_UDP) && ((frag_off & 0x3FFF) == 0)) { 748 | u_short ip_len = ((u_short)iph->ihl * 4); 749 | struct ndpi_udphdr *udp = (struct ndpi_udphdr *)&packet[sizeof(struct ndpi_ethhdr)+ip_len]; 750 | u_int16_t sport = ntohs(udp->source), dport = ntohs(udp->dest); 751 | 752 | if((sport == GTP_U_V1_PORT) || (dport == GTP_U_V1_PORT)) { 753 | /* Check if it's GTPv1 */ 754 | u_int offset = sizeof(struct ndpi_ethhdr)+ip_len+sizeof(struct ndpi_udphdr); 755 | u_int8_t flags = packet[offset]; 756 | u_int8_t message_type = packet[offset+1]; 757 | 758 | if((((flags & 0xE0) >> 5) == 1 /* GTPv1 */) && (message_type == 0xFF /* T-PDU */)) { 759 | ip_offset = sizeof(struct ndpi_ethhdr)+ip_len+sizeof(struct ndpi_udphdr)+8 /* GTPv1 header len */; 760 | 761 | if(flags & 0x04) ip_offset += 1; /* next_ext_header is present */ 762 | if(flags & 0x02) ip_offset += 4; /* sequence_number is present (it also includes next_ext_header and pdu_number) */ 763 | if(flags & 0x01) ip_offset += 1; /* pdu_number is present */ 764 | 765 | iph = (struct ndpi_iphdr *) &packet[ip_offset]; 766 | 767 | if (iph->version != 4) { 768 | // printf("WARNING: not good (packet_id=%u)!\n", (unsigned int)raw_packet_count); 769 | goto v4_warning; 770 | } 771 | } 772 | } 773 | 774 | } 775 | 776 | // process the packet 777 | packet_processing(time, header, iph, header->len - ip_offset, header->len); 778 | } 779 | } 780 | 781 | static void runPcapLoop(void) 782 | { 783 | if((!shutdown_app) && (_pcap_handle != NULL)) 784 | pcap_loop(_pcap_handle, -1, &pcap_packet_callback, NULL); 785 | } 786 | 787 | void test_lib() { 788 | setupDetection(); 789 | openPcapFileOrDevice(); 790 | signal(SIGINT, sigproc); 791 | runPcapLoop(); 792 | closePcapFile(); 793 | printResults(); 794 | terminateDetection(); 795 | } 796 | 797 | int main(int argc, char **argv) 798 | { 799 | int i; 800 | 801 | parseOptions(argc, argv); 802 | 803 | for(i=0; i 2 | 3 | 4 | 5 | 6 | nDPI 7 | 8 | 9 | 10 | 11 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 |
170 | 171 |
172 |
173 | 285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 | 293 |
294 | 295 |
296 |
297 |
298 |
299 |
300 | 301 | 302 | 303 | 304 |
305 | 306 |
307 |
  
308 |

nDPI

309 |

Open and Extensible GPLv3 Deep Packet Inspection Library.

310 |
311 |

nDPI is a ntop-maintained superset of the popular OpenDPI library. Released under the GPL license, its goal is to extend the original library by adding new protocols that are otherwise available only on the paid version of OpenDPI. In addition to Unix platforms, we also support Windows, in order to provide you a cross-platform DPI experience. Furthermore, we have modified nDPI do be more suitable for traffic monitoring applications, by disabling specific features that slow down the DPI engine while being them un-necessary for network traffic monitoring.

312 |

nDPI is used by both ntop and nProbe for adding application-layer detection of protocols, regardless of the port being used. This means that it is possible to both detect known protocols on non-standard ports (e.g. detect http non ports other than 80), and also the opposite (e.g. detect Skype traffic on port 80). This is because nowadays the concept of port=application no longer holds.

313 |

We are continuously extending nDPI and so far the following protocols are supported:

314 |
    315 |
  • FTP
  • 316 |
  • POP
  • 317 |
  • SMTP
  • 318 |
  • IMAP
  • 319 |
  • DNS
  • 320 |
  • IPP
  • 321 |
  • HTTP
  • 322 |
  • MDNS
  • 323 |
  • NTP
  • 324 |
  • NETBIOS
  • 325 |
  • NFS
  • 326 |
  • SSDP
  • 327 |
  • BGP
  • 328 |
  • SNMP
  • 329 |
  • XDMCP
  • 330 |
  • SMB
  • 331 |
  • SYSLOG
  • 332 |
  • DHCP
  • 333 |
  • PostgreSQL
  • 334 |
  • MySQL
  • 335 |
  • TDS
  • 336 |
  • DirectDownloadLink
  • 337 |
  • I23V5
  • 338 |
  • AppleJuice
  • 339 |
  • DirectConnect
  • 340 |
  • Socrates
  • 341 |
  • WinMX
  • 342 |
  • VMware
  • 343 |
  • PANDO
  • 344 |
  • Filetopia
  • 345 |
  • iMESH
  • 346 |
  • Kontiki
  • 347 |
  • OpenFT
  • 348 |
  • Kazaa/Fasttrack
  • 349 |
  • Gnutella
  • 350 |
  • eDonkey
  • 351 |
  • Bittorrent
  • 352 |
  • OFF
  • 353 |
  • AVI
  • 354 |
  • Flash
  • 355 |
  • OGG
  • 356 |
  • MPEG
  • 357 |
  • QuickTime
  • 358 |
  • RealMedia
  • 359 |
  • Windowsmedia
  • 360 |
  • MMS
  • 361 |
  • XBOX
  • 362 |
  • QQ
  • 363 |
  • MOVE
  • 364 |
  • RTSP
  • 365 |
  • Feidian
  • 366 |
  • Icecast
  • 367 |
  • PPLive
  • 368 |
  • PPStream
  • 369 |
  • Zattoo
  • 370 |
  • SHOUTCast
  • 371 |
  • SopCast
  • 372 |
  • TVAnts
  • 373 |
  • TVUplayer
  • 374 |
  • VeohTV
  • 375 |
  • QQLive
  • 376 |
  • Thunder/Webthunder
  • 377 |
  • Soulseek
  • 378 |
  • GaduGadu
  • 379 |
  • IRC
  • 380 |
  • Popo
  • 381 |
  • Jabber
  • 382 |
  • MSN
  • 383 |
  • Oscar
  • 384 |
  • Yahoo
  • 385 |
  • Battlefield
  • 386 |
  • Quake
  • 387 |
  • VRRP
  • 388 |
  • Steam
  • 389 |
  • Halflife2
  • 390 |
  • World of Warcraft
  • 391 |
  • Telnet
  • 392 |
  • STUN
  • 393 |
  • IPSEC
  • 394 |
  • GRE
  • 395 |
  • ICMP
  • 396 |
  • IGMP
  • 397 |
  • EGP
  • 398 |
  • SCTP
  • 399 |
  • OSPF
  • 400 |
  • IP in IP
  • 401 |
  • RTP
  • 402 |
  • RDP
  • 403 |
  • VNC
  • 404 |
  • PCAnywhere
  • 405 |
  • SSL
  • 406 |
  • SSH
  • 407 |
  • USENET
  • 408 |
  • MGCP
  • 409 |
  • IAX
  • 410 |
  • TFTP
  • 411 |
  • AFP
  • 412 |
  • StealthNet
  • 413 |
  • Aimini
  • 414 |
  • SIP
  • 415 |
  • Truphone
  • 416 |
  • ICMPv6
  • 417 |
  • DHCPv6
  • 418 |
  • Armagetron
  • 419 |
  • CrossFire
  • 420 |
  • Dofus
  • 421 |
  • Fiesta
  • 422 |
  • Florensia
  • 423 |
  • Guildwars
  • 424 |
  • HTTP Application Activesync
  • 425 |
  • Kerberos
  • 426 |
  • LDAP
  • 427 |
  • MapleStory
  • 428 |
  • msSQL
  • 429 |
  • PPTP
  • 430 |
  • WARCRAFT3
  • 431 |
  • World of Kung Fu
  • 432 |
  • MEEBO
  • 433 |
  • FaceBook
  • 434 |
  • Twitter
  • 435 |
  • DropBox
  • 436 |
  • Gmail
  • 437 |
  • Google Maps
  • 438 |
  • YouTube
  • 439 |
  • Skype
  • 440 |
  • Google
  • 441 |
  • DCE RPC
  • 442 |
  • NetFlow_IPFIX
  • 443 |
  • sFlow
  • 444 |
  • HTTP Connect (SSL over HTTP)
  • 445 |
  • HTTP Proxy
  • 446 |
  • Netflix
  • 447 |
  • Citrix
  • 448 |
  • CitrixOnline/GotoMeeting
  • 449 |
  • Apple (iMessage, FaceTime…)
  • 450 |
  • Webex
  • 451 |
  • WhatsApp
  • 452 |
  • Apple iCloud
  • 453 |
  • Viber
  • 454 |
  • Apple iTunes
  • 455 |
  • Radius
  • 456 |
  • WindowsUpdate
  • 457 |
  • TeamViewer
  • 458 |
  • Tuenti
  • 459 |
  • LotusNotes
  • 460 |
  • SAP
  • 461 |
  • GTP
  • 462 |
  • UPnP
  • 463 |
  • LLMNR
  • 464 |
  • RemoteScan
  • 465 |
  • Spotify
  • 466 |
  • H323
  • 467 |
  • OpenVPN
  • 468 |
  • NOE
  • 469 |
  • CiscoVPN
  • 470 |
  • TeamSpeak
  • 471 |
  •  Tor
  • 472 |
  •  CiscoSkinny
  • 473 |
  •  RTCP
  • 474 |
  •  RSYNC
  • 475 |
  •  Oracle
  • 476 |
  •  Corba
  • 477 |
  •  UbuntuONE
  • 478 |
479 |

 

480 |

Handling Encrypted Content

481 |
482 |

The trend of Internet traffic is going towards encrypted content often using SSL. In order to let nDPI support encrypted connections, we have added a decoder for SSL (both client and server) certificates, thus we can figure out the protocol using the encryption certificate. This allows us to identify protocols such as Citrix Online and Apple iCloud that otherwise would be undetected.

483 |

Documentation

484 |
485 | You can refer to the documentation page for nDPI manuals.

486 |

487 |

Download Source

488 |
489 |

nDPI is automatically downloaded when you build ntop and nProbe. However nothing prevents you from using it as a standalone DPI library. The source code can be downloaded from the ntop SVN.

490 |

Please Contribute!

491 |
492 |

DPI is a time-consuming activity as protocols (in particular P2P) change quite often. This means that it’s necessary to update the code from time to time and add extensions. We would encourage anyone out there to help us adding or enhancing new protocols: we will put your contributions on our SVN and make them available to everyone free of charge. In fact the main reason why we decided to go for nDPI instead of using the original library, is that the company behind OpenDPI has never replied to our offers to merge the extensions we coded onto the original source code.

493 |
494 |
495 |
496 |   497 |
498 |
499 |
500 | 501 |
502 |
503 |
504 |
505 |
506 | 507 | 508 |
509 | 510 | 511 | 553 | 554 |
555 |
556 |
557 |
558 |
559 |
560 | 561 |
562 |
563 |
564 | 565 |
566 |
567 |
568 | 569 | 606 |
607 |
608 |
609 | 610 | 611 | 612 | 613 | 618 | 619 | 620 | 621 | 626 | 627 | 628 | 629 | 635 | 636 | --------------------------------------------------------------------------------