aboutsummaryrefslogtreecommitdiff
path: root/example
diff options
context:
space:
mode:
Diffstat (limited to 'example')
-rw-r--r--example/ndpiReader.c105
-rw-r--r--example/reader_util.c30
-rw-r--r--example/reader_util.h7
3 files changed, 122 insertions, 20 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index 912f2f99b..74e28a094 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -73,6 +73,7 @@ static char *_statsFilePath = NULL; /**< Top stats file path */
static char *_diagnoseFilePath = NULL; /**< Top stats file path */
static char *_jsonFilePath = NULL; /**< JSON file path */
static FILE *stats_fp = NULL; /**< for Top Stats JSON file */
+static FILE *csv_fp = NULL; /**< for CSV export */
#endif
#ifdef HAVE_JSON_C
static json_object *jArray_known_flows = NULL, *jArray_unknown_flows = NULL;
@@ -347,7 +348,7 @@ static void help(u_int long_help) {
#endif
"[-f <filter>][-s <duration>][-m <duration>]\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"
+ " [-n <threads>][-w <file>][-c <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"
@@ -378,6 +379,7 @@ static void help(u_int long_help) {
" | Default: %u:%u:%u:%u:%u\n"
" -r | Print nDPI version and git revision\n"
" -c <path> | Load custom categories from the specified file\n"
+ " -C <path> | Write output in CSV format on the specified file\n"
" -w <path> | Write test output on the specified file. This is useful for\n"
" | testing purposes in order to compare results across runs\n"
" -h | This help\n"
@@ -438,6 +440,8 @@ static struct option longopts[] = {
/* ndpiReader options */
{ "enable-protocol-guess", no_argument, NULL, 'd'},
+ { "categories", required_argument, NULL, 'c'},
+ { "csv-dump", required_argument, NULL, 'C'},
{ "interface", required_argument, NULL, 'i'},
{ "filter", required_argument, NULL, 'f'},
{ "cpu-bind", required_argument, NULL, 'g'},
@@ -576,6 +580,26 @@ void extcap_capture() {
/* ********************************** */
+void printCSVHeader() {
+ if(!csv_fp) return;
+
+ fprintf(csv_fp, "#flow_id,protocol,first_seen,last_seen,src_ip,src_port,dst_ip,dst_port,ndpi_proto_num,ndpi_proto,");
+ fprintf(csv_fp, "src2dst_packets,src2dst_bytes,dst2src_packets,dst2src_bytes,");
+ fprintf(csv_fp, "data_ratio,str_data_ratio,");
+
+ /* IAT (Inter Arrival Time) */
+ fprintf(csv_fp, "iat_flow_min,iat_flow_avg,iat_flow_max,iat_flow_stddev,");
+ fprintf(csv_fp, "iat_c_to_s_min,iat_c_to_s_avg,iat_c_to_s_max,iat_c_to_s_stddev,");
+ fprintf(csv_fp, "iat_s_to_c_min,iat_s_to_c_avg,iat_s_to_c_max,iat_s_to_c_stddev,");
+
+/* Packet Length */
+ fprintf(csv_fp, "pktlen_c_to_s_min,pktlen_c_to_s_avg,pktlen_c_to_s_max,pktlen_c_to_s_stddev");
+ fprintf(csv_fp, "pktlen_s_to_c_min,pktlen_s_to_c_avg,pktlen_s_to_c_max,pktlen_s_to_c_stddev");
+ fprintf(csv_fp, "\n");
+}
+
+/* ********************************** */
+
/**
* @brief Option parser
*/
@@ -604,7 +628,7 @@ static void parseOptions(int argc, char **argv) {
}
#endif
- while((opt = getopt_long(argc, argv, "e:c:df:g:i:hp:P: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:C:df:g:i:hp:P:l: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 : "");
@@ -671,6 +695,13 @@ static void parseOptions(int argc, char **argv) {
_customCategoryFilePath = optarg;
break;
+ case 'C':
+ if((csv_fp = fopen(optarg, "w")) == NULL)
+ printf("Unable to write on CSV file %s\n", optarg);
+ else
+ printCSVHeader();
+ break;
+
case 's':
capture_for = atoi(optarg);
capture_until = capture_for + time(NULL);
@@ -949,7 +980,48 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
json_object *jObj;
#endif
FILE *out = results_file ? results_file : stdout;
-
+
+ if(csv_fp != NULL) {
+ char buf[32];
+ float data_ratio = ndpi_data_ratio(flow->src2dst_bytes, flow->dst2src_bytes);
+ float f = (float)flow->first_seen, l = (float)flow->last_seen;
+
+ /* PLEASE KEEP IN SYNC WITH printCSVHeader() */
+
+ fprintf(csv_fp, "%u,%u,%.3f,%.3f,%s,%u,%s,%u,",
+ flow->flow_id,
+ flow->protocol,
+ f/1000.0, l/1000.0,
+ flow->src_name, ntohs(flow->src_port),
+ flow->dst_name, ntohs(flow->dst_port)
+ );
+
+ fprintf(csv_fp, "%u.%u,%s,",
+ flow->detected_protocol.master_protocol, flow->detected_protocol.app_protocol,
+ ndpi_protocol2name(ndpi_thread_info[thread_id].workflow->ndpi_struct,
+ flow->detected_protocol, buf, sizeof(buf)));
+
+ fprintf(csv_fp, "%u,%llu,", flow->src2dst_packets, (long long unsigned int) flow->src2dst_bytes);
+ fprintf(csv_fp, "%u,%llu,", flow->dst2src_packets, (long long unsigned int) flow->dst2src_bytes);
+
+ fprintf(csv_fp, "%.3f,%s,", data_ratio, ndpi_data_ratio2str(data_ratio));
+
+ /* IAT (Inter Arrival Time) */
+ fprintf(csv_fp, "%u,%.1f,%u,%.1f",
+ ndpi_data_min(flow->iat_flow), ndpi_data_average(flow->iat_flow), ndpi_data_max(flow->iat_flow), ndpi_data_stddev(flow->iat_flow));
+
+ fprintf(csv_fp, "%u,%.1f,%u,%.1f,%u,%.1f,%u,%.1f",
+ ndpi_data_min(flow->iat_c_to_s), ndpi_data_average(flow->iat_c_to_s), ndpi_data_max(flow->iat_c_to_s), ndpi_data_stddev(flow->iat_c_to_s),
+ ndpi_data_min(flow->iat_s_to_c), ndpi_data_average(flow->iat_s_to_c), ndpi_data_max(flow->iat_s_to_c), ndpi_data_stddev(flow->iat_s_to_c));
+
+ /* Packet Length */
+ fprintf(csv_fp, "%u,%.1f,%u,%.1f,%u,%.1f,%u,%.1f",
+ ndpi_data_min(flow->pktlen_c_to_s), ndpi_data_average(flow->pktlen_c_to_s), ndpi_data_max(flow->pktlen_c_to_s), ndpi_data_stddev(flow->pktlen_c_to_s),
+ ndpi_data_min(flow->pktlen_s_to_c), ndpi_data_average(flow->pktlen_s_to_c), ndpi_data_max(flow->pktlen_s_to_c), ndpi_data_stddev(flow->pktlen_s_to_c));
+
+ fprintf(csv_fp, "\n");
+ }
+
if((verbose != 1) && (verbose != 2))
return;
@@ -1006,13 +1078,22 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
if((flow->src2dst_packets+flow->dst2src_packets) > 5) {
if(flow->iat_c_to_s && flow->iat_s_to_c) {
float data_ratio = ndpi_data_ratio(flow->src2dst_bytes, flow->dst2src_bytes);
+
fprintf(out, "[bytes ratio: %.3f (%s)]", data_ratio, ndpi_data_ratio2str(data_ratio));
/* IAT (Inter Arrival Time) */
- fprintf(out, "[IAT c2s/s2c avg/stddev/entropy: %.1f/%.1f %.1f/%.1f %.1f/%.1f]",
- ndpi_data_average(flow->iat_c_to_s), ndpi_data_average(flow->iat_s_to_c),
- ndpi_data_stddev(flow->iat_c_to_s), ndpi_data_stddev(flow->iat_s_to_c),
- ndpi_data_entropy(flow->iat_c_to_s), ndpi_data_entropy(flow->iat_s_to_c));
+ fprintf(out, "[IAT c2s/s2c min/avg/max/stddev: %u/%u %.1f/%.1f %u/%u %.1f/%.1f]",
+ ndpi_data_min(flow->iat_c_to_s), ndpi_data_min(flow->iat_s_to_c),
+ (float)ndpi_data_average(flow->iat_c_to_s), (float)ndpi_data_average(flow->iat_s_to_c),
+ ndpi_data_max(flow->iat_c_to_s), ndpi_data_max(flow->iat_s_to_c),
+ (float)ndpi_data_stddev(flow->iat_c_to_s), (float)ndpi_data_stddev(flow->iat_s_to_c));
+
+ /* Packet Length */
+ fprintf(out, "[Pkt Len c2s/s2c min/avg/max/stddev: %u/%u %.1f/%.1f %u/%u %.1f/%.1f]",
+ ndpi_data_min(flow->pktlen_c_to_s), ndpi_data_min(flow->pktlen_s_to_c),
+ ndpi_data_average(flow->pktlen_c_to_s), ndpi_data_average(flow->pktlen_s_to_c),
+ ndpi_data_max(flow->pktlen_c_to_s), ndpi_data_max(flow->pktlen_s_to_c),
+ ndpi_data_stddev(flow->pktlen_c_to_s), ndpi_data_stddev(flow->pktlen_s_to_c));
}
}
@@ -2517,7 +2598,7 @@ static void printFlowsStats() {
if(verbose > 1) {
for(i=0; i<num_flows; i++)
- printFlow(i+1, all_flows[i].flow, all_flows[i].thread_id);
+ printFlow(i+1, all_flows[i].flow, all_flows[i].thread_id);
}
for(thread_id = 0; thread_id < num_threads; thread_id++) {
@@ -3998,7 +4079,7 @@ int orginal_main(int argc, char **argv) {
int main(int argc, char **argv) {
#endif
int i;
-
+
if(ndpi_get_api_version() != NDPI_API_VERSION) {
printf("nDPI Library version mismatch: please make sure this code and the nDPI library are in sync\n");
return(-1);
@@ -4041,14 +4122,12 @@ int orginal_main(int argc, char **argv) {
for(i=0; i<num_loops; i++)
test_lib();
-
-
if(results_path) free(results_path);
if(results_file) fclose(results_file);
if(extcap_dumper) pcap_dump_close(extcap_dumper);
if(ndpi_info_mod) ndpi_exit_detection_module(ndpi_info_mod);
-
-
+ if(csv_fp) fclose(csv_fp);
+
return 0;
}
diff --git a/example/reader_util.c b/example/reader_util.c
index f2a466e8f..c716d1766 100644
--- a/example/reader_util.c
+++ b/example/reader_util.c
@@ -451,12 +451,14 @@ void ndpi_flow_info_freer(void *node) {
ndpi_free_flow_info_half(flow);
- if(flow->iat_c_to_s)
- ndpi_free_data_analysis(flow->iat_c_to_s);
+ if(flow->iat_c_to_s) ndpi_free_data_analysis(flow->iat_c_to_s);
+ if(flow->iat_s_to_c) ndpi_free_data_analysis(flow->iat_s_to_c);
- if(flow->iat_s_to_c)
- ndpi_free_data_analysis(flow->iat_s_to_c);
+ if(flow->pktlen_c_to_s) ndpi_free_data_analysis(flow->pktlen_c_to_s);
+ if(flow->pktlen_s_to_c) ndpi_free_data_analysis(flow->pktlen_s_to_c);
+ if(flow->iat_flow) ndpi_free_data_analysis(flow->iat_flow);
+
ndpi_free(flow);
}
@@ -762,6 +764,9 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow
newflow->ip_version = version;
newflow->iat_c_to_s = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW),
newflow->iat_s_to_c = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW);
+ newflow->pktlen_c_to_s = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW),
+ newflow->pktlen_s_to_c = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW),
+ newflow->iat_flow = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW);;
if(version == IPVERSION) {
inet_ntop(AF_INET, &newflow->src_ip, newflow->src_name, sizeof(newflow->src_name));
@@ -1045,6 +1050,18 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
workflow->stats.total_ip_bytes += rawsize;
ndpi_flow = flow->ndpi_flow;
+ if(flow->flow_last_pkt_time.tv_sec) {
+ ndpi_timer_sub(&when, &flow->flow_last_pkt_time, &tdiff);
+
+ if(flow->iat_flow) {
+ u_int32_t ms = ndpi_timeval_to_milliseconds(tdiff);
+
+ if(ms > 0)
+ ndpi_data_add_value(flow->iat_flow, ms);
+ }
+ }
+ memcpy(&flow->flow_last_pkt_time, &when, sizeof(when));
+
if(src_to_dst_direction) {
if(flow->src2dst_last_pkt_time.tv_sec) {
ndpi_timer_sub(&when, &flow->src2dst_last_pkt_time, &tdiff);
@@ -1056,6 +1073,7 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
}
}
+ ndpi_data_add_value(flow->pktlen_c_to_s, rawsize);
flow->src2dst_packets++, flow->src2dst_bytes += rawsize;
flow->src2dst_l4_bytes += payload_len;
memcpy(&flow->src2dst_last_pkt_time, &when, sizeof(when));
@@ -1070,6 +1088,7 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
}
}
+ ndpi_data_add_value(flow->pktlen_s_to_c, rawsize);
flow->dst2src_packets++, flow->dst2src_bytes += rawsize;
flow->dst2src_l4_bytes += payload_len;
memcpy(&flow->dst2src_last_pkt_time, &when, sizeof(when));
@@ -1086,6 +1105,9 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
ndpi_flow_update_byte_dist_mean_var(flow, payload, payload_len, src_to_dst_direction);
}
+ if(flow->first_seen == 0)
+ flow->first_seen = time;
+
flow->last_seen = time;
if(!flow->has_human_readeable_strings) {
diff --git a/example/reader_util.h b/example/reader_util.h
index 8f248a5f0..0d3c2c9d9 100644
--- a/example/reader_util.h
+++ b/example/reader_util.h
@@ -137,7 +137,7 @@ typedef struct ndpi_flow_info {
struct ndpi_flow_struct *ndpi_flow;
char src_name[48], dst_name[48];
u_int8_t ip_version;
- u_int64_t last_seen;
+ u_int64_t first_seen, last_seen;
u_int64_t src2dst_bytes, dst2src_bytes;
u_int32_t src2dst_packets, dst2src_packets;
u_int32_t src2dst_opackets, dst2src_opackets;
@@ -148,7 +148,8 @@ typedef struct ndpi_flow_info {
ndpi_protocol detected_protocol;
// Flow data analysis
- struct ndpi_analyze_struct *iat_c_to_s, *iat_s_to_c;
+ struct ndpi_analyze_struct *iat_c_to_s, *iat_s_to_c, *iat_flow,
+ *pktlen_c_to_s, *pktlen_s_to_c;
char info[96];
char host_server_name[256];
@@ -167,7 +168,7 @@ typedef struct ndpi_flow_info {
void *src_id, *dst_id;
- struct timeval src2dst_last_pkt_time, dst2src_last_pkt_time;
+ struct timeval src2dst_last_pkt_time, dst2src_last_pkt_time, flow_last_pkt_time;
// Entropy fields
u_int16_t src2dst_pkt_len[MAX_NUM_PKTS]; /*!< array of packet appdata lengths */