aboutsummaryrefslogtreecommitdiff
path: root/example
diff options
context:
space:
mode:
Diffstat (limited to 'example')
-rw-r--r--example/ndpiReader.c290
-rw-r--r--example/reader_util.c390
-rw-r--r--example/reader_util.h39
3 files changed, 618 insertions, 101 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index 32321aa94..708e330e1 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -81,8 +81,8 @@ static json_object *jArray_topStats;
static u_int8_t live_capture = 0;
static u_int8_t undetected_flows_deleted = 0;
/** User preferences **/
-u_int8_t enable_protocol_guess = 1;
-u_int8_t verbose = 0, json_flag = 0;
+u_int8_t enable_protocol_guess = 1, enable_payload_analyzer = 0;
+u_int8_t verbose = 0, json_flag = 0, enable_joy_stats = 0;
int nDPI_LogLevel = 0;
char *_debug_protocols = NULL;
static u_int8_t stats_flag = 0, bpf_filter_flag = 0;
@@ -90,6 +90,7 @@ static u_int8_t stats_flag = 0, bpf_filter_flag = 0;
static u_int8_t file_first_time = 1;
#endif
u_int8_t human_readeable_string_len = 5;
+u_int8_t max_num_udp_dissected_pkts = 16 /* 8 is enough for most protocols, Signal requires more */, max_num_tcp_dissected_pkts = 10;
static u_int32_t pcap_analysis_duration = (u_int32_t)-1;
static u_int16_t decode_tunnels = 0;
static u_int16_t num_loops = 1;
@@ -212,6 +213,8 @@ static int dpdk_port_id = 0, dpdk_run_capture = 1;
void test_lib(); /* Forward */
+extern void ndpi_report_payload_stats();
+
/* ********************************** */
#ifdef DEBUG_TRACE
@@ -225,6 +228,110 @@ FILE *trace = NULL;
*/
static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle);
+static void reduceBDbits(uint32_t *bd, unsigned int len) {
+ int mask = 0;
+ int shift = 0;
+ unsigned int i = 0;
+
+ for(i = 0; i < len; i++)
+ mask = mask | bd[i];
+
+ mask = mask >> 8;
+ for(i = 0; i < 24 && mask; i++) {
+ mask = mask >> 1;
+ if (mask == 0) {
+ shift = i+1;
+ break;
+ }
+ }
+
+ for(i = 0; i < len; i++)
+ bd[i] = bd[i] >> shift;
+}
+
+/**
+ * @brief Get flow byte distribution mean and variance
+ */
+static void
+flowGetBDMeanandVariance(struct ndpi_flow_info* flow) {
+ FILE *out = results_file ? results_file : stdout;
+
+ const uint32_t *array = NULL;
+ uint32_t tmp[256], i;
+ unsigned int num_bytes;
+ double mean = 0.0, variance = 0.0;
+
+ fflush(out);
+
+ /*
+ * Sum up the byte_count array for outbound and inbound flows,
+ * if this flow is bidirectional
+ */
+ if (!flow->bidirectional) {
+ array = flow->src2dst_byte_count;
+ num_bytes = flow->src2dst_l4_bytes;
+ for (i=0; i<256; i++) {
+ tmp[i] = flow->src2dst_byte_count[i];
+ }
+
+ if (flow->src2dst_num_bytes != 0) {
+ mean = flow->src2dst_bd_mean;
+ variance = flow->src2dst_bd_variance/(flow->src2dst_num_bytes - 1);
+ variance = sqrt(variance);
+
+ if (flow->src2dst_num_bytes == 1) {
+ variance = 0.0;
+ }
+ }
+ } else {
+ for (i=0; i<256; i++) {
+ tmp[i] = flow->src2dst_byte_count[i] + flow->dst2src_byte_count[i];
+ }
+ array = tmp;
+ num_bytes = flow->src2dst_l4_bytes + flow->dst2src_l4_bytes;
+
+ if (flow->src2dst_num_bytes + flow->dst2src_num_bytes != 0) {
+ mean = ((double)flow->src2dst_num_bytes)/((double)(flow->src2dst_num_bytes+flow->dst2src_num_bytes))*flow->src2dst_bd_mean +
+ ((double)flow->dst2src_num_bytes)/((double)(flow->dst2src_num_bytes+flow->src2dst_num_bytes))*flow->dst2src_bd_mean;
+
+ variance = ((double)flow->src2dst_num_bytes)/((double)(flow->src2dst_num_bytes+flow->dst2src_num_bytes))*flow->src2dst_bd_variance +
+ ((double)flow->dst2src_num_bytes)/((double)(flow->dst2src_num_bytes+flow->src2dst_num_bytes))*flow->dst2src_bd_variance;
+
+ variance = variance/((double)(flow->src2dst_num_bytes + flow->dst2src_num_bytes - 1));
+ variance = sqrt(variance);
+ if (flow->src2dst_num_bytes + flow->dst2src_num_bytes == 1) {
+ variance = 0.0;
+ }
+ }
+ }
+
+ if(enable_joy_stats) {
+ if(verbose > 1) {
+ reduceBDbits(tmp, 256);
+ array = tmp;
+
+ fprintf(out, " [byte_dist: ");
+ for(i = 0; i < 255; i++)
+ fprintf(out, "%u,", (unsigned char)array[i]);
+
+ fprintf(out, "%u]", (unsigned char)array[i]);
+ }
+
+ /* Output the mean */
+ if(num_bytes != 0) {
+ fprintf(out, "][byte_dist_mean: %f", mean);
+ fprintf(out, "][byte_dist_std: %f]", variance);
+ }
+
+ if(num_bytes != 0) {
+ double entropy = ndpi_flow_get_byte_count_entropy(array, num_bytes);
+
+ fprintf(out, "[entropy: %f]", entropy);
+ fprintf(out, "[total_entropy: %f]", entropy * num_bytes);
+ }
+ }
+}
+
/**
* @brief Print help instructions
*/
@@ -236,8 +343,9 @@ static void help(u_int long_help) {
"-i <file|device> "
#endif
"[-f <filter>][-s <duration>][-m <duration>]\n"
- " [-p <protos>][-l <loops> [-q][-d][-h][-e <len>][-t][-v <level>]\n"
- " [-n <threads>][-w <file>][-c <file>][-j <file>][-x <file>]\n\n"
+ " [-p <protos>][-l <loops> [-q][-d][-J][-h][-e <len>][-t][-v <level>]\n"
+ " [-n <threads>][-w <file>][-c <file>][-j <file>][-x <file>]\n"
+ " [-T <num>][-U <num>]\n\n"
"Usage:\n"
" -i <file.pcap|device> | Specify a pcap file/playlist to read packets from or a\n"
" | device for live capture (comma-separated list)\n"
@@ -255,7 +363,10 @@ static void help(u_int long_help) {
" -d | Disable protocol guess and use only DPI\n"
" -e <len> | Min human readeable string match len. Default %u\n"
" -q | Quiet mode\n"
+ " -J | Display flow SPLT (sequence of packet length and time)\n"
+ " | and BD (byte distribution). See https://github.com/cisco/joy\n"
" -t | Dissect GTP/TZSP tunnels\n"
+ " -P | Enable payload analysis\n"
" -r | Print nDPI version and git revision\n"
" -c <path> | Load custom categories from the specified file\n"
" -w <path> | Write test output on the specified file. This is useful for\n"
@@ -270,8 +381,13 @@ static void help(u_int long_help) {
" | >3 - full debug + dbg_proto = all\n"
" -b <file.json> | Specify a file to write port based diagnose statistics\n"
" -x <file.json> | Produce bpf filters for specified diagnose file. Use\n"
- " | this option only for .json files generated with -b flag.\n",
- human_readeable_string_len);
+ " | this option only for .json files generated with -b flag.\n"
+ " -T <num> | Max number of TCP processed packets before giving up [default: %u]\n"
+ " -U <num> | Max number of UDP processed packets before giving up [default: %u]\n"
+ ,
+ human_readeable_string_len,
+ max_num_tcp_dissected_pkts,
+ max_num_udp_dissected_pkts);
#ifndef WIN32
printf("\nExcap (wireshark) options:\n"
@@ -327,6 +443,8 @@ static struct option longopts[] = {
{ "version", no_argument, NULL, 'V'},
{ "help", no_argument, NULL, 'h'},
{ "json", required_argument, NULL, 'j'},
+ { "joy", required_argument, NULL, 'J'},
+ { "payload-analysis", required_argument, NULL, 'P'},
{ "result-path", required_argument, NULL, 'w'},
{ "quiet", no_argument, NULL, 'q'},
@@ -477,7 +595,8 @@ static void parseOptions(int argc, char **argv) {
}
#endif
- while((opt = getopt_long(argc, argv, "e:c:df:g:i:hp:l:s:tv:V:n:j:rp:w:q0123:456:7:89:m:b:x:", longopts, &option_idx)) != EOF) {
+ while((opt = getopt_long(argc, argv, "e:c:df:g:i:hp:Pl:s:tv:V:n:j:Jrp:w:q0123:456:7:89:m:b:x:T:U:",
+ longopts, &option_idx)) != EOF) {
#ifdef DEBUG_TRACE
if(trace) fprintf(trace, " #### -%c [%s] #### \n", opt, optarg ? optarg : "");
#endif
@@ -573,6 +692,14 @@ static void parseOptions(int argc, char **argv) {
help(1);
break;
+ case 'J':
+ enable_joy_stats = 1;
+ break;
+
+ case 'P':
+ enable_payload_analyzer = 1;
+ break;
+
case 'j':
#ifndef HAVE_JSON_C
printf("WARNING: this copy of ndpiReader has been compiled without json-c: JSON export disabled\n");
@@ -634,6 +761,16 @@ static void parseOptions(int argc, char **argv) {
_debug_protocols = strdup(optarg);
break;
+ case 'T':
+ max_num_tcp_dissected_pkts = atoi(optarg);
+ if(max_num_tcp_dissected_pkts < 3) max_num_tcp_dissected_pkts = 3;
+ break;
+
+ case 'U':
+ max_num_udp_dissected_pkts = atoi(optarg);
+ if(max_num_udp_dissected_pkts < 3) max_num_udp_dissected_pkts = 3;
+ break;
+
default:
help(0);
break;
@@ -721,12 +858,12 @@ static char* ipProto2Name(u_int16_t proto_id) {
/* ********************************** */
+#if 0
/**
* @brief A faster replacement for inet_ntoa().
*/
char* intoaV4(u_int32_t addr, char* buf, u_int16_t bufLen) {
- char *cp, *retStr;
- uint byte;
+ char *cp;
int n;
cp = &buf[bufLen];
@@ -734,7 +871,8 @@ char* intoaV4(u_int32_t addr, char* buf, u_int16_t bufLen) {
n = 4;
do {
- byte = addr & 0xff;
+ u_int byte = addr & 0xff;
+
*--cp = byte % 10 + '0';
byte /= 10;
if(byte > 0) {
@@ -743,15 +881,14 @@ char* intoaV4(u_int32_t addr, char* buf, u_int16_t bufLen) {
if(byte > 0)
*--cp = byte + '0';
}
- *--cp = '.';
+ if(n > 1)
+ *--cp = '.';
addr >>= 8;
- } while(--n > 0);
+ } while (--n > 0);
- /* Convert the string to lowercase */
- retStr = (char*)(cp+1);
-
- return(retStr);
+ return(cp);
}
+#endif
/* ********************************** */
@@ -799,6 +936,13 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
if(flow->vlan_id > 0) fprintf(out, "[VLAN: %u]", flow->vlan_id);
+ if(enable_joy_stats) {
+ /* Print entropy values for monitored flows. */
+ flowGetBDMeanandVariance(flow);
+ fflush(out);
+ fprintf(out, "[score: %.4f]", flow->score);
+ }
+
if(flow->detected_protocol.master_protocol) {
char buf[64];
@@ -826,15 +970,19 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
if(flow->info[0] != '\0') fprintf(out, "[%s]", flow->info);
- if(flow->ssh_ssl.ssl_version != 0) fprintf(out, "[%s]", ndpi_ssl_version2str(flow->ssh_ssl.ssl_version));
- if(flow->ssh_ssl.ja3_client[0] != '\0') fprintf(out, "[JA3C: %s%s]", flow->ssh_ssl.ja3_client,
- print_cipher(flow->ssh_ssl.client_unsafe_cipher));
- if(flow->ssh_ssl.server_info[0] != '\0') fprintf(out, "[server: %s]", flow->ssh_ssl.server_info);
-
- if(flow->ssh_ssl.ja3_server[0] != '\0') fprintf(out, "[JA3S: %s%s]", flow->ssh_ssl.ja3_server,
- print_cipher(flow->ssh_ssl.server_unsafe_cipher));
- if(flow->ssh_ssl.server_organization[0] != '\0') fprintf(out, "[organization: %s]", flow->ssh_ssl.server_organization);
- if(flow->ssh_ssl.server_cipher != '\0') fprintf(out, "[Cipher: %s]", ndpi_cipher2str(flow->ssh_ssl.server_cipher));
+ if(flow->ssh_tls.ssl_version != 0) fprintf(out, "[%s]", ndpi_ssl_version2str(flow->ssh_tls.ssl_version));
+ if(flow->ssh_tls.client_info[0] != '\0') fprintf(out, "[client: %s]", flow->ssh_tls.client_info);
+ if(flow->ssh_tls.client_hassh[0] != '\0') fprintf(out, "[HASSH-C: %s]", flow->ssh_tls.client_hassh);
+
+ if(flow->ssh_tls.ja3_client[0] != '\0') fprintf(out, "[JA3C: %s%s]", flow->ssh_tls.ja3_client,
+ print_cipher(flow->ssh_tls.client_unsafe_cipher));
+ if(flow->ssh_tls.server_info[0] != '\0') fprintf(out, "[server: %s]", flow->ssh_tls.server_info);
+ if(flow->ssh_tls.server_hassh[0] != '\0') fprintf(out, "[HASSH-S: %s]", flow->ssh_tls.server_hassh);
+
+ if(flow->ssh_tls.ja3_server[0] != '\0') fprintf(out, "[JA3S: %s%s]", flow->ssh_tls.ja3_server,
+ print_cipher(flow->ssh_tls.server_unsafe_cipher));
+ if(flow->ssh_tls.server_organization[0] != '\0') fprintf(out, "[organization: %s]", flow->ssh_tls.server_organization);
+ if(flow->ssh_tls.server_cipher != '\0') fprintf(out, "[Cipher: %s]", ndpi_cipher2str(flow->ssh_tls.server_cipher));
if(flow->bittorent_hash[0] != '\0') fprintf(out, "[BT Hash: %s]", flow->bittorent_hash);
if(flow->dhcp_fingerprint[0] != '\0') fprintf(out, "[DHCP Fingerprint: %s]", flow->dhcp_fingerprint);
@@ -881,25 +1029,25 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
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->ssh_ssl.client_info[0] != '\0') || (flow->ssh_ssl.server_info[0] != '\0')) {
+ if((flow->ssh_tls.client_info[0] != '\0') || (flow->ssh_tls.server_info[0] != '\0')) {
json_object *sjObj = json_object_new_object();
- if(flow->ssh_ssl.ja3_server[0] != '\0')
- json_object_object_add(jObj,"ja3s",json_object_new_string(flow->ssh_ssl.ja3_server));
+ if(flow->ssh_tls.ja3_server[0] != '\0')
+ json_object_object_add(jObj,"ja3s",json_object_new_string(flow->ssh_tls.ja3_server));
- if(flow->ssh_ssl.ja3_client[0] != '\0')
- json_object_object_add(jObj,"ja3c",json_object_new_string(flow->ssh_ssl.ja3_client));
+ if(flow->ssh_tls.ja3_client[0] != '\0')
+ json_object_object_add(jObj,"ja3c",json_object_new_string(flow->ssh_tls.ja3_client));
- if(flow->ssh_ssl.ja3_server[0] != '\0')
- json_object_object_add(jObj,"host.server.ja3",json_object_new_string(flow->ssh_ssl.ja3_server));
+ if(flow->ssh_tls.ja3_server[0] != '\0')
+ json_object_object_add(jObj,"host.server.ja3",json_object_new_string(flow->ssh_tls.ja3_server));
- if(flow->ssh_ssl.client_info[0] != '\0')
- json_object_object_add(sjObj, "client", json_object_new_string(flow->ssh_ssl.client_info));
+ if(flow->ssh_tls.client_info[0] != '\0')
+ json_object_object_add(sjObj, "client", json_object_new_string(flow->ssh_tls.client_info));
- if(flow->ssh_ssl.server_info[0] != '\0')
- json_object_object_add(sjObj, "server", json_object_new_string(flow->ssh_ssl.server_info));
+ if(flow->ssh_tls.server_info[0] != '\0')
+ json_object_object_add(sjObj, "server", json_object_new_string(flow->ssh_tls.server_info));
- json_object_object_add(jObj, "ssh_ssl", sjObj);
+ json_object_object_add(jObj, "ssh_tls", sjObj);
}
if(json_flag == 1)
@@ -1944,6 +2092,9 @@ void printPortStats(struct port_stats *stats) {
/* *********************************************** */
static void printFlowsStats() {
+ if(enable_payload_analyzer)
+ ndpi_report_payload_stats();
+
if(verbose) {
int thread_id;
FILE *out = results_file ? results_file : stdout;
@@ -1982,7 +2133,7 @@ static void printFlowsStats() {
ndpi_ja3_fingerprints_host *hostByJA3Found = NULL;
//check if this is a ssh-ssl flow
- if(all_flows[i].flow->ssh_ssl.ja3_client[0] != '\0'){
+ if(all_flows[i].flow->ssh_tls.ja3_client[0] != '\0'){
//looking if the host is already in the hash table
HASH_FIND_INT(ja3ByHostsHashT, &(all_flows[i].flow->src_ip), ja3ByHostFound);
@@ -1994,11 +2145,11 @@ static void printFlowsStats() {
newHost->host_server_info_hasht = NULL;
newHost->ip_string = all_flows[i].flow->src_name;
newHost->ip = all_flows[i].flow->src_ip;
- newHost->dns_name = all_flows[i].flow->ssh_ssl.client_info;
+ newHost->dns_name = all_flows[i].flow->ssh_tls.client_info;
ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
- newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
- newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
+ newJA3->ja3 = all_flows[i].flow->ssh_tls.ja3_client;
+ newJA3->unsafe_cipher = all_flows[i].flow->ssh_tls.client_unsafe_cipher;
//adding the new ja3 fingerprint
HASH_ADD_KEYPTR(hh, newHost->host_client_info_hasht,
newJA3->ja3, strlen(newJA3->ja3), newJA3);
@@ -2009,29 +2160,29 @@ static void printFlowsStats() {
ndpi_ja3_info *infoFound = NULL;
HASH_FIND_STR(ja3ByHostFound->host_client_info_hasht,
- all_flows[i].flow->ssh_ssl.ja3_client, infoFound);
+ all_flows[i].flow->ssh_tls.ja3_client, infoFound);
if(infoFound == NULL){
ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
- newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
- newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
+ newJA3->ja3 = all_flows[i].flow->ssh_tls.ja3_client;
+ newJA3->unsafe_cipher = all_flows[i].flow->ssh_tls.client_unsafe_cipher;
HASH_ADD_KEYPTR(hh, ja3ByHostFound->host_client_info_hasht,
newJA3->ja3, strlen(newJA3->ja3), newJA3);
}
}
//ja3 -> host ip
- HASH_FIND_STR(hostByJA3C_ht, all_flows[i].flow->ssh_ssl.ja3_client, hostByJA3Found);
+ HASH_FIND_STR(hostByJA3C_ht, all_flows[i].flow->ssh_tls.ja3_client, hostByJA3Found);
if(hostByJA3Found == NULL){
ndpi_ip_dns *newHost = malloc(sizeof(ndpi_ip_dns));
newHost->ip = all_flows[i].flow->src_ip;
newHost->ip_string = all_flows[i].flow->src_name;
- newHost->dns_name = all_flows[i].flow->ssh_ssl.client_info;;
+ newHost->dns_name = all_flows[i].flow->ssh_tls.client_info;;
ndpi_ja3_fingerprints_host *newElement = malloc(sizeof(ndpi_ja3_fingerprints_host));
- newElement->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
- newElement->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
+ newElement->ja3 = all_flows[i].flow->ssh_tls.ja3_client;
+ newElement->unsafe_cipher = all_flows[i].flow->ssh_tls.client_unsafe_cipher;
newElement->ipToDNS_ht = NULL;
HASH_ADD_INT(newElement->ipToDNS_ht, ip, newHost);
@@ -2044,13 +2195,13 @@ static void printFlowsStats() {
ndpi_ip_dns *newInnerElement = malloc(sizeof(ndpi_ip_dns));
newInnerElement->ip = all_flows[i].flow->src_ip;
newInnerElement->ip_string = all_flows[i].flow->src_name;
- newInnerElement->dns_name = all_flows[i].flow->ssh_ssl.client_info;
+ newInnerElement->dns_name = all_flows[i].flow->ssh_tls.client_info;
HASH_ADD_INT(hostByJA3Found->ipToDNS_ht, ip, newInnerElement);
}
}
}
- if(all_flows[i].flow->ssh_ssl.ja3_server[0] != '\0'){
+ if(all_flows[i].flow->ssh_tls.ja3_server[0] != '\0'){
//looking if the host is already in the hash table
HASH_FIND_INT(ja3ByHostsHashT, &(all_flows[i].flow->dst_ip), ja3ByHostFound);
if(ja3ByHostFound == NULL){
@@ -2060,11 +2211,11 @@ static void printFlowsStats() {
newHost->host_server_info_hasht = NULL;
newHost->ip_string = all_flows[i].flow->dst_name;
newHost->ip = all_flows[i].flow->dst_ip;
- newHost->dns_name = all_flows[i].flow->ssh_ssl.server_info;
+ newHost->dns_name = all_flows[i].flow->ssh_tls.server_info;
ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
- newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
- newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
+ newJA3->ja3 = all_flows[i].flow->ssh_tls.ja3_server;
+ newJA3->unsafe_cipher = all_flows[i].flow->ssh_tls.server_unsafe_cipher;
//adding the new ja3 fingerprint
HASH_ADD_KEYPTR(hh, newHost->host_server_info_hasht, newJA3->ja3,
strlen(newJA3->ja3), newJA3);
@@ -2074,27 +2225,27 @@ static void printFlowsStats() {
//host already in the hashtable
ndpi_ja3_info *infoFound = NULL;
HASH_FIND_STR(ja3ByHostFound->host_server_info_hasht,
- all_flows[i].flow->ssh_ssl.ja3_server, infoFound);
+ all_flows[i].flow->ssh_tls.ja3_server, infoFound);
if(infoFound == NULL){
ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
- newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
- newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
+ newJA3->ja3 = all_flows[i].flow->ssh_tls.ja3_server;
+ newJA3->unsafe_cipher = all_flows[i].flow->ssh_tls.server_unsafe_cipher;
HASH_ADD_KEYPTR(hh, ja3ByHostFound->host_server_info_hasht,
newJA3->ja3, strlen(newJA3->ja3), newJA3);
}
}
- HASH_FIND_STR(hostByJA3S_ht, all_flows[i].flow->ssh_ssl.ja3_server, hostByJA3Found);
+ HASH_FIND_STR(hostByJA3S_ht, all_flows[i].flow->ssh_tls.ja3_server, hostByJA3Found);
if(hostByJA3Found == NULL){
ndpi_ip_dns *newHost = malloc(sizeof(ndpi_ip_dns));
newHost->ip = all_flows[i].flow->dst_ip;
newHost->ip_string = all_flows[i].flow->dst_name;
- newHost->dns_name = all_flows[i].flow->ssh_ssl.server_info;;
+ newHost->dns_name = all_flows[i].flow->ssh_tls.server_info;;
ndpi_ja3_fingerprints_host *newElement = malloc(sizeof(ndpi_ja3_fingerprints_host));
- newElement->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
- newElement->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
+ newElement->ja3 = all_flows[i].flow->ssh_tls.ja3_server;
+ newElement->unsafe_cipher = all_flows[i].flow->ssh_tls.server_unsafe_cipher;
newElement->ipToDNS_ht = NULL;
HASH_ADD_INT(newElement->ipToDNS_ht, ip, newHost);
@@ -2108,7 +2259,7 @@ static void printFlowsStats() {
ndpi_ip_dns *newInnerElement = malloc(sizeof(ndpi_ip_dns));
newInnerElement->ip = all_flows[i].flow->dst_ip;
newInnerElement->ip_string = all_flows[i].flow->dst_name;
- newInnerElement->dns_name = all_flows[i].flow->ssh_ssl.server_info;
+ newInnerElement->dns_name = all_flows[i].flow->ssh_tls.server_info;
HASH_ADD_INT(hostByJA3Found->ipToDNS_ht, ip, newInnerElement);
}
}
@@ -3094,10 +3245,11 @@ void serializerUnitTest() {
assert(ndpi_serialize_uint32_string(&serializer, i, "Hello") != -1);
assert(ndpi_serialize_string_string(&serializer, kbuf, vbuf) != -1);
assert(ndpi_serialize_string_uint32(&serializer, kbuf, i*i) != -1);
+ assert(ndpi_serialize_string_float(&serializer, kbuf, (float)(i*i), "%f") != -1);
}
if(trace)
- printf("Serialization size: %u/%u\n", serializer.size_used, serializer.buffer_size);
+ printf("Serialization size: %u\n", ndpi_serializer_get_buffer_len(&serializer));
assert(ndpi_init_deserializer(&deserializer, &serializer) != -1);
@@ -3109,7 +3261,8 @@ void serializerUnitTest() {
else {
u_int32_t k32, v32;
ndpi_string ks, vs;
-
+ float vf;
+
switch(et) {
case ndpi_serialization_uint32_uint32:
assert(ndpi_deserialize_uint32_uint32(&deserializer, &k32, &v32) != -1);
@@ -3149,6 +3302,17 @@ void serializerUnitTest() {
}
break;
+ case ndpi_serialization_string_float:
+ assert(ndpi_deserialize_string_float(&deserializer, &ks, &vf) != -1);
+ if(trace) {
+ u_int8_t bkpk = ks.str[ks.str_len];
+
+ ks.str[ks.str_len] = '\0';
+ printf("%s=%f\n", ks.str, vf);
+ ks.str[ks.str_len] = bkpk;
+ }
+ break;
+
default:
printf("serializerUnitTest: unsupported type %u detected!\n", et);
return;
diff --git a/example/reader_util.c b/example/reader_util.c
index d0ec31930..b8e21cce8 100644
--- a/example/reader_util.c
+++ b/example/reader_util.c
@@ -34,6 +34,8 @@
#else
#include <unistd.h>
#include <netinet/in.h>
+#include <math.h>
+#include <float.h>
#endif
#ifndef ETH_P_IP
@@ -73,9 +75,158 @@
#include "ndpi_main.h"
#include "reader_util.h"
+#include "ndpi_classify.h"
-extern u_int8_t enable_protocol_guess;
+extern u_int8_t enable_protocol_guess, enable_joy_stats, enable_payload_analyzer;
extern u_int8_t verbose, human_readeable_string_len;
+extern u_int8_t max_num_udp_dissected_pkts /* 8 */, max_num_tcp_dissected_pkts /* 10 */;
+
+static u_int32_t flow_id = 0;
+
+/* ****************************************************** */
+
+struct payload_stats {
+ u_int8_t *pattern;
+ u_int8_t pattern_len;
+ u_int16_t num_occurrencies;
+ UT_hash_handle hh; /* makes this structure hashable */
+};
+
+
+struct payload_stats *pstats = NULL;
+u_int32_t max_num_packets_per_flow = 32;
+u_int32_t max_packet_payload_dissection = 32; /* Full payload */
+u_int16_t min_pattern_len = 4;
+u_int16_t max_pattern_len = 8;
+
+
+void ndpi_analyze_payload(struct ndpi_flow_info *flow,
+ u_int8_t src_to_dst_direction,
+ u_int8_t *payload,
+ u_int16_t payload_len) {
+ struct payload_stats *ret;
+ u_int i;
+
+#ifdef DEBUG_PAYLOAD
+ for(i=0; i<payload_len; i++)
+ printf("%c", isprint(payload[i]) ? payload[i] : '.');
+ printf("\n");
+#endif
+
+ HASH_FIND(hh, pstats, payload, payload_len, ret);
+ if(ret == NULL) {
+ if((ret = (struct payload_stats*)calloc(1, sizeof(struct payload_stats))) == NULL)
+ return; /* OOM */
+
+ if((ret->pattern = (u_int8_t*)malloc(payload_len)) == NULL) {
+ free(ret);
+ return;
+ }
+
+ memcpy(ret->pattern, payload, payload_len);
+ ret->pattern_len = payload_len;
+ ret->num_occurrencies = 1;
+
+ HASH_ADD(hh, pstats, pattern[0], payload_len, ret);
+
+#ifdef DEBUG_PAYLOAD
+ printf("Added element [total: %u]\n", HASH_COUNT(pstats));
+#endif
+ } else {
+ ret->num_occurrencies++;
+ // printf("==> %u\n", ret->num_occurrencies);
+ }
+}
+
+
+void ndpi_payload_analyzer(struct ndpi_flow_info *flow,
+ u_int8_t src_to_dst_direction,
+ u_int8_t *payload, u_int16_t payload_len) {
+ u_int16_t i, j;
+ u_int16_t scan_len = ndpi_min(max_packet_payload_dissection, payload_len);
+
+ if((flow->src2dst_pkt_count+flow->dst2src_pkt_count) < max_num_packets_per_flow) {
+#ifdef DEBUG_PAYLOAD
+ printf("[hashval: %u][proto: %u][vlan: %u][%s:%u <-> %s:%u][direction: %s][payload_len: %u]\n",
+ flow->hashval, flow->protocol, flow->vlan_id,
+ flow->src_name, flow->src_port,
+ flow->dst_name, flow->dst_port,
+ src_to_dst_direction ? "s2d" : "d2s",
+ payload_len);
+#endif
+ } else
+ return;
+
+ for(i=0; i<scan_len; i++) {
+ for(j=min_pattern_len; j <= max_pattern_len; j++) {
+ if((i+j) < payload_len) {
+ ndpi_analyze_payload(flow, src_to_dst_direction, &payload[i], j);
+ ndpi_analyze_payload(flow, src_to_dst_direction, &payload[i], j);
+ }
+ }
+ }
+}
+
+/* ***************************************************** */
+
+static int payload_stats_sort_asc(void *_a, void *_b) {
+ struct payload_stats *a = (struct payload_stats *)_a;
+ struct payload_stats *b = (struct payload_stats *)_b;
+
+ //return(a->num_occurrencies - b->num_occurrencies);
+ return(b->num_occurrencies - a->num_occurrencies);
+}
+
+/* ***************************************************** */
+
+void print_payload_stat(struct payload_stats *p) {
+ u_int i;
+
+ printf("\t[");
+
+ for(i=0; i<p->pattern_len; i++) {
+ printf("%c", isprint(p->pattern[i]) ? p->pattern[i] : '.');
+ }
+
+ printf("]");
+ for(; i<16; i++) printf(" ");
+ printf("[");
+
+ for(i=0; i<p->pattern_len; i++) {
+ printf("%s%02X", (i > 0) ? " " : "", isprint(p->pattern[i]) ? p->pattern[i] : '.');
+ }
+
+ printf("]");
+
+ for(; i<16; i++) printf(" ");
+ for(i=p->pattern_len; i<max_pattern_len; i++) printf(" ");
+
+ printf("[len: %u][num_occurrencies: %u]\n",
+ p->pattern_len, p->num_occurrencies);
+}
+
+/* ***************************************************** */
+
+void ndpi_report_payload_stats() {
+ struct payload_stats *p, *tmp;
+ u_int num = 0, max_num = 25;
+
+ printf("\n\nPayload Analysis\n");
+
+ HASH_SORT(pstats, payload_stats_sort_asc);
+
+ HASH_ITER(hh, pstats, p, tmp) {
+ if(num <= max_num)
+ print_payload_stat(p);
+
+ free(p->pattern);
+ HASH_DEL(pstats, p);
+ free(p);
+ num++;
+ }
+}
+
+
/* ***************************************************** */
@@ -273,6 +424,94 @@ int ndpi_workflow_node_cmp(const void *a, const void *b) {
return(0); /* notreached */
}
+/**
+ * \brief Update the byte count for the flow record.
+ * \param f Flow data
+ * \param x Data to use for update
+ * \param len Length of the data (in bytes)
+ * \return none
+ */
+static void
+ndpi_flow_update_byte_count(struct ndpi_flow_info *flow, const void *x,
+ unsigned int len, u_int8_t src_to_dst_direction) {
+ const unsigned char *data = x;
+ u_int32_t i;
+ u_int32_t current_count = 0;
+
+ /*
+ * implementation note: The spec says that 4000 octets is enough of a
+ * sample size to accurately reflect the byte distribution. Also, to avoid
+ * wrapping of the byte count at the 16-bit boundry, we stop counting once
+ * the 4000th octet has been seen for a flow.
+ */
+
+ /* octet count was already incremented before processing this payload */
+ if (src_to_dst_direction) {
+ current_count = flow->src2dst_l4_bytes - len;
+ } else {
+ current_count = flow->dst2src_l4_bytes - len;
+ }
+
+ if (current_count < ETTA_MIN_OCTETS) {
+ for (i=0; i<len; i++) {
+ if (src_to_dst_direction) {
+ flow->src2dst_byte_count[data[i]]++;
+ } else {
+ flow->dst2src_byte_count[data[i]]++;
+ }
+ current_count++;
+ if (current_count >= ETTA_MIN_OCTETS) {
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * \brief Update the byte distribution mean for the flow record.
+ * \param f Flow record
+ * \param x Data to use for update
+ * \param len Length of the data (in bytes)
+ * \return none
+ */
+static void
+ndpi_flow_update_byte_dist_mean_var(ndpi_flow_info_t *flow, const void *x,
+ unsigned int len, u_int8_t src_to_dst_direction) {
+ const unsigned char *data = x;
+ double delta;
+ unsigned int i;
+
+ for (i=0; i<len; i++) {
+ if (src_to_dst_direction) {
+ flow->src2dst_num_bytes += 1;
+ delta = ((double)data[i] - flow->src2dst_bd_mean);
+ flow->src2dst_bd_mean += delta/((double)flow->src2dst_num_bytes);
+ flow->src2dst_bd_variance += delta*((double)data[i] - flow->src2dst_bd_mean);
+ } else {
+ flow->dst2src_num_bytes += 1;
+ delta = ((double)data[i] - flow->dst2src_bd_mean);
+ flow->dst2src_bd_mean += delta/((double)flow->dst2src_num_bytes);
+ flow->dst2src_bd_variance += delta*((double)data[i] - flow->dst2src_bd_mean);
+ }
+ }
+}
+
+float
+ndpi_flow_get_byte_count_entropy(const uint32_t byte_count[256],
+ unsigned int num_bytes)
+{
+ int i;
+ float tmp, sum = 0.0;
+
+ for (i=0; i<256; i++) {
+ tmp = (float) byte_count[i] / (float) num_bytes;
+ if (tmp > FLT_EPSILON) {
+ sum -= tmp * logf(tmp);
+ }
+ }
+ return sum / logf(2.0);
+}
+
/* ***************************************************** */
static void patchIPv6Address(char *str) {
@@ -309,11 +548,13 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow
u_int8_t *proto,
u_int8_t **payload,
u_int16_t *payload_len,
- u_int8_t *src_to_dst_direction) {
+ u_int8_t *src_to_dst_direction,
+ struct timeval when) {
u_int32_t idx, l4_offset, hashval;
struct ndpi_flow_info flow;
void *ret;
const u_int8_t *l3, *l4;
+ u_int32_t l4_data_len = 0XFEEDFACE;
/*
Note: to keep things simple (ndpiReader is just a demo app)
@@ -363,6 +604,7 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow
tcp_len = ndpi_min(4*(*tcph)->doff, l4_packet_len);
*payload = (u_int8_t*)&l4[tcp_len];
*payload_len = ndpi_max(0, l4_packet_len-4*(*tcph)->doff);
+ l4_data_len = l4_packet_len - sizeof(struct ndpi_tcphdr);
} else if(iph->protocol == IPPROTO_UDP && l4_packet_len >= 8) {
// udp
@@ -371,9 +613,11 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow
*sport = ntohs((*udph)->source), *dport = ntohs((*udph)->dest);
*payload = (u_int8_t*)&l4[sizeof(struct ndpi_udphdr)];
*payload_len = (l4_packet_len > sizeof(struct ndpi_udphdr)) ? l4_packet_len-sizeof(struct ndpi_udphdr) : 0;
+ l4_data_len = l4_packet_len - sizeof(struct ndpi_udphdr);
} else {
// non tcp/udp protocols
*sport = *dport = 0;
+ l4_data_len = 0;
}
flow.protocol = iph->protocol, flow.vlan_id = vlan_id;
@@ -418,6 +662,7 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow
workflow->num_allocated_flows++;
memset(newflow, 0, sizeof(struct ndpi_flow_info));
+ newflow->flow_id = flow_id++;
newflow->hashval = hashval;
newflow->protocol = iph->protocol, newflow->vlan_id = vlan_id;
newflow->src_ip = iph->saddr, newflow->dst_ip = iph->daddr;
@@ -459,7 +704,15 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow
workflow->stats.ndpi_flow_count++;
*src = newflow->src_id, *dst = newflow->dst_id;
-
+ newflow->src2dst_pkt_len[newflow->src2dst_pkt_count] = l4_packet_len;
+ newflow->src2dst_pkt_time[newflow->src2dst_pkt_count] = when;
+ if (newflow->src2dst_pkt_count == 0) {
+ newflow->src2dst_start = when;
+ }
+ newflow->src2dst_pkt_count++;
+ if (l4_data_len != 0XFEEDFACE) {
+ newflow->src2dst_opackets++;
+ }
return newflow;
}
} else {
@@ -485,6 +738,28 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow
else
*src = flow->dst_id, *dst = flow->src_id, *src_to_dst_direction = 0, flow->bidirectional = 1;
}
+ if (src_to_dst_direction) {
+ if (flow->src2dst_pkt_count < MAX_NUM_PKTS) {
+ flow->src2dst_pkt_len[flow->src2dst_pkt_count] = l4_packet_len;
+ flow->src2dst_pkt_time[flow->src2dst_pkt_count] = when;
+ flow->src2dst_pkt_count++;
+ }
+ if (l4_data_len != 0XFEEDFACE) {
+ flow->src2dst_opackets++;
+ }
+ } else {
+ if (flow->dst2src_pkt_count < MAX_NUM_PKTS) {
+ flow->dst2src_pkt_len[flow->dst2src_pkt_count] = l4_packet_len;
+ flow->dst2src_pkt_time[flow->dst2src_pkt_count] = when;
+ if (flow->dst2src_pkt_count == 0) {
+ flow->dst2src_start = when;
+ }
+ flow->dst2src_pkt_count++;
+ }
+ if (l4_data_len != 0XFEEDFACE) {
+ flow->dst2src_opackets++;
+ }
+ }
return flow;
}
}
@@ -503,7 +778,8 @@ static struct ndpi_flow_info *get_ndpi_flow_info6(struct ndpi_workflow * workflo
u_int8_t *proto,
u_int8_t **payload,
u_int16_t *payload_len,
- u_int8_t *src_to_dst_direction) {
+ u_int8_t *src_to_dst_direction,
+ struct timeval when) {
struct ndpi_iphdr iph;
memset(&iph, 0, sizeof(iph));
@@ -523,12 +799,35 @@ static struct ndpi_flow_info *get_ndpi_flow_info6(struct ndpi_workflow * workflo
ntohs(iph6->ip6_hdr.ip6_un1_plen),
tcph, udph, sport, dport,
src, dst, proto, payload,
- payload_len, src_to_dst_direction));
+ payload_len, src_to_dst_direction, when));
}
/* ****************************************************** */
void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_flow_info *flow) {
+
+ if(enable_joy_stats) {
+ /* Update SPLT scores. */
+
+ if(flow->bidirectional)
+ flow->score = ndpi_classify(flow->src2dst_pkt_len, flow->src2dst_pkt_time,
+ flow->dst2src_pkt_len, flow->dst2src_pkt_time,
+ flow->src2dst_start, flow->dst2src_start,
+ MAX_NUM_PKTS, flow->src_port, flow->dst_port,
+ flow->src2dst_packets, flow->dst2src_packets,
+ flow->src2dst_opackets, flow->dst2src_opackets,
+ flow->src2dst_l4_bytes, flow->dst2src_l4_bytes, 1,
+ flow->src2dst_byte_count, flow->dst2src_byte_count);
+ else
+ flow->score = ndpi_classify(flow->src2dst_pkt_len, flow->src2dst_pkt_time,
+ NULL, NULL, flow->src2dst_start, flow->src2dst_start,
+ MAX_NUM_PKTS, flow->src_port, flow->dst_port,
+ flow->src2dst_packets, 0,
+ flow->src2dst_opackets, 0,
+ flow->src2dst_l4_bytes, 0, 1,
+ flow->src2dst_byte_count, NULL);
+ }
+
if(!flow->ndpi_flow) return;
snprintf(flow->host_server_name, sizeof(flow->host_server_name), "%s",
@@ -559,27 +858,33 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
if(flow->detected_protocol.app_protocol != NDPI_PROTOCOL_DNS) {
/* SSH */
if(flow->detected_protocol.app_protocol == NDPI_PROTOCOL_SSH) {
- snprintf(flow->ssh_ssl.client_info, sizeof(flow->ssh_ssl.client_info), "%s",
+ snprintf(flow->ssh_tls.client_info, sizeof(flow->ssh_tls.client_info), "%s",
flow->ndpi_flow->protos.ssh.client_signature);
- snprintf(flow->ssh_ssl.server_info, sizeof(flow->ssh_ssl.server_info), "%s",
+ snprintf(flow->ssh_tls.server_info, sizeof(flow->ssh_tls.server_info), "%s",
flow->ndpi_flow->protos.ssh.server_signature);
+ snprintf(flow->ssh_tls.client_hassh, sizeof(flow->ssh_tls.client_hassh), "%s",
+ flow->ndpi_flow->protos.ssh.hassh_client);
+ snprintf(flow->ssh_tls.server_hassh, sizeof(flow->ssh_tls.server_hassh), "%s",
+ flow->ndpi_flow->protos.ssh.hassh_server);
}
- /* SSL */
- else if((flow->detected_protocol.app_protocol == NDPI_PROTOCOL_SSL)
- || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_SSL)) {
- flow->ssh_ssl.ssl_version = flow->ndpi_flow->protos.stun_ssl.ssl.ssl_version;
- snprintf(flow->ssh_ssl.client_info, sizeof(flow->ssh_ssl.client_info), "%s",
+ /* TLS */
+ else if((flow->detected_protocol.app_protocol == NDPI_PROTOCOL_TLS)
+ || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_TLS)
+ || (flow->ndpi_flow->protos.stun_ssl.ssl.ja3_client[0] != '\0')
+ ) {
+ flow->ssh_tls.ssl_version = flow->ndpi_flow->protos.stun_ssl.ssl.ssl_version;
+ snprintf(flow->ssh_tls.client_info, sizeof(flow->ssh_tls.client_info), "%s",
flow->ndpi_flow->protos.stun_ssl.ssl.client_certificate);
- snprintf(flow->ssh_ssl.server_info, sizeof(flow->ssh_ssl.server_info), "%s",
+ snprintf(flow->ssh_tls.server_info, sizeof(flow->ssh_tls.server_info), "%s",
flow->ndpi_flow->protos.stun_ssl.ssl.server_certificate);
- snprintf(flow->ssh_ssl.server_organization, sizeof(flow->ssh_ssl.server_organization), "%s",
+ snprintf(flow->ssh_tls.server_organization, sizeof(flow->ssh_tls.server_organization), "%s",
flow->ndpi_flow->protos.stun_ssl.ssl.server_organization);
- snprintf(flow->ssh_ssl.ja3_client, sizeof(flow->ssh_ssl.ja3_client), "%s",
+ snprintf(flow->ssh_tls.ja3_client, sizeof(flow->ssh_tls.ja3_client), "%s",
flow->ndpi_flow->protos.stun_ssl.ssl.ja3_client);
- snprintf(flow->ssh_ssl.ja3_server, sizeof(flow->ssh_ssl.ja3_server), "%s",
+ snprintf(flow->ssh_tls.ja3_server, sizeof(flow->ssh_tls.ja3_server), "%s",
flow->ndpi_flow->protos.stun_ssl.ssl.ja3_server);
- flow->ssh_ssl.server_unsafe_cipher = flow->ndpi_flow->protos.stun_ssl.ssl.server_unsafe_cipher;
- flow->ssh_ssl.server_cipher = flow->ndpi_flow->protos.stun_ssl.ssl.server_cipher;
+ flow->ssh_tls.server_unsafe_cipher = flow->ndpi_flow->protos.stun_ssl.ssl.server_unsafe_cipher;
+ flow->ssh_tls.server_cipher = flow->ndpi_flow->protos.stun_ssl.ssl.server_cipher;
}
}
@@ -613,7 +918,8 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
u_int16_t ip_offset,
u_int16_t ipsize, u_int16_t rawsize,
const struct pcap_pkthdr *header,
- const u_char *packet) {
+ const u_char *packet,
+ struct timeval when) {
struct ndpi_id_struct *src, *dst;
struct ndpi_flow_info *flow = NULL;
struct ndpi_flow_struct *ndpi_flow = NULL;
@@ -631,12 +937,12 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
ntohs(iph->tot_len) - (iph->ihl * 4),
&tcph, &udph, &sport, &dport,
&src, &dst, &proto,
- &payload, &payload_len, &src_to_dst_direction);
+ &payload, &payload_len, &src_to_dst_direction, when);
else
flow = get_ndpi_flow_info6(workflow, vlan_id, iph6, ip_offset,
&tcph, &udph, &sport, &dport,
&src, &dst, &proto,
- &payload, &payload_len, &src_to_dst_direction);
+ &payload, &payload_len, &src_to_dst_direction, when);
if(flow != NULL) {
workflow->stats.ip_packet_count++;
@@ -644,22 +950,34 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
workflow->stats.total_ip_bytes += rawsize;
ndpi_flow = flow->ndpi_flow;
- if(src_to_dst_direction)
+ if(src_to_dst_direction) {
flow->src2dst_packets++, flow->src2dst_bytes += rawsize;
- else
+ flow->src2dst_l4_bytes += payload_len;
+ } else {
flow->dst2src_packets++, flow->dst2src_bytes += rawsize;
+ flow->dst2src_l4_bytes += payload_len;
+ }
+
+ if(enable_payload_analyzer && (payload_len > 0))
+ ndpi_payload_analyzer(flow, src_to_dst_direction, payload, payload_len);
+
+ if(enable_joy_stats) {
+ /* Update BD, distribution and mean. */
+ ndpi_flow_update_byte_count(flow, payload, payload_len, src_to_dst_direction);
+ ndpi_flow_update_byte_dist_mean_var(flow, payload, payload_len, src_to_dst_direction);
+ }
flow->last_seen = time;
if(!flow->has_human_readeable_strings) {
u_int8_t skip = 0;
-
+
if((proto == IPPROTO_TCP)
&& (
- (flow->detected_protocol.app_protocol == NDPI_PROTOCOL_SSL)
- || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_SSL)
+ (flow->detected_protocol.app_protocol == NDPI_PROTOCOL_TLS)
+ || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_TLS)
|| (flow->detected_protocol.app_protocol == NDPI_PROTOCOL_SSH)
- || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_SSH))
+ || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_SSH))
) {
if((flow->src2dst_packets+flow->dst2src_packets) < 10 /* MIN_NUM_ENCRYPT_SKIP_PACKETS */)
skip = 1;
@@ -667,7 +985,7 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
if(!skip) {
char outbuf[64] = { '\0' };
-
+
if(ndpi_has_human_readeable_string(workflow->ndpi_struct, (char*)packet, header->caplen,
human_readeable_string_len,
flow->human_readeable_string_buffer,
@@ -677,10 +995,10 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
} else {
if((proto == IPPROTO_TCP)
&& (
- (flow->detected_protocol.app_protocol == NDPI_PROTOCOL_SSL)
- || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_SSL)
+ (flow->detected_protocol.app_protocol == NDPI_PROTOCOL_TLS)
+ || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_TLS)
|| (flow->detected_protocol.app_protocol == NDPI_PROTOCOL_SSH)
- || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_SSH))
+ || (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_SSH))
)
flow->has_human_readeable_strings = 0;
}
@@ -691,8 +1009,8 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
if(!flow->detection_completed) {
u_int enough_packets =
- (((proto == IPPROTO_UDP) && ((flow->src2dst_packets + flow->dst2src_packets) > 8))
- || ((proto == IPPROTO_TCP) && ((flow->src2dst_packets + flow->dst2src_packets) > 10))) ? 1 : 0;
+ (((proto == IPPROTO_UDP) && ((flow->src2dst_packets + flow->dst2src_packets) > max_num_udp_dissected_pkts))
+ || ((proto == IPPROTO_TCP) && ((flow->src2dst_packets + flow->dst2src_packets) > max_num_tcp_dissected_pkts))) ? 1 : 0;
flow->detected_protocol = ndpi_detection_process_packet(workflow->ndpi_struct, ndpi_flow,
iph ? (uint8_t *)iph : (uint8_t *)iph6,
@@ -700,7 +1018,7 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
if(enough_packets || (flow->detected_protocol.app_protocol != NDPI_PROTOCOL_UNKNOWN)) {
if((!enough_packets)
- && (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_SSL)
+ && (flow->detected_protocol.master_protocol == NDPI_PROTOCOL_TLS)
&& (flow->ndpi_flow->protos.stun_ssl.ssl.ja3_server[0] == '\0'))
; /* Wait for JA3S certificate */
else {
@@ -985,7 +1303,7 @@ iph_check:
proto = options[0];
ip_len += 8 * (options[1] + 1);
}
-
+
iph = NULL;
} else {
static u_int8_t ipv4_warning_used = 0;
@@ -1070,7 +1388,7 @@ iph_check:
/* process the packet */
return(packet_processing(workflow, time, vlan_id, iph, iph6,
ip_offset, header->caplen - ip_offset,
- header->caplen, header, packet));
+ header->caplen, header, packet, header->ts));
}
/* ********************************************************** */
diff --git a/example/reader_util.h b/example/reader_util.h
index b006fd8d3..cf6acc7ec 100644
--- a/example/reader_util.h
+++ b/example/reader_util.h
@@ -31,6 +31,7 @@
#include "uthash.h"
#include <pcap.h>
+#include "ndpi_classify.h"
#ifdef USE_DPDK
#include <rte_eal.h>
@@ -50,6 +51,14 @@
extern int dpdk_port_init(int port, struct rte_mempool *mbuf_pool);
#endif
+/* ETTA Spec defiintions for feature readiness */
+#define ETTA_MIN_PACKETS 10
+#define ETTA_MIN_OCTETS 4000
+/** maximum line length */
+#define LINEMAX 512
+#define MAX_BYTE_COUNT_ARRAY_LENGTH 256
+#define MAX_NUM_PKTS 100
+
#define MAX_NUM_READER_THREADS 16
#define IDLE_SCAN_PERIOD 10 /* msec (use TICK_RESOLUTION = 1000) */
#define MAX_IDLE_TIME 30000
@@ -115,6 +124,7 @@ typedef struct ndpi_ja3_fingerprints_host{
// flow tracking
typedef struct ndpi_flow_info {
+ u_int32_t flow_id;
u_int32_t hashval;
u_int32_t src_ip;
u_int32_t dst_ip;
@@ -128,6 +138,7 @@ typedef struct ndpi_flow_info {
u_int64_t last_seen;
u_int64_t src2dst_bytes, dst2src_bytes;
u_int32_t src2dst_packets, dst2src_packets;
+ u_int32_t src2dst_opackets, dst2src_opackets;
u_int32_t has_human_readeable_strings;
char human_readeable_string_buffer[32];
@@ -141,13 +152,36 @@ typedef struct ndpi_flow_info {
struct {
u_int16_t ssl_version;
- char client_info[64], server_info[64], server_organization[64],
+ char client_info[64], server_info[64],
+ client_hassh[33], server_hassh[33],
+ server_organization[64],
ja3_client[33], ja3_server[33];
u_int16_t server_cipher;
ndpi_cipher_weakness client_unsafe_cipher, server_unsafe_cipher;
- } ssh_ssl;
+ } ssh_tls;
void *src_id, *dst_id;
+
+ // Entropy fields
+ u_int16_t src2dst_pkt_len[MAX_NUM_PKTS]; /*!< array of packet appdata lengths */
+ struct timeval src2dst_pkt_time[MAX_NUM_PKTS]; /*!< array of arrival times */
+ u_int16_t dst2src_pkt_len[MAX_NUM_PKTS]; /*!< array of packet appdata lengths */
+ struct timeval dst2src_pkt_time[MAX_NUM_PKTS]; /*!< array of arrival times */
+ struct timeval src2dst_start; /*!< first packet arrival time */
+ struct timeval dst2src_start; /*!< first packet arrival time */
+ u_int16_t src2dst_pkt_count; /*!< packet counts */
+ u_int16_t dst2src_pkt_count; /*!< packet counts */
+ u_int32_t src2dst_l4_bytes; /*!< packet counts */
+ u_int32_t dst2src_l4_bytes; /*!< packet counts */
+ u_int32_t src2dst_byte_count[256]; /*!< number of occurences of each byte */
+ u_int32_t dst2src_byte_count[256]; /*!< number of occurences of each byte */
+ u_int32_t src2dst_num_bytes;
+ u_int32_t dst2src_num_bytes;
+ double src2dst_bd_mean;
+ double src2dst_bd_variance;
+ double dst2src_bd_mean;
+ double dst2src_bd_variance;
+ float score;
} ndpi_flow_info_t;
@@ -245,6 +279,7 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
u_int32_t ethernet_crc32(const void* data, size_t n_bytes);
void ndpi_flow_info_freer(void *node);
const char* print_cipher_id(u_int32_t cipher);
+float ndpi_flow_get_byte_count_entropy(const uint32_t byte_count[256], unsigned int num_bytes);
extern int nDPI_LogLevel;