diff options
-rw-r--r-- | example/ndpiReader.c | 242 | ||||
-rw-r--r-- | example/ndpi_util.c | 42 | ||||
-rw-r--r-- | example/ndpi_util.h | 6 |
3 files changed, 255 insertions, 35 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index dda137df9..0852777c8 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -24,11 +24,11 @@ #endif #include <stdio.h> #include <stdlib.h> +#include <getopt.h> #ifdef WIN32 #include <winsock2.h> /* winsock.h is included automatically */ #include <process.h> #include <io.h> -#include <getopt.h> #define getopt getopt____ #else #include <unistd.h> @@ -81,6 +81,10 @@ static time_t capture_for = 0; static time_t capture_until = 0; static u_int32_t num_flows; +static pcap_dumper_t *extcap_dumper = NULL; +static char *extcap_capture_fifo = NULL; +static u_int16_t extcap_packet_filter = (u_int16_t)-1; + // struct associated to a workflow for a thread struct reader_thread { struct ndpi_workflow * workflow; @@ -104,8 +108,15 @@ typedef struct ndpi_id { u_int32_t current_ndpi_memory = 0, max_ndpi_memory = 0; -/********************** FUNCTIONS ********************* */ +void test_lib(); /* Forward */ + +/* ********************************** */ + +#ifdef DEBUG_TRACE +FILE *trace = NULL; +#endif +/********************** FUNCTIONS ********************* */ /** * @brief Set main components necessary to the detection @@ -142,6 +153,20 @@ static void help(u_int long_help) { " -h | This help\n" " -v <1|2> | Verbose 'unknown protocol' packet print. 1=verbose, 2=very verbose\n"); + #ifndef WIN32 + printf("\nExcap (wireshark) options:\n" + " --extcap-interfaces\n" + " --extcap-version\n" + " --extcap-dlts\n" + " --extcap-interface <name>\n" + " --extcap-config\n" + " --capture\n" + " --extcap-capture-filter\n" + " --fifo <path to file or pipe>\n" + " --debug\n" + ); + #endif + if(long_help) { printf("\n\nSupported protocols:\n"); num_threads = 1; @@ -152,28 +177,153 @@ static void help(u_int long_help) { } +static struct option longopts[] = { + /* mandatory extcap options */ + { "extcap-interfaces", no_argument, NULL, '0'}, + { "extcap-version", optional_argument, NULL, '1'}, + { "extcap-dlts", no_argument, NULL, '2'}, + { "extcap-interface", required_argument, NULL, '3'}, + { "extcap-config", no_argument, NULL, '4'}, + { "capture", no_argument, NULL, '5'}, + { "extcap-capture-filter", required_argument, NULL, '6'}, + { "fifo", required_argument, NULL, '7'}, + { "debug", optional_argument, NULL, '8'}, + { "ndpi-proto-filter", required_argument, NULL, '9'}, + + /* ndpiReader options */ + { "enable-protocol-guess", no_argument, NULL, 'd'}, + { "interface", required_argument, NULL, 'i'}, + { "filter", required_argument, NULL, 'f'}, + { "cpu-bind", required_argument, NULL, 'g'}, + { "loops", required_argument, NULL, 'l'}, + { "num-threads", required_argument, NULL, 'n'}, + + { "protos", required_argument, NULL, 'p'}, + { "capture-duration", required_argument, NULL, 's'}, + { "decode-tunnels", no_argument, NULL, 't'}, + { "revision", no_argument, NULL, 'r'}, + { "verbose", no_argument, NULL, 'v'}, + { "version", no_argument, NULL, 'V'}, + { "help", no_argument, NULL, 'h'}, + { "json", required_argument, NULL, 'j'}, + { "result-path", required_argument, NULL, 'w'}, + { "quiet", no_argument, NULL, 'q'}, + + {0, 0, 0, 0} +}; + +/* ********************************** */ + +void extcap_interfaces() { + printf("extcap {version=%s}\n", ndpi_revision()); + printf("interface {value=ndpi}{display=nDPI interface}\n"); + exit(0); +} + +/* ********************************** */ + +void extcap_dlts() { + u_int dlts_number = DLT_EN10MB; + printf("dlt {number=%u}{name=%s}{display=%s}\n", dlts_number, "ndpi", "nDPI interface"); + exit(0); +} + +/* ********************************** */ + +void extcap_config() { + int i, argidx = 0; + struct ndpi_detection_module_struct *ndpi_mod; + +#if 1 + printf("arg {number=%u}{call=-i}{display=Capture Interface Name}{type=string}" + "{tooltip=The interface name}\n", argidx++); +#else + + printf("arg {number=%u}{call=-i}{display=Pcap File to Analize}{type=fileselect}" + "{tooltip=The pcap file to analyze (if the interface is unspecified)}\n", argidx++); +#endif + + printf("arg {number=%u}{call=-9}{display=nDPI Protocol}{type=selector}" + "{tooltip=nDPI Protocol to be filtered}\n", argidx); + + setupDetection(0, NULL); + ndpi_mod = ndpi_thread_info[0].workflow->ndpi_struct; + + printf("value {arg=%d}{value=%d}{display=%s}\n", argidx, -1, "All Protocols (no nDPI filtering)"); + + for(i=0; i<(int)ndpi_mod->ndpi_num_supported_protocols; i++) + printf("value {arg=%d}{value=%d}{display=%s (%u)}\n", argidx, i, + ndpi_mod->proto_defaults[i].protoName, i); + + exit(0); +} + +/* ********************************** */ + +void extcap_capture() { +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, " #### %s #### \n", __FUNCTION__); +#endif + + if((extcap_dumper = pcap_dump_open(pcap_open_dead(DLT_EN10MB, 16384 /* MTU */), + extcap_capture_fifo)) == NULL) { + fprintf(stderr, "Unable to open the pcap dumper on %s", extcap_capture_fifo); + +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, "Unable to open the pcap dumper on %s\n", + extcap_capture_fifo); +#endif + return; + } + +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, "Starting packet capture [%p]\n", extcap_dumper); +#endif + + test_lib(); + pcap_dump_close(extcap_dumper); + +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, "End of packet capture [%p]\n", extcap_dumper); +#endif +} + +/* ********************************** */ + /** * @brief Option parser */ static void parseOptions(int argc, char **argv) { - + int option_idx = 0, do_capture = 0; char *__pcap_file = NULL, *bind_mask = NULL; int thread_id, opt; #ifdef linux u_int num_cores = sysconf(_SC_NPROCESSORS_ONLN); #endif - while ((opt = getopt(argc, argv, "df:g:i:hp:l:s:tv:V:n:j:rp:w:q")) != EOF) { +#ifdef DEBUG_TRACE + trace = fopen("/tmp/ndpiReader.log", "a"); + + if(trace) fprintf(trace, " #### %s #### \n", __FUNCTION__); +#endif + + while ((opt = getopt_long(argc, argv, "df:g:i:hp:l:s:tv:V:n:j:rp:w:q0123:456:7:89:", longopts, &option_idx)) != EOF) { +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, " #### -%c [%s] #### \n", opt, optarg ? optarg : ""); +#endif + switch (opt) { case 'd': enable_protocol_guess = 0; break; case 'i': + case '3': _pcap_file[0] = optarg; break; case 'f': + case '6': _bpf_filter = optarg; break; @@ -240,12 +390,47 @@ static void parseOptions(int argc, char **argv) { quiet_mode = 1; break; + /* Extcap */ + case '0': + extcap_interfaces(); + break; + + case '1': + printf("extcap {version=%s}\n", ndpi_revision()); + break; + + case '2': + extcap_dlts(); + break; + + case '4': + extcap_config(); + break; + + case '5': + do_capture = 1; + break; + + case '7': + extcap_capture_fifo = strdup(optarg); + break; + + case '8': + nDPI_traceLevel = 9; + break; + + case '9': + extcap_packet_filter = atoi(optarg); + break; + default: help(0); break; } } + if(do_capture) extcap_capture(); + // check parameters if(_pcap_file[0] == NULL || strcmp(_pcap_file[0], "") == 0) { help(0); @@ -277,6 +462,10 @@ static void parseOptions(int argc, char **argv) { } } #endif + +#ifdef DEBUG_TRACE + if(trace) fclose(trace); +#endif } @@ -370,7 +559,7 @@ static void printFlow(u_int16_t thread_id, struct ndpi_flow_info *flow) { ntohs(flow->upper_port)); if(flow->vlan_id > 0) fprintf(out, "[VLAN: %u]", flow->vlan_id); - + if(flow->detected_protocol.master_protocol) { char buf[64]; @@ -388,7 +577,7 @@ static void printFlow(u_int16_t thread_id, struct ndpi_flow_info *flow) { if(flow->host_server_name[0] != '\0') fprintf(out, "[Host: %s]", flow->host_server_name); if(flow->info[0] != '\0') fprintf(out, "[%s]", flow->info); - + if(flow->ssh_ssl.client_info[0] != '\0') fprintf(out, "[client: %s]", flow->ssh_ssl.client_info); if(flow->ssh_ssl.server_info[0] != '\0') fprintf(out, "[server: %s]", flow->ssh_ssl.server_info); if(flow->bittorent_hash[0] != '\0') fprintf(out, "[BT Hash: %s]", flow->bittorent_hash); @@ -1138,13 +1327,14 @@ static pcap_t * openPcapFileOrDevice(u_int16_t thread_id, const u_char * pcap_fi static void pcap_packet_callback_checked(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { - + struct ndpi_proto p; u_int16_t thread_id = *((u_int16_t*)args); /* allocate an exact size buffer to check overflows */ uint8_t *packet_checked = malloc(header->caplen); + memcpy(packet_checked, packet, header->caplen); - ndpi_workflow_process_packet(ndpi_thread_info[thread_id].workflow, header, packet_checked); + p = ndpi_workflow_process_packet(ndpi_thread_info[thread_id].workflow, header, packet_checked); if((capture_until != 0) && (header->ts.tv_sec >= capture_until)) { if(ndpi_thread_info[thread_id].workflow->pcap_handle != NULL) @@ -1182,6 +1372,25 @@ static void pcap_packet_callback_checked(u_char *args, } } +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, "Found %u bytes packet %u.%u\n", header->caplen, p.app_protocol, p.master_protocol); +#endif + + if(extcap_dumper + && ((extcap_packet_filter == (u_int16_t)-1) + || (p.app_protocol == extcap_packet_filter) + || (p.master_protocol == extcap_packet_filter) + ) + ) { + struct pcap_pkthdr *h = (struct pcap_pkthdr*)header; + +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, "Dumping %u bytes packet\n", header->caplen); +#endif + // h->caplen += 8, h->len += 8; + pcap_dump((u_char*)extcap_dumper, h, packet); + } + /* check for buffer changes */ if(memcmp(packet, packet_checked, header->caplen) != 0) printf("INTERNAL ERROR: ingress packet was modified by nDPI: this should not happen [thread_id=%u, packetId=%lu]\n", @@ -1244,7 +1453,6 @@ void * processing_thread(void *_thread_id) { * @brief Begin, process, end detection process */ void test_lib() { - struct timeval begin, end; u_int64_t tot_usec; long thread_id; @@ -1253,8 +1461,18 @@ void test_lib() { json_init(); #endif +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, "Num threads: %d\n", num_threads); +#endif + for(thread_id = 0; thread_id < num_threads; thread_id++) { - pcap_t * cap = openPcapFileOrDevice(thread_id, (const u_char*)_pcap_file[thread_id]); + pcap_t *cap; + +#ifdef DEBUG_TRACE + if(trace) fprintf(trace, "Opening %s\n", (const u_char*)_pcap_file[thread_id]); +#endif + + cap = openPcapFileOrDevice(thread_id, (const u_char*)_pcap_file[thread_id]); setupDetection(thread_id, cap); } @@ -1275,9 +1493,9 @@ void test_lib() { printResults(tot_usec); for(thread_id = 0; thread_id < num_threads; thread_id++) { - if(ndpi_thread_info[thread_id].workflow->pcap_handle != NULL) { + if(ndpi_thread_info[thread_id].workflow->pcap_handle != NULL) pcap_close(ndpi_thread_info[thread_id].workflow->pcap_handle); - } + terminateDetection(thread_id); } } diff --git a/example/ndpi_util.c b/example/ndpi_util.c index d2f002270..60dc94230 100644 --- a/example/ndpi_util.c +++ b/example/ndpi_util.c @@ -502,13 +502,13 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl @Note: ipsize = header->len - ip_offset ; rawsize = header->len */ -static unsigned int packet_processing(struct ndpi_workflow * workflow, - const u_int64_t time, - u_int16_t vlan_id, - const struct ndpi_iphdr *iph, - struct ndpi_ipv6hdr *iph6, - u_int16_t ip_offset, - u_int16_t ipsize, u_int16_t rawsize) { +static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow, + const u_int64_t time, + u_int16_t vlan_id, + const struct ndpi_iphdr *iph, + struct ndpi_ipv6hdr *iph6, + u_int16_t ip_offset, + u_int16_t ipsize, u_int16_t rawsize) { struct ndpi_id_struct *src, *dst; struct ndpi_flow_info *flow = NULL; struct ndpi_flow_struct *ndpi_flow = NULL; @@ -540,11 +540,11 @@ static unsigned int packet_processing(struct ndpi_workflow * workflow, flow->packets++, flow->bytes += rawsize; flow->last_seen = time; } else { - return(0); + return(flow->detected_protocol); } /* Protocol already detected */ - if(flow->detection_completed) return(0); + if(flow->detection_completed) return(flow->detected_protocol); flow->detected_protocol = ndpi_detection_process_packet(workflow->ndpi_struct, ndpi_flow, iph ? (uint8_t *)iph : (uint8_t *)iph6, @@ -565,14 +565,14 @@ static unsigned int packet_processing(struct ndpi_workflow * workflow, } process_ndpi_collected_info(workflow, flow); - return 0; + return(flow->detected_protocol); } /* ****************************************************** */ -void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, - const struct pcap_pkthdr *header, - const u_char *packet) { +struct ndpi_proto ndpi_workflow_process_packet (struct ndpi_workflow * workflow, + const struct pcap_pkthdr *header, + const u_char *packet) { /* * Declare pointers to packet headers */ @@ -597,6 +597,8 @@ void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, /** --- IPv6 header --- **/ struct ndpi_ipv6hdr *iph6; + struct ndpi_proto nproto = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN }; + /* lengths and offsets */ u_int16_t eth_offset = 0; u_int16_t radio_len; @@ -691,7 +693,7 @@ void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, /* Check Bad FCS presence */ if((radiotap->flags & BAD_FCS) == BAD_FCS) { workflow->stats.total_discarded_bytes += header->len; - return; + return(nproto); } /* Calculate 802.11 header length (variable) */ @@ -721,7 +723,7 @@ void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, default: /* printf("Unknown datalink %d\n", datalink_type); */ - return; + return(nproto); } /* check ether type */ @@ -802,7 +804,7 @@ void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, } workflow->stats.total_discarded_bytes += header->len; - return; + return(nproto); } } else if(iph->version == 6) { iph6 = (struct ndpi_ipv6hdr *)&packet[ip_offset]; @@ -827,7 +829,7 @@ void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, ipv4_warning_used = 1; } workflow->stats.total_discarded_bytes += header->len; - return; + return(nproto); } if(workflow->prefs.decode_tunnels && (proto == IPPROTO_UDP)) { @@ -886,7 +888,7 @@ void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, offset += tag_len; if(offset >= header->caplen) - return; /* Invalid packet */ + return(nproto); /* Invalid packet */ else { eth_offset = offset; goto datalink_check; @@ -897,6 +899,6 @@ void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, } /* process the packet */ - packet_processing(workflow, time, vlan_id, iph, iph6, - ip_offset, header->len - ip_offset, header->len); + return(packet_processing(workflow, time, vlan_id, iph, iph6, + ip_offset, header->len - ip_offset, header->len)); } diff --git a/example/ndpi_util.h b/example/ndpi_util.h index 1c092cbfa..4895cdcb1 100644 --- a/example/ndpi_util.h +++ b/example/ndpi_util.h @@ -138,9 +138,9 @@ void ndpi_free_flow_info_half(struct ndpi_flow_info *flow); /* Process a packet and update the workflow */ -void ndpi_workflow_process_packet (struct ndpi_workflow * workflow, - const struct pcap_pkthdr *header, - const u_char *packet); +struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, + const struct pcap_pkthdr *header, + const u_char *packet); /* flow callbacks for complete detected flow |