diff options
Diffstat (limited to 'example')
-rw-r--r-- | example/ndpiReader.c | 17 | ||||
-rw-r--r-- | example/reader_util.c | 167 | ||||
-rw-r--r-- | example/reader_util.h | 1 |
3 files changed, 175 insertions, 10 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index dc1d5505d..06e303a6c 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -81,7 +81,7 @@ 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 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; @@ -213,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 @@ -364,6 +366,7 @@ static void help(u_int long_help) { " -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" @@ -441,6 +444,7 @@ static struct option longopts[] = { { "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'}, @@ -591,7 +595,7 @@ 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:Jrp:w:q0123:456:7:89:m:b:x:T:U:", + 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 : ""); @@ -691,6 +695,10 @@ static void parseOptions(int argc, char **argv) { case 'J': enable_joy_stats = 1; break; + + case 'P': + enable_payload_analyzer = 1; + break; case 'j': #ifndef HAVE_JSON_C @@ -850,6 +858,7 @@ static char* ipProto2Name(u_int16_t proto_id) { /* ********************************** */ +#if 0 /** * @brief A faster replacement for inet_ntoa(). */ @@ -879,6 +888,7 @@ char* intoaV4(u_int32_t addr, char* buf, u_int16_t bufLen) { return(cp); } +#endif /* ********************************** */ @@ -2079,6 +2089,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; diff --git a/example/reader_util.c b/example/reader_util.c index fba2dfa38..b57e23526 100644 --- a/example/reader_util.c +++ b/example/reader_util.c @@ -77,10 +77,157 @@ #include "reader_util.h" #include "ndpi_classify.h" -extern u_int8_t enable_protocol_guess, enable_joy_stats; +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++; + } +} + + + /* ***************************************************** */ void ndpi_free_flow_info_half(struct ndpi_flow_info *flow) { @@ -515,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; @@ -679,7 +827,7 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl 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", @@ -806,23 +954,26 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow, 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_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; @@ -830,7 +981,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, @@ -843,7 +994,7 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow, (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; } @@ -1148,7 +1299,7 @@ iph_check: proto = options[0]; ip_len += 8 * (options[1] + 1); } - + iph = NULL; } else { static u_int8_t ipv4_warning_used = 0; diff --git a/example/reader_util.h b/example/reader_util.h index d100c0ad5..8b511ff30 100644 --- a/example/reader_util.h +++ b/example/reader_util.h @@ -124,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; |