From 667e77c609d842a9a41930b590de206fb2b917fe Mon Sep 17 00:00:00 2001 From: Luca Date: Sat, 21 Jul 2018 16:02:54 +0200 Subject: Major code cleanup Converted some not popular protocols to NDPI_PROTOCOL_GENERIC with category detection --- src/lib/protocols/http.c | 45 +++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) (limited to 'src/lib/protocols/http.c') diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c index ac5b9d173..e03b48710 100644 --- a/src/lib/protocols/http.c +++ b/src/lib/protocols/http.c @@ -1,7 +1,7 @@ /* * http.c * - * Copyright (C) 2011-17 - ntop.org + * Copyright (C) 2011-18 - ntop.org * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH @@ -23,8 +23,6 @@ #include "ndpi_protocol_ids.h" -#ifdef NDPI_PROTOCOL_HTTP - #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_HTTP #include "ndpi_api.h" @@ -121,7 +119,6 @@ static void avi_check_http_payload(struct ndpi_detection_module_struct *ndpi_str } #endif -#ifdef NDPI_PROTOCOL_TEAMVIEWER static void teamviewer_check_http_payload(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; @@ -140,10 +137,7 @@ static void teamviewer_check_http_payload(struct ndpi_detection_module_struct *n ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TEAMVIEWER); } } -#endif - -#ifdef NDPI_PROTOCOL_RTSP static void rtsp_parse_packet_acceptline(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { @@ -154,7 +148,6 @@ static void rtsp_parse_packet_acceptline(struct ndpi_detection_module_struct ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_RTSP); } } -#endif static void setHttpUserAgent(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, char *ua) { @@ -428,25 +421,20 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ if(packet->accept_line.ptr != NULL) { NDPI_LOG_DBG2(ndpi_struct, "Accept line found %.*s\n", packet->accept_line.len, packet->accept_line.ptr); -#ifdef NDPI_PROTOCOL_RTSP - if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, NDPI_PROTOCOL_RTSP) != 0) { + if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, + NDPI_PROTOCOL_RTSP) != 0) { rtsp_parse_packet_acceptline(ndpi_struct, flow); } -#endif } /* search for line startin with "Icy-MetaData" */ -#ifdef NDPI_CONTENT_CATEGORY_MPEG - for (a = 0; a < packet->parsed_lines; a++) { + for (a = 0; a < packet->parsed_lines; a++) { if(packet->line[a].len > 11 && memcmp(packet->line[a].ptr, "Icy-MetaData", 12) == 0) { - NDPI_LOG_INFO(ndpi_struct, "found MPEG: Icy-MetaData\n"); - ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_CONTENT_CATEGORY_MPEG); - return; - } + NDPI_LOG_INFO(ndpi_struct, "found MPEG: Icy-MetaData\n"); + ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_CONTENT_CATEGORY_MPEG); + return; + } } -#ifdef NDPI_CONTENT_CATEGORY_AVI -#endif -#endif if(packet->content_line.ptr != NULL && packet->content_line.len != 0) { NDPI_LOG_DBG2(ndpi_struct, "Content Type line found %.*s\n", @@ -471,10 +459,8 @@ static void check_http_payload(struct ndpi_detection_module_struct *ndpi_struct, if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, NDPI_CONTENT_CATEGORY_AVI) != 0) avi_check_http_payload(ndpi_struct, flow); #endif -#ifdef NDPI_PROTOCOL_TEAMVIEWER - teamviewer_check_http_payload(ndpi_struct, flow); -#endif + teamviewer_check_http_payload(ndpi_struct, flow); } /** @@ -550,9 +536,8 @@ static void http_bitmask_exclude_other(struct ndpi_flow_struct *flow) #ifdef NDPI_CONTENT_CATEGORY_OGG NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_CONTENT_CATEGORY_OGG); #endif -#ifdef NDPI_PROTOCOL_XBOX + NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_XBOX); -#endif } /*************************************************************************************************/ @@ -1007,7 +992,7 @@ void init_http_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int ADD_TO_DETECTION_BITMASK); *id += 1; #endif -#ifdef NDPI_PROTOCOL_XBOX + ndpi_set_bitmask_protocol_detection("Xbox", ndpi_struct, detection_bitmask, *id, NDPI_PROTOCOL_XBOX, ndpi_search_http_tcp, @@ -1015,8 +1000,7 @@ void init_http_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int NO_SAVE_DETECTION_BITMASK_AS_UNKNOWN, ADD_TO_DETECTION_BITMASK); *id += 1; -#endif -#ifdef NDPI_PROTOCOL_QQ + ndpi_set_bitmask_protocol_detection("QQ", ndpi_struct, detection_bitmask, *id, NDPI_PROTOCOL_QQ, ndpi_search_http_tcp, @@ -1024,7 +1008,7 @@ void init_http_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int NO_SAVE_DETECTION_BITMASK_AS_UNKNOWN, ADD_TO_DETECTION_BITMASK); *id += 1; -#endif + #ifdef NDPI_CONTENT_CATEGORY_AVI ndpi_set_bitmask_protocol_detection("AVI", ndpi_struct, detection_bitmask, *id, NDPI_CONTENT_CATEGORY_AVI, @@ -1069,7 +1053,4 @@ void init_http_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int a++; #endif - } - -#endif -- cgit v1.2.3 From 01bf295a19c19dc4f521ee40f0c478c794e1b5e4 Mon Sep 17 00:00:00 2001 From: Luca Deri Date: Thu, 16 Aug 2018 14:57:44 +0200 Subject: Completed custom category implementation --- example/ndpiReader.c | 81 +++++++++++++++++---------- src/include/ndpi_api.h | 6 ++ src/include/ndpi_main.h | 60 ++++++++++++++------ src/include/ndpi_typedefs.h | 9 ++- src/lib/Makefile | 2 +- src/lib/ndpi_main.c | 108 +++++++++++++++++++++++++----------- src/lib/protocols/dns.c | 8 ++- src/lib/protocols/fbzero.c | 4 +- src/lib/protocols/http.c | 27 ++++++--- src/lib/protocols/quic.c | 2 + src/lib/protocols/ssl.c | 67 +++++++++++----------- tests/result/pps.pcap.out | 4 +- tests/result/webex.pcap.out | 58 +++++++++---------- tests/result/whatsappfiles.pcap.out | 4 +- 14 files changed, 283 insertions(+), 157 deletions(-) (limited to 'src/lib/protocols/http.c') diff --git a/example/ndpiReader.c b/example/ndpiReader.c index 39748cd90..faa453ee2 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -111,7 +111,6 @@ struct flow_info { static struct flow_info *all_flows; - struct info_pair { u_int32_t addr; u_int8_t version; /* IP version */ @@ -135,16 +134,15 @@ struct port_stats { u_int32_t cumulative_addr; /*cumulative some of IP addresses */ addr_node *addr_tree; /* tree of distinct IP addresses */ struct info_pair top_ip_addrs[MAX_NUM_IP_ADDRESS]; - u_int8_t hasTopHost; /* as boolean flag*/ - u_int32_t top_host; /*host that is contributed to > 95% of traffic*/ - u_int8_t version; /* top host's ip version */ - char proto[16]; /*application level protocol of top host */ - UT_hash_handle hh; /* makes this structure hashable */ + u_int8_t hasTopHost; /* as boolean flag */ + u_int32_t top_host; /* host that is contributed to > 95% of traffic */ + u_int8_t version; /* top host's ip version */ + char proto[16]; /* application level protocol of top host */ + UT_hash_handle hh; /* makes this structure hashable */ }; struct port_stats *srcStats = NULL, *dstStats = NULL; - // struct to hold count of flows received by destination ports struct port_flow_info { u_int32_t port; /* key */ @@ -349,6 +347,8 @@ struct ndpi_proto_sorter { char name[16]; }; +/* ********************************** */ + int cmpProto(const void *_a, const void *_b) { struct ndpi_proto_sorter *a = (struct ndpi_proto_sorter*)_a; struct ndpi_proto_sorter *b = (struct ndpi_proto_sorter*)_b; @@ -356,6 +356,8 @@ int cmpProto(const void *_a, const void *_b) { return(strcmp(a->name, b->name)); } +/* ********************************** */ + int cmpFlows(const void *_a, const void *_b) { struct ndpi_flow_info *fa = ((struct flow_info*)_a)->flow; struct ndpi_flow_info *fb = ((struct flow_info*)_b)->flow; @@ -375,6 +377,8 @@ int cmpFlows(const void *_a, const void *_b) { return(0); } +/* ********************************** */ + void extcap_config() { int i, argidx = 0; struct ndpi_proto_sorter *protos; @@ -656,12 +660,12 @@ static void parseOptions(int argc, char **argv) { #endif } +/* ********************************** */ /** * @brief From IPPROTO to string NAME */ static char* ipProto2Name(u_int16_t proto_id) { - static char proto[8]; switch(proto_id) { @@ -689,12 +693,12 @@ static char* ipProto2Name(u_int16_t proto_id) { return(proto); } +/* ********************************** */ /** * @brief A faster replacement for inet_ntoa(). */ char* intoaV4(u_int32_t addr, char* buf, u_int16_t bufLen) { - char *cp, *retStr; uint byte; int n; @@ -723,6 +727,8 @@ char* intoaV4(u_int32_t addr, char* buf, u_int16_t bufLen) { return(retStr); } +/* ********************************** */ + /** * @brief Print the flow */ @@ -792,16 +798,20 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa json_object_object_add(jObj,"host_b.port",json_object_new_int(ntohs(flow->dst_port))); if(flow->detected_protocol.master_protocol) - json_object_object_add(jObj,"detected.master_protocol",json_object_new_int(flow->detected_protocol.master_protocol)); + json_object_object_add(jObj,"detected.master_protocol", + json_object_new_int(flow->detected_protocol.master_protocol)); - json_object_object_add(jObj,"detected.app_protocol",json_object_new_int(flow->detected_protocol.app_protocol)); + json_object_object_add(jObj,"detected.app_protocol", + json_object_new_int(flow->detected_protocol.app_protocol)); if(flow->detected_protocol.master_protocol) { char tmp[256]; snprintf(tmp, sizeof(tmp), "%s.%s", - ndpi_get_proto_name(ndpi_thread_info[thread_id].workflow->ndpi_struct, flow->detected_protocol.master_protocol), - ndpi_get_proto_name(ndpi_thread_info[thread_id].workflow->ndpi_struct, flow->detected_protocol.app_protocol)); + ndpi_get_proto_name(ndpi_thread_info[thread_id].workflow->ndpi_struct, + flow->detected_protocol.master_protocol), + ndpi_get_proto_name(ndpi_thread_info[thread_id].workflow->ndpi_struct, + flow->detected_protocol.app_protocol)); json_object_object_add(jObj,"detected.protocol.name", json_object_new_string(tmp)); @@ -836,12 +846,13 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa } } +/* ********************************** */ /** * @brief Unknown Proto Walker */ -static void node_print_unknown_proto_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { - +static void node_print_unknown_proto_walker(const void *node, + ndpi_VISIT which, int depth, void *user_data) { struct ndpi_flow_info *flow = *(struct ndpi_flow_info**)node; u_int16_t thread_id = *((u_int16_t*)user_data); @@ -854,11 +865,13 @@ static void node_print_unknown_proto_walker(const void *node, ndpi_VISIT which, } } +/* ********************************** */ + /** * @brief Known Proto Walker */ -static void node_print_known_proto_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { - +static void node_print_known_proto_walker(const void *node, + ndpi_VISIT which, int depth, void *user_data) { struct ndpi_flow_info *flow = *(struct ndpi_flow_info**)node; u_int16_t thread_id = *((u_int16_t*)user_data); @@ -871,6 +884,7 @@ static void node_print_known_proto_walker(const void *node, ndpi_VISIT which, in } } +/* ********************************** */ /** * @brief Guess Undetected Protocol @@ -890,6 +904,7 @@ static u_int16_t node_guess_undetected_protocol(u_int16_t thread_id, struct ndpi return(flow->detected_protocol.app_protocol); } +/* ********************************** */ /** * @brief Proto Guess Walker @@ -909,6 +924,7 @@ static void node_proto_guess_walker(const void *node, ndpi_VISIT which, int dept } process_ndpi_collected_info(ndpi_thread_info[thread_id].workflow, flow); + ndpi_thread_info[thread_id].workflow->stats.protocol_counter[flow->detected_protocol.app_protocol] += flow->src2dst_packets + flow->dst2src_packets; ndpi_thread_info[thread_id].workflow->stats.protocol_counter_bytes[flow->detected_protocol.app_protocol] += flow->src2dst_bytes + flow->dst2src_bytes; ndpi_thread_info[thread_id].workflow->stats.protocol_flows[flow->detected_protocol.app_protocol]++; @@ -1354,7 +1370,6 @@ static void port_stats_walker(const void *node, ndpi_VISIT which, int depth, voi * @brief Idle Scan Walker */ static void node_idle_scan_walker(const void *node, ndpi_VISIT which, int depth, void *user_data) { - struct ndpi_flow_info *flow = *(struct ndpi_flow_info **) node; u_int16_t thread_id = *((u_int16_t *) user_data); @@ -1386,7 +1401,6 @@ static void node_idle_scan_walker(const void *node, ndpi_VISIT which, int depth, static void on_protocol_discovered(struct ndpi_workflow * workflow, struct ndpi_flow_info * flow, void * udata) { - const u_int16_t thread_id = (uintptr_t) udata; if(verbose > 1) { @@ -1446,7 +1460,6 @@ static void debug_printf(u_int32_t protocol, void *id_struct, * @brief Setup for detection begin */ static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) { - NDPI_PROTOCOL_BITMASK all; struct ndpi_workflow_prefs prefs; @@ -1468,16 +1481,20 @@ static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) { ndpi_pref_enable_category_substring_match, 1); ndpi_workflow_set_flow_detected_callback(ndpi_thread_info[thread_id].workflow, - on_protocol_discovered, (void *)(uintptr_t)thread_id); + on_protocol_discovered, + (void *)(uintptr_t)thread_id); // enable all protocols NDPI_BITMASK_SET_ALL(all); ndpi_set_protocol_detection_bitmask2(ndpi_thread_info[thread_id].workflow->ndpi_struct, &all); // clear memory for results - memset(ndpi_thread_info[thread_id].workflow->stats.protocol_counter, 0, sizeof(ndpi_thread_info[thread_id].workflow->stats.protocol_counter)); - memset(ndpi_thread_info[thread_id].workflow->stats.protocol_counter_bytes, 0, sizeof(ndpi_thread_info[thread_id].workflow->stats.protocol_counter_bytes)); - memset(ndpi_thread_info[thread_id].workflow->stats.protocol_flows, 0, sizeof(ndpi_thread_info[thread_id].workflow->stats.protocol_flows)); + memset(ndpi_thread_info[thread_id].workflow->stats.protocol_counter, 0, + sizeof(ndpi_thread_info[thread_id].workflow->stats.protocol_counter)); + memset(ndpi_thread_info[thread_id].workflow->stats.protocol_counter_bytes, 0, + sizeof(ndpi_thread_info[thread_id].workflow->stats.protocol_counter_bytes)); + memset(ndpi_thread_info[thread_id].workflow->stats.protocol_flows, 0, + sizeof(ndpi_thread_info[thread_id].workflow->stats.protocol_flows)); if(_protoFilePath != NULL) ndpi_load_protocols_file(ndpi_thread_info[thread_id].workflow->ndpi_struct, _protoFilePath); @@ -1608,7 +1625,9 @@ static void json_open_stats_file() { static void json_close_stats_file() { json_object *jObjFinal = json_object_new_object(); - json_object_object_add(jObjFinal,"duration.in.seconds",json_object_new_int(pcap_analysis_duration)); + + json_object_object_add(jObjFinal,"duration.in.seconds", + json_object_new_int(pcap_analysis_duration)); json_object_object_add(jObjFinal,"statistics", jArray_topStats); fprintf(stats_fp,"%s\n",json_object_to_json_string(jObjFinal)); fclose(stats_fp); @@ -1910,8 +1929,10 @@ static void printResults(u_int64_t tot_usec) { continue; for(i=0; indpi_flows_root[i], node_proto_guess_walker, &thread_id); - if(verbose == 3 || stats_flag) ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[i], port_stats_walker, &thread_id); + ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[i], + node_proto_guess_walker, &thread_id); + if(verbose == 3 || stats_flag) ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[i], + port_stats_walker, &thread_id); } /* Stats aggregation */ @@ -2396,11 +2417,11 @@ static void pcap_process_packet(u_char *args, if(live_capture) { if(ndpi_thread_info[thread_id].last_idle_scan_time + IDLE_SCAN_PERIOD < ndpi_thread_info[thread_id].workflow->last_time) { /* scan for idle flows */ - ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[ndpi_thread_info[thread_id].idle_scan_idx], node_idle_scan_walker, &thread_id); + ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[ndpi_thread_info[thread_id].idle_scan_idx], + node_idle_scan_walker, &thread_id); /* remove idle flows (unfortunately we cannot do this inline) */ - while (ndpi_thread_info[thread_id].num_idle_flows > 0) { - + while(ndpi_thread_info[thread_id].num_idle_flows > 0) { /* search and delete the idle flow from the "ndpi_flow_root" (see struct reader thread) - here flows are the node of a b-tree */ ndpi_tdelete(ndpi_thread_info[thread_id].idle_flows[--ndpi_thread_info[thread_id].num_idle_flows], &ndpi_thread_info[thread_id].workflow->ndpi_flows_root[ndpi_thread_info[thread_id].idle_scan_idx], diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h index 358c0491c..3fefc8e4b 100644 --- a/src/include/ndpi_api.h +++ b/src/include/ndpi_api.h @@ -346,6 +346,7 @@ extern "C" { * @par ndpi_struct = the detection module * @par string_to_match = the string to match * @par string_to_match_len = the length of the string + * @par ret_match = completed returned match information * @par is_host_match = value of the second field of struct ndpi_automa * @return the ID of the matched subprotocol * @@ -353,6 +354,7 @@ extern "C" { int ndpi_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_struct, char *string_to_match, u_int string_to_match_len, + ndpi_protocol_match_result *ret_match, u_int8_t is_host_match); /** * Check if the host passed match with a protocol @@ -361,6 +363,7 @@ extern "C" { * @par flow = the flow where match the host * @par string_to_match = the string to match * @par string_to_match_len = the length of the string + * @par ret_match = completed returned match information * @par master_protocol_id = value of the ID associated to the master protocol detected * @return the ID of the matched subprotocol * @@ -369,6 +372,7 @@ extern "C" { struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, + ndpi_protocol_match_result *ret_match, u_int16_t master_protocol_id); @@ -379,6 +383,7 @@ extern "C" { * @par flow = the flow where match the host * @par string_to_match = the string to match * @par string_to_match_len = the length of the string + * @par ret_match = completed returned match information * @par master_protocol_id = value of the ID associated to the master protocol detected * @return the ID of the matched subprotocol * @@ -387,6 +392,7 @@ extern "C" { struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, + ndpi_protocol_match_result *ret_match, u_int16_t master_protocol_id); /** * Exclude protocol from search diff --git a/src/include/ndpi_main.h b/src/include/ndpi_main.h index b18efa21a..3517d45b2 100644 --- a/src/include/ndpi_main.h +++ b/src/include/ndpi_main.h @@ -53,34 +53,55 @@ extern "C" { extern u_int8_t ndpi_ips_match(u_int32_t src, u_int32_t dst, u_int32_t net, u_int32_t num_bits); - u_int16_t ntohs_ndpi_bytestream_to_number(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read); - - u_int32_t ndpi_bytestream_to_number(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read); - u_int64_t ndpi_bytestream_to_number64(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read); - u_int32_t ndpi_bytestream_dec_or_hex_to_number(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read); - u_int64_t ndpi_bytestream_dec_or_hex_to_number64(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read); - u_int32_t ndpi_bytestream_to_ipv4(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read); + u_int16_t ntohs_ndpi_bytestream_to_number(const u_int8_t * str, + u_int16_t max_chars_to_read, + u_int16_t * bytes_read); + + u_int32_t ndpi_bytestream_to_number(const u_int8_t * str, u_int16_t max_chars_to_read, + u_int16_t * bytes_read); + u_int64_t ndpi_bytestream_to_number64(const u_int8_t * str, u_int16_t max_chars_to_read, + u_int16_t * bytes_read); + u_int32_t ndpi_bytestream_dec_or_hex_to_number(const u_int8_t * str, + u_int16_t max_chars_to_read, + u_int16_t * bytes_read); + u_int64_t ndpi_bytestream_dec_or_hex_to_number64(const u_int8_t * str, + u_int16_t max_chars_to_read, + u_int16_t * bytes_read); + u_int32_t ndpi_bytestream_to_ipv4(const u_int8_t * str, u_int16_t max_chars_to_read, + u_int16_t * bytes_read); void ndpi_set_detected_protocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol); - extern void ndpi_parse_packet_line_info(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); - extern void ndpi_parse_packet_line_info_any(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); + extern void ndpi_parse_packet_line_info(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow); + extern void ndpi_parse_packet_line_info_any(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow); - extern u_int16_t ndpi_check_for_email_address(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, u_int16_t counter); + extern u_int16_t ndpi_check_for_email_address(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, u_int16_t counter); - extern void ndpi_int_change_packet_protocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, + extern void ndpi_int_change_packet_protocol(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol); - extern void ndpi_int_change_protocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, + extern void ndpi_int_change_protocol(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol); - extern void ndpi_set_proto_defaults(struct ndpi_detection_module_struct *ndpi_mod, ndpi_protocol_breed_t protoBreed, u_int16_t protoId, - u_int16_t tcp_alias_protoId[2], u_int16_t udp_alias_protoId[2], char *protoName, + extern void ndpi_int_change_category(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + ndpi_protocol_category_t protocol_category); + + extern void ndpi_set_proto_defaults(struct ndpi_detection_module_struct *ndpi_mod, + ndpi_protocol_breed_t protoBreed, u_int16_t protoId, + u_int16_t tcp_alias_protoId[2], + u_int16_t udp_alias_protoId[2], char *protoName, ndpi_protocol_category_t protoCategory, - ndpi_port_range *tcpDefPorts, ndpi_port_range *udpDefPorts); + ndpi_port_range *tcpDefPorts, + ndpi_port_range *udpDefPorts); extern void ndpi_int_reset_packet_protocol(struct ndpi_packet_struct *packet); extern void ndpi_int_reset_protocol(struct ndpi_flow_struct *flow); @@ -90,8 +111,10 @@ extern "C" { extern void ndpi_packet_src_ip_get(const struct ndpi_packet_struct *packet, ndpi_ip_addr_t * ip); extern void ndpi_packet_dst_ip_get(const struct ndpi_packet_struct *packet, ndpi_ip_addr_t * ip); - extern char *ndpi_get_ip_string(struct ndpi_detection_module_struct *ndpi_struct, const ndpi_ip_addr_t * ip); - extern char *ndpi_get_packet_src_ip_string(struct ndpi_detection_module_struct *ndpi_struct, const struct ndpi_packet_struct *packet); + extern char *ndpi_get_ip_string(struct ndpi_detection_module_struct *ndpi_struct, + const ndpi_ip_addr_t * ip); + extern char *ndpi_get_packet_src_ip_string(struct ndpi_detection_module_struct *ndpi_struct, + const struct ndpi_packet_struct *packet); extern char* ndpi_get_proto_by_id(struct ndpi_detection_module_struct *ndpi_mod, u_int id); u_int16_t ndpi_get_proto_by_name(struct ndpi_detection_module_struct *ndpi_mod, const char *name); @@ -102,7 +125,8 @@ extern "C" { extern u_int8_t ndpi_is_proto(ndpi_protocol p, u_int16_t proto); extern u_int16_t ndpi_get_lower_proto(ndpi_protocol p); - extern int ndpi_get_protocol_id_master_proto(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t protocol_id, + extern int ndpi_get_protocol_id_master_proto(struct ndpi_detection_module_struct *ndpi_struct, + u_int16_t protocol_id, u_int16_t** tcp_master_proto, u_int16_t** udp_master_proto); #/* NDPI_PROTOCOL_NETBIOS */ diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 244074044..3d0eccab7 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1099,8 +1099,9 @@ struct ndpi_flow_struct { /* protocols which have marked a connection as this connection cannot be protocol XXX, multiple u_int64_t */ NDPI_PROTOCOL_BITMASK excluded_protocol_bitmask; - + ndpi_protocol_category_t category; + /* NDPI_PROTOCOL_REDIS */ u_int8_t redis_s2d_first_char, redis_d2s_first_char; @@ -1207,4 +1208,10 @@ typedef struct { u_int8_t value; } ndpi_network; +typedef struct { + int protocol_id; + ndpi_protocol_category_t protocol_category; + ndpi_protocol_breed_t protocol_breed; +} ndpi_protocol_match_result; + #endif /* __NDPI_TYPEDEFS_H__ */ diff --git a/src/lib/Makefile b/src/lib/Makefile index c9f317931..19c6f1cfe 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -6,7 +6,7 @@ # make -f Makefile.simple # CFLAGS += -fPIC -DPIC -I../include -Ithird_party/include -DNDPI_LIB_COMPILATION -g -RANLIB=ranlib +RANLIB = ranlib OBJECTS = $(patsubst protocols/%.c, protocols/%.o, $(wildcard protocols/*.c)) $(patsubst third_party/src/%.c, third_party/src/%.o, $(wildcard third_party/src/*.c)) ndpi_main.o HEADERS = $(wildcard ../include/*.h) diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 494c93bd0..952026ce6 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -413,15 +413,13 @@ u_int32_t ndpi_detection_get_sizeof_ndpi_id_struct(void) { return sizeof(struct /* *********************************************************************************** */ -char * ndpi_get_proto_by_id(struct ndpi_detection_module_struct *ndpi_mod, u_int id) -{ +char * ndpi_get_proto_by_id(struct ndpi_detection_module_struct *ndpi_mod, u_int id) { return((id >= ndpi_mod->ndpi_num_supported_protocols) ? NULL : ndpi_mod->proto_defaults[id].protoName); } /* *********************************************************************************** */ -u_int16_t ndpi_get_proto_by_name(struct ndpi_detection_module_struct *ndpi_mod, const char *name) -{ +u_int16_t ndpi_get_proto_by_name(struct ndpi_detection_module_struct *ndpi_mod, const char *name) { u_int16_t i, num = ndpi_get_num_supported_protocols(ndpi_mod); for(i = 0; i < num; i++) @@ -438,8 +436,7 @@ ndpi_port_range * ndpi_build_default_ports_range(ndpi_port_range *ports, u_int16_t portB_low, u_int16_t portB_high, u_int16_t portC_low, u_int16_t portC_high, u_int16_t portD_low, u_int16_t portD_high, - u_int16_t portE_low, u_int16_t portE_high) -{ + u_int16_t portE_low, u_int16_t portE_high) { int i = 0; ports[i].port_low = portA_low, ports[i].port_high = portA_high; i++; @@ -458,8 +455,7 @@ ndpi_port_range * ndpi_build_default_ports(ndpi_port_range *ports, u_int16_t portB, u_int16_t portC, u_int16_t portD, - u_int16_t portE) -{ + u_int16_t portE) { int i = 0; ports[i].port_low = portA, ports[i].port_high = portA; i++; @@ -753,8 +749,7 @@ static int ndpi_remove_host_url_subprotocol(struct ndpi_detection_module_struct /* ******************************************************************** */ void ndpi_init_protocol_match(struct ndpi_detection_module_struct *ndpi_mod, - ndpi_protocol_match *match) -{ + ndpi_protocol_match *match) { u_int16_t no_master[2] = { NDPI_PROTOCOL_NO_MASTER_PROTO, NDPI_PROTOCOL_NO_MASTER_PROTO }; ndpi_port_range ports_a[MAX_DEFAULT_PORTS], ports_b[MAX_DEFAULT_PORTS]; static u_int16_t generic_id = NDPI_LAST_IMPLEMENTED_PROTOCOL; @@ -2634,7 +2629,7 @@ int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_mod, else removeDefaultPort(&range, def, is_tcp ? &ndpi_mod->tcpRoot : &ndpi_mod->udpRoot); } else if(is_ip) { -/* NDPI_PROTOCOL_TOR */ + /* NDPI_PROTOCOL_TOR */ ndpi_add_host_ip_subprotocol(ndpi_mod, value, subprotocol_id); } else { if(do_add) @@ -4172,6 +4167,11 @@ int ndpi_enable_loaded_categories(struct ndpi_detection_module_struct *ndpi_str) void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, ndpi_protocol *ret) { + if(flow->category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) { + ret->category = flow->category; + return; + } + if(ndpi_struct->custom_categories.categories_loaded) { if(flow->packet.iph) { prefix_t prefix; @@ -4189,7 +4189,7 @@ void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_struc } if(node) { - ret->category = (ndpi_protocol_category_t)node->value.user_value; + flow->category = ret->category = (ndpi_protocol_category_t)node->value.user_value; return; } } @@ -4199,7 +4199,7 @@ void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_struc int rc = ndpi_match_custom_category(ndpi_struct, (char *)flow->host_server_name, &id); if(rc == 0) { - ret->category = (ndpi_protocol_category_t)id; + flow->category = ret->category = (ndpi_protocol_category_t)id; return; } } @@ -4209,13 +4209,13 @@ void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_struc int rc = ndpi_match_custom_category(ndpi_struct, (char *)flow->protos.stun_ssl.ssl.server_certificate, &id); if(rc == 0) { - ret->category = (ndpi_protocol_category_t)id; + flow->category = ret->category = (ndpi_protocol_category_t)id; return; } } } - ret->category = ndpi_get_proto_category(ndpi_struct, *ret); + flow->category = ret->category = ndpi_get_proto_category(ndpi_struct, *ret); } /* ********************************************************************************* */ @@ -4347,6 +4347,19 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct if(flow->guessed_host_protocol_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS-1)) { /* This is a custom protocol and it has priority over everything else */ ret.master_protocol = NDPI_PROTOCOL_UNKNOWN, ret.app_protocol = flow->guessed_host_protocol_id; + + if(flow->packet.tcp) { + /* Minimal guess for HTTP/SSL-based protocols */ + switch(ntohs(flow->packet.tcp->dest)) { + case 80: + ret.master_protocol = NDPI_PROTOCOL_HTTP; + break; + case 443: + ret.master_protocol = NDPI_PROTOCOL_SSL; /* QUIC could also match */ + break; + } + } + ndpi_check_flow_func(ndpi_struct, flow, &ndpi_selection_packet); ndpi_fill_protocol_category(ndpi_struct, flow, &ret); return(ret); @@ -4921,10 +4934,11 @@ void ndpi_debug_get_last_log_function_line(struct ndpi_detection_module_struct /* ********************************************************************************* */ -u_int8_t ndpi_detection_get_l4(const u_int8_t * l3, u_int16_t l3_len, const u_int8_t ** l4_return, u_int16_t * l4_len_return, - u_int8_t * l4_protocol_return, u_int32_t flags) -{ - return ndpi_detection_get_l4_internal(NULL, l3, l3_len, l4_return, l4_len_return, l4_protocol_return, flags); +u_int8_t ndpi_detection_get_l4(const u_int8_t * l3, u_int16_t l3_len, + const u_int8_t ** l4_return, u_int16_t * l4_len_return, + u_int8_t * l4_protocol_return, u_int32_t flags) { + return ndpi_detection_get_l4_internal(NULL, l3, l3_len, + l4_return, l4_len_return, l4_protocol_return, flags); } /* ********************************************************************************* */ @@ -4932,8 +4946,7 @@ u_int8_t ndpi_detection_get_l4(const u_int8_t * l3, u_int16_t l3_len, const u_in void ndpi_set_detected_protocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, u_int16_t upper_detected_protocol, - u_int16_t lower_detected_protocol) -{ + u_int16_t lower_detected_protocol) { struct ndpi_id_struct *src = flow->src; struct ndpi_id_struct *dst = flow->dst; @@ -4969,7 +4982,8 @@ void ndpi_int_change_flow_protocol(struct ndpi_detection_module_struct *ndpi_str u_int16_t lower_detected_protocol) { if(!flow) return; - flow->detected_protocol_stack[0] = upper_detected_protocol, flow->detected_protocol_stack[1] = lower_detected_protocol; + flow->detected_protocol_stack[0] = upper_detected_protocol, + flow->detected_protocol_stack[1] = lower_detected_protocol; } /* ********************************************************************************* */ @@ -5018,6 +5032,14 @@ void ndpi_int_change_protocol(struct ndpi_detection_module_struct *ndpi_struct, /* ********************************************************************************* */ +void ndpi_int_change_category(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + ndpi_protocol_category_t protocol_category) { + flow->category = protocol_category; +} + +/* ********************************************************************************* */ + /* change protocol only if guessing is active */ /* void ndpi_guess_change_protocol(struct ndpi_detection_module_struct *ndpi_struct, */ /* struct ndpi_flow_struct *flow) */ @@ -5600,22 +5622,29 @@ int ndpi_match_prefix(const u_int8_t *payload, size_t payload_len, int ndpi_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_struct, char *string_to_match, u_int string_to_match_len, + ndpi_protocol_match_result *ret_match, u_int8_t is_host_match) { - AC_REP_t match = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED }; AC_TEXT_t ac_input_text; - ndpi_automa *automa = is_host_match ? &ndpi_struct->host_automa : &ndpi_struct->content_automa; - - if((automa->ac_automa == NULL) || (string_to_match_len == 0)) return(NDPI_PROTOCOL_UNKNOWN); + ndpi_automa *automa = is_host_match ? &ndpi_struct->host_automa : + &ndpi_struct->content_automa; + AC_REP_t match = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED }; + + if((automa->ac_automa == NULL) || (string_to_match_len == 0)) + return(NDPI_PROTOCOL_UNKNOWN); if(!automa->ac_automa_finalized) { ac_automata_finalize((AC_AUTOMATA_t*)automa->ac_automa); automa->ac_automa_finalized = 1; } - + ac_input_text.astring = string_to_match, ac_input_text.length = string_to_match_len; ac_automata_search(((AC_AUTOMATA_t*)automa->ac_automa), &ac_input_text, &match); ac_automata_reset(((AC_AUTOMATA_t*)automa->ac_automa)); - + + ret_match->protocol_id = match.number, + ret_match->protocol_category = match.category, + ret_match->protocol_breed = match.breed; + return(match.number); } @@ -5627,10 +5656,15 @@ static int ndpi_automa_match_string_subprotocol(struct ndpi_detection_module_str struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, u_int16_t master_protocol_id, + ndpi_protocol_match_result *ret_match, u_int8_t is_host_match) { - int matching_protocol_id = ndpi_match_string_subprotocol(ndpi_struct, string_to_match, string_to_match_len, is_host_match); + int matching_protocol_id; struct ndpi_packet_struct *packet = &flow->packet; + matching_protocol_id = ndpi_match_string_subprotocol(ndpi_struct, string_to_match, + string_to_match_len, ret_match, + is_host_match); + #ifdef DEBUG { char m[256]; @@ -5650,8 +5684,9 @@ static int ndpi_automa_match_string_subprotocol(struct ndpi_detection_module_str packet->detected_protocol_stack[0] = matching_protocol_id; flow->detected_protocol_stack[0] = packet->detected_protocol_stack[0], - flow->detected_protocol_stack[1] = packet->detected_protocol_stack[1]; - + flow->detected_protocol_stack[1] = packet->detected_protocol_stack[1], + flow->category = ret_match->protocol_category; + return(packet->detected_protocol_stack[0]); } @@ -5679,10 +5714,15 @@ static int ndpi_automa_match_string_subprotocol(struct ndpi_detection_module_str struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, u_int16_t master_protocol_id, + ndpi_automa_match_string_subprotocol *ret_match, u_int8_t is_host_match) { int rv = NDPI_PROTOCOL_UNKNOWN; struct hs *hs = (struct hs*)ndpi_struct->hyperscan; + /* + TODO HYPERSCAN + In case of match fill up ret_match and set flow protocol + category + */ if(hs_scan(hs->database, string_to_match, string_to_match_len, 0, hs->scratch, hyperscanEventHandler, &rv) != HS_SUCCESS) @@ -5698,10 +5738,11 @@ static int ndpi_automa_match_string_subprotocol(struct ndpi_detection_module_str int ndpi_match_host_subprotocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, + ndpi_protocol_match_result *ret_match, u_int16_t master_protocol_id) { return(ndpi_automa_match_string_subprotocol(ndpi_struct, flow, string_to_match, string_to_match_len, - master_protocol_id, 1)); + master_protocol_id, ret_match, 1)); } /* ****************************************************** */ @@ -5709,10 +5750,11 @@ int ndpi_match_host_subprotocol(struct ndpi_detection_module_struct *ndpi_struct int ndpi_match_content_subprotocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, + ndpi_protocol_match_result *ret_match, u_int16_t master_protocol_id) { return(ndpi_automa_match_string_subprotocol(ndpi_struct, flow, string_to_match, string_to_match_len, - master_protocol_id, 0)); + master_protocol_id, ret_match, 0)); } /* ****************************************************** */ diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c index 6ffa74a27..90be9544c 100644 --- a/src/lib/protocols/dns.c +++ b/src/lib/protocols/dns.c @@ -207,12 +207,16 @@ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct nd flow->protos.dns.num_queries = (u_int8_t)dns_header.num_queries, flow->protos.dns.num_answers = (u_int8_t) (dns_header.num_answers + dns_header.authority_rrs + dns_header.additional_rrs); - if(j > 0) + if(j > 0) { + ndpi_protocol_match_result ret_match; + ndpi_match_host_subprotocol(ndpi_struct, flow, (char *)flow->host_server_name, strlen((const char*)flow->host_server_name), + &ret_match, NDPI_PROTOCOL_DNS); - + } + #ifdef DNS_DEBUG NDPI_LOG_DBG2(ndpi_struct, "[num_queries=%d][num_answers=%d][reply_code=%u][rsp_type=%u][host_server_name=%s]\n", flow->protos.dns.num_queries, flow->protos.dns.num_answers, diff --git a/src/lib/protocols/fbzero.c b/src/lib/protocols/fbzero.c index 3048bff79..6c818e3c7 100644 --- a/src/lib/protocols/fbzero.c +++ b/src/lib/protocols/fbzero.c @@ -84,7 +84,8 @@ void ndpi_search_fbzero(struct ndpi_detection_module_struct *ndpi_struct, && (t->tag[2] == 'I') && (t->tag[3] == '\0')) { char *value = (char*)&packet->payload[data_offset + data_prev_offset]; u_int tag_len = t->tag_offset_len-data_prev_offset, max_len; - + ndpi_protocol_match_result ret_match; + max_len = ndpi_min(tag_len, sizeof(flow->host_server_name)-1); strncpy((char*)flow->host_server_name, value, max_len); @@ -99,6 +100,7 @@ void ndpi_search_fbzero(struct ndpi_detection_module_struct *ndpi_struct, ndpi_match_host_subprotocol(ndpi_struct, flow, (char *)flow->host_server_name, strlen((const char *)flow->host_server_name), + &ret_match, NDPI_PROTOCOL_FBZERO); return; } diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c index e03b48710..94d918e76 100644 --- a/src/lib/protocols/http.c +++ b/src/lib/protocols/http.c @@ -172,7 +172,8 @@ static void setHttpUserAgent(struct ndpi_detection_module_struct *ndpi_struct, static void parseHttpSubprotocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { if((flow->l4.tcp.http_stage == 0) || (flow->http.url && flow->http_detected)) { char *double_col = strchr((char*)flow->host_server_name, ':'); - + ndpi_protocol_match_result ret_match; + if(double_col) double_col[0] = '\0'; /** @@ -182,6 +183,7 @@ static void parseHttpSubprotocol(struct ndpi_detection_module_struct *ndpi_struc */ ndpi_match_host_subprotocol(ndpi_struct, flow, (char *)flow->host_server_name, strlen((const char *)flow->host_server_name), + &ret_match, NDPI_PROTOCOL_HTTP); } } @@ -349,12 +351,16 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ packet->host_line.len, packet->host_line.ptr); /* call ndpi_match_host_subprotocol to see if there is a match with known-host HTTP subprotocol */ - if((ndpi_struct->http_dont_dissect_response) || flow->http_detected) + if((ndpi_struct->http_dont_dissect_response) || flow->http_detected) { + ndpi_protocol_match_result ret_match; + ndpi_match_host_subprotocol(ndpi_struct, flow, (char*)packet->host_line.ptr, packet->host_line.len, + &ret_match, NDPI_PROTOCOL_HTTP); - + } + /* Copy result for nDPI apps */ if(!ndpi_struct->disable_metadata_export) { len = ndpi_min(packet->host_line.len, sizeof(flow->host_server_name)-1); @@ -395,12 +401,16 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) && ((ndpi_struct->http_dont_dissect_response) || flow->http_detected) - && (packet->http_origin.len > 0)) + && (packet->http_origin.len > 0)) { + ndpi_protocol_match_result ret_match; + ndpi_match_host_subprotocol(ndpi_struct, flow, (char *)packet->http_origin.ptr, packet->http_origin.len, + &ret_match, NDPI_PROTOCOL_HTTP); - + } + if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) { if(packet->detected_protocol_stack[0] != NDPI_PROTOCOL_HTTP) { NDPI_LOG_INFO(ndpi_struct, "found HTTP/%s\n", @@ -440,10 +450,13 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ NDPI_LOG_DBG2(ndpi_struct, "Content Type line found %.*s\n", packet->content_line.len, packet->content_line.ptr); - if((ndpi_struct->http_dont_dissect_response) || flow->http_detected) + if((ndpi_struct->http_dont_dissect_response) || flow->http_detected) { + ndpi_protocol_match_result ret_match; + ndpi_match_content_subprotocol(ndpi_struct, flow, (char*)packet->content_line.ptr, packet->content_line.len, - NDPI_PROTOCOL_HTTP); + &ret_match, NDPI_PROTOCOL_HTTP); + } } } diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c index 4c838f41f..e28db634a 100644 --- a/src/lib/protocols/quic.c +++ b/src/lib/protocols/quic.c @@ -107,6 +107,7 @@ void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct, if((sni_offset+len) < udp_len) { if(!ndpi_struct->disable_metadata_export) { int max_len = sizeof(flow->host_server_name)-1, j = 0; + ndpi_protocol_match_result ret_match; if(len > max_len) len = max_len; @@ -118,6 +119,7 @@ void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct, ndpi_match_host_subprotocol(ndpi_struct, flow, (char *)flow->host_server_name, strlen((const char*)flow->host_server_name), + &ret_match, NDPI_PROTOCOL_QUIC); } } diff --git a/src/lib/protocols/ssl.c b/src/lib/protocols/ssl.c index a277f8120..b8c36976b 100644 --- a/src/lib/protocols/ssl.c +++ b/src/lib/protocols/ssl.c @@ -327,13 +327,13 @@ int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi } /* Client hello, Server Hello, and certificate packets probably all checked in this case */ if ((packet->ssl_certificate_num_checks >= 3) - && (flow->l4.tcp.seen_syn) - && (flow->l4.tcp.seen_syn_ack) - && (flow->l4.tcp.seen_ack) /* We have seen the 3-way handshake */) - { - /* We're done processing extra packets since we've probably checked all possible cert packets */ - return 0; - } + && (flow->l4.tcp.seen_syn) + && (flow->l4.tcp.seen_syn_ack) + && (flow->l4.tcp.seen_ack) /* We have seen the 3-way handshake */) + { + /* We're done processing extra packets since we've probably checked all possible cert packets */ + return 0; + } } /* 1 means keep looking for more packets */ return 1; @@ -368,22 +368,27 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s #ifdef CERTIFICATE_DEBUG NDPI_LOG_DBG2(ndpi_struct, "***** [SSL] %s\n", certificate); #endif + ndpi_protocol_match_result ret_match; u_int32_t subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, certificate, - strlen(certificate), NDPI_PROTOCOL_SSL); + strlen(certificate), + &ret_match, + NDPI_PROTOCOL_SSL); + if(subproto != NDPI_PROTOCOL_UNKNOWN) { - /* If we've detected the subprotocol from client certificate but haven't had a chance - * to see the server certificate yet, set up extra packet processing to wait - * a few more packets. */ - if((flow->protos.stun_ssl.ssl.client_certificate[0] != '\0') && (flow->protos.stun_ssl.ssl.server_certificate[0] == '\0')) { - sslInitExtraPacketProcessing(0, flow); - } - ndpi_set_detected_protocol(ndpi_struct, flow, subproto, - ndpi_ssl_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSL)); - return(rc); /* Fix courtesy of Gianluca Costa */ - } + /* If we've detected the subprotocol from client certificate but haven't had a chance + * to see the server certificate yet, set up extra packet processing to wait + * a few more packets. */ + if((flow->protos.stun_ssl.ssl.client_certificate[0] != '\0') && (flow->protos.stun_ssl.ssl.server_certificate[0] == '\0')) { + sslInitExtraPacketProcessing(0, flow); + } + + ndpi_set_detected_protocol(ndpi_struct, flow, subproto, + ndpi_ssl_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSL)); + return(rc); /* Fix courtesy of Gianluca Costa */ + } - if(ndpi_is_ssl_tor(ndpi_struct, flow, certificate) != 0) - return(rc); + if(ndpi_is_ssl_tor(ndpi_struct, flow, certificate) != 0) + return(rc); } if(((packet->ssl_certificate_num_checks >= 2) @@ -394,9 +399,9 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s /* || (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0') */ ) { ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL); - } + } + } } - } return(0); } @@ -480,7 +485,7 @@ static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL_NO_CERT); } else NDPI_LOG_INFO(ndpi_struct, "found ssl\n"); - ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL); + ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL); } } @@ -516,16 +521,16 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct u_int32_t cert_start; NDPI_LOG_DBG2(ndpi_struct, - "maybe SSLv3 server hello split into smaller packets\n"); + "maybe SSLv3 server hello split into smaller packets\n"); /* lets hope at least the server hello and the start of the certificate block are in the first packet */ cert_start = ntohs(get_u_int16_t(packet->payload, 7)) + 5 + 4; NDPI_LOG_DBG2(ndpi_struct, "suspected start of certificate: %u\n", - cert_start); + cert_start); if(cert_start < packet->payload_packet_len && packet->payload[cert_start] == 0x0b) { NDPI_LOG_DBG2(ndpi_struct, - "found 0x0b at suspected start of certificate block\n"); + "found 0x0b at suspected start of certificate block\n"); return 2; } } @@ -536,16 +541,16 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct u_int32_t cert_start; NDPI_LOG_DBG2(ndpi_struct, - "maybe SSLv3 server hello split into smaller packets but with seperate record for the certificate\n"); + "maybe SSLv3 server hello split into smaller packets but with seperate record for the certificate\n"); /* lets hope at least the server hello record and the start of the certificate record are in the first packet */ cert_start = ntohs(get_u_int16_t(packet->payload, 7)) + 5 + 5 + 4; NDPI_LOG_DBG2(ndpi_struct, "suspected start of certificate: %u\n", - cert_start); + cert_start); if(cert_start < packet->payload_packet_len && packet->payload[cert_start] == 0x0b) { NDPI_LOG_DBG2(ndpi_struct, - "found 0x0b at suspected start of certificate block\n"); + "found 0x0b at suspected start of certificate block\n"); return 2; } } @@ -603,7 +608,7 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc * so go on checking for certificate patterns for a couple more packets */ NDPI_LOG_DBG2(ndpi_struct, - "ssl flow but check another packet for patterns\n"); + "ssl flow but check another packet for patterns\n"); ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) { /* still ssl so check another packet */ @@ -685,7 +690,7 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc return; } else if(ret == 2) { NDPI_LOG_DBG2(ndpi_struct, - "sslv3 server len match with split packet -> check some more packets for SSL patterns\n"); + "sslv3 server len match with split packet -> check some more packets for SSL patterns\n"); ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) { flow->l4.tcp.ssl_stage = 3; diff --git a/tests/result/pps.pcap.out b/tests/result/pps.pcap.out index 5b3c3e7ce..a8259c514 100644 --- a/tests/result/pps.pcap.out +++ b/tests/result/pps.pcap.out @@ -23,11 +23,11 @@ GenericProtocol 1429 1780307 49 16 TCP 192.168.115.8:50779 <-> 111.206.22.77:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][2 pkts/1438 bytes <-> 1 pkts/194 bytes][Host: msg.iqiyi.com] 17 UDP 192.168.5.38:58897 -> 239.255.255.250:1900 [proto: 12/SSDP][cat: System/18][9 pkts/1575 bytes -> 0 pkts/0 bytes] 18 UDP 192.168.115.1:50945 -> 239.255.255.250:1900 [proto: 12/SSDP][cat: System/18][9 pkts/1539 bytes -> 0 pkts/0 bytes] - 19 TCP 192.168.115.8:50464 <-> 123.125.112.49:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][1 pkts/707 bytes <-> 1 pkts/744 bytes][Host: click.hm.baidu.com] + 19 TCP 192.168.115.8:50464 <-> 123.125.112.49:80 [proto: 7.137/HTTP.GenericProtocol][cat: Web/5][1 pkts/707 bytes <-> 1 pkts/744 bytes][Host: click.hm.baidu.com] 20 TCP 192.168.115.8:50492 <-> 111.206.13.3:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][1 pkts/389 bytes <-> 2 pkts/1034 bytes][Host: pdata.video.qiyi.com] 21 TCP 192.168.115.8:50777 <-> 111.206.22.77:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][1 pkts/1186 bytes <-> 1 pkts/194 bytes][Host: msg.iqiyi.com] 22 TCP 192.168.115.8:50494 <-> 223.26.106.66:80 [proto: 7.60/HTTP.HTTP_Download][cat: Download-FileTransfer-FileSharing/7][2 pkts/887 bytes <-> 1 pkts/443 bytes][Host: 223.26.106.66] - 23 TCP 192.168.115.8:50497 <-> 123.125.112.49:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][1 pkts/1004 bytes <-> 2 pkts/301 bytes][Host: click.hm.baidu.com] + 23 TCP 192.168.115.8:50497 <-> 123.125.112.49:80 [proto: 7.137/HTTP.GenericProtocol][cat: Web/5][1 pkts/1004 bytes <-> 2 pkts/301 bytes][Host: click.hm.baidu.com] 24 TCP 192.168.115.8:50499 <-> 111.206.22.76:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][1 pkts/1097 bytes <-> 1 pkts/199 bytes][Host: msg.iqiyi.com] 25 TCP 192.168.115.8:50474 <-> 202.108.14.221:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][1 pkts/1100 bytes <-> 1 pkts/194 bytes][Host: msg.iqiyi.com] 26 TCP 192.168.115.8:50507 <-> 223.26.106.19:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][1 pkts/212 bytes <-> 1 pkts/1063 bytes][Host: static.qiyi.com] diff --git a/tests/result/webex.pcap.out b/tests/result/webex.pcap.out index fbf341918..ecd0f6432 100644 --- a/tests/result/webex.pcap.out +++ b/tests/result/webex.pcap.out @@ -6,36 +6,36 @@ Google 17 6375 1 Webex 1380 818407 43 Amazon 3 174 1 - 1 TCP 10.8.0.1:51155 <-> 62.109.224.120:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][256 pkts/14707 bytes <-> 257 pkts/329379 bytes][server: *.webex.com] - 2 TCP 10.8.0.1:41348 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][28 pkts/4815 bytes <-> 28 pkts/104881 bytes][client: radcom.webex.com] - 3 TCP 10.8.0.1:41346 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][48 pkts/11540 bytes <-> 47 pkts/80696 bytes][client: radcom.webex.com][server: *.webex.com] - 4 TCP 10.8.0.1:41358 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][19 pkts/2005 bytes <-> 19 pkts/40477 bytes][server: *.webex.com] - 5 TCP 10.8.0.1:51194 <-> 62.109.224.120:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][12 pkts/1531 bytes <-> 12 pkts/34357 bytes][server: *.webex.com] - 6 TCP 10.8.0.1:41354 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][13 pkts/2145 bytes <-> 13 pkts/24239 bytes][server: *.webex.com] - 7 TCP 10.8.0.1:51154 <-> 62.109.224.120:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][55 pkts/12583 bytes <-> 50 pkts/6703 bytes][server: *.webex.com] + 1 TCP 10.8.0.1:51155 <-> 62.109.224.120:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][256 pkts/14707 bytes <-> 257 pkts/329379 bytes][server: *.webex.com] + 2 TCP 10.8.0.1:41348 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][28 pkts/4815 bytes <-> 28 pkts/104881 bytes][client: radcom.webex.com] + 3 TCP 10.8.0.1:41346 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][48 pkts/11540 bytes <-> 47 pkts/80696 bytes][client: radcom.webex.com][server: *.webex.com] + 4 TCP 10.8.0.1:41358 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][19 pkts/2005 bytes <-> 19 pkts/40477 bytes][server: *.webex.com] + 5 TCP 10.8.0.1:51194 <-> 62.109.224.120:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][12 pkts/1531 bytes <-> 12 pkts/34357 bytes][server: *.webex.com] + 6 TCP 10.8.0.1:41354 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][13 pkts/2145 bytes <-> 13 pkts/24239 bytes][server: *.webex.com] + 7 TCP 10.8.0.1:51154 <-> 62.109.224.120:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][55 pkts/12583 bytes <-> 50 pkts/6703 bytes][server: *.webex.com] 8 UDP 10.8.0.1:64538 -> 172.16.1.75:5060 [proto: 100/SIP][cat: VoIP/10][22 pkts/15356 bytes -> 0 pkts/0 bytes] - 9 TCP 10.8.0.1:51857 <-> 62.109.229.158:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][29 pkts/4559 bytes <-> 21 pkts/5801 bytes][server: *.webex.com] + 9 TCP 10.8.0.1:51857 <-> 62.109.229.158:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][29 pkts/4559 bytes <-> 21 pkts/5801 bytes][server: *.webex.com] 10 TCP 10.8.0.1:46211 <-> 54.241.32.14:443 [proto: 91/SSL][cat: Web/5][16 pkts/1984 bytes <-> 14 pkts/7584 bytes][client: api.crittercism.com][server: *.crittercism.com] - 11 TCP 10.8.0.1:41386 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][9 pkts/1417 bytes <-> 8 pkts/6984 bytes][server: *.webex.com] - 12 TCP 10.8.0.1:41419 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][7 pkts/1309 bytes <-> 7 pkts/6930 bytes][server: *.webex.com] - 13 TCP 10.8.0.1:52730 <-> 173.243.4.76:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][9 pkts/1369 bytes <-> 8 pkts/6621 bytes][server: *.webex.com] - 14 TCP 10.8.0.1:44492 <-> 64.68.104.140:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][9 pkts/1369 bytes <-> 8 pkts/6600 bytes][server: *.webex.com] - 15 TCP 10.8.0.1:45814 <-> 62.109.231.3:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][8 pkts/1315 bytes <-> 8 pkts/6653 bytes][server: *.webex.com] - 16 TCP 10.8.0.1:47498 <-> 209.197.222.159:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][7 pkts/1261 bytes <-> 7 pkts/6535 bytes][server: *.webex.com] - 17 TCP 10.8.0.1:57647 <-> 64.68.121.153:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][7 pkts/1261 bytes <-> 7 pkts/6535 bytes][server: *.webex.com] - 18 TCP 10.8.0.1:37129 <-> 64.68.105.98:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][9 pkts/1369 bytes <-> 9 pkts/5838 bytes][server: *.webex.com] - 19 TCP 10.8.0.1:51370 <-> 64.68.105.97:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][8 pkts/1315 bytes <-> 8 pkts/5784 bytes][server: *.webex.com] - 20 TCP 10.8.0.1:55669 <-> 173.243.0.110:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][11 pkts/1830 bytes <-> 12 pkts/4811 bytes][server: *.webex.com] - 21 TCP 10.8.0.1:55665 <-> 173.243.0.110:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][11 pkts/1798 bytes <-> 11 pkts/4757 bytes][server: *.webex.com] - 22 TCP 10.8.0.1:55671 <-> 173.243.0.110:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][11 pkts/1798 bytes <-> 11 pkts/4757 bytes][server: *.webex.com] - 23 TCP 10.8.0.1:55687 <-> 173.243.0.110:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][11 pkts/1798 bytes <-> 11 pkts/4757 bytes][server: *.webex.com] + 11 TCP 10.8.0.1:41386 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][9 pkts/1417 bytes <-> 8 pkts/6984 bytes][server: *.webex.com] + 12 TCP 10.8.0.1:41419 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][7 pkts/1309 bytes <-> 7 pkts/6930 bytes][server: *.webex.com] + 13 TCP 10.8.0.1:52730 <-> 173.243.4.76:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][9 pkts/1369 bytes <-> 8 pkts/6621 bytes][server: *.webex.com] + 14 TCP 10.8.0.1:44492 <-> 64.68.104.140:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][9 pkts/1369 bytes <-> 8 pkts/6600 bytes][server: *.webex.com] + 15 TCP 10.8.0.1:45814 <-> 62.109.231.3:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][8 pkts/1315 bytes <-> 8 pkts/6653 bytes][server: *.webex.com] + 16 TCP 10.8.0.1:47498 <-> 209.197.222.159:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][7 pkts/1261 bytes <-> 7 pkts/6535 bytes][server: *.webex.com] + 17 TCP 10.8.0.1:57647 <-> 64.68.121.153:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][7 pkts/1261 bytes <-> 7 pkts/6535 bytes][server: *.webex.com] + 18 TCP 10.8.0.1:37129 <-> 64.68.105.98:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][9 pkts/1369 bytes <-> 9 pkts/5838 bytes][server: *.webex.com] + 19 TCP 10.8.0.1:51370 <-> 64.68.105.97:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][8 pkts/1315 bytes <-> 8 pkts/5784 bytes][server: *.webex.com] + 20 TCP 10.8.0.1:55669 <-> 173.243.0.110:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][11 pkts/1830 bytes <-> 12 pkts/4811 bytes][server: *.webex.com] + 21 TCP 10.8.0.1:55665 <-> 173.243.0.110:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][11 pkts/1798 bytes <-> 11 pkts/4757 bytes][server: *.webex.com] + 22 TCP 10.8.0.1:55671 <-> 173.243.0.110:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][11 pkts/1798 bytes <-> 11 pkts/4757 bytes][server: *.webex.com] + 23 TCP 10.8.0.1:55687 <-> 173.243.0.110:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][11 pkts/1798 bytes <-> 11 pkts/4757 bytes][server: *.webex.com] 24 TCP 10.8.0.1:43433 <-> 216.58.208.40:443 [proto: 91.126/SSL.Google][cat: Web/5][9 pkts/1540 bytes <-> 8 pkts/4835 bytes][client: ssl.google-analytics.com][server: *.google-analytics.com] - 25 TCP 10.8.0.1:51646 <-> 114.29.204.49:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][9 pkts/895 bytes <-> 8 pkts/4398 bytes][server: *.webex.com] - 26 TCP 10.8.0.1:52219 <-> 64.68.121.100:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][8 pkts/841 bytes <-> 7 pkts/4376 bytes][server: *.webex.com] - 27 TCP 10.8.0.1:55969 <-> 64.68.121.99:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][8 pkts/841 bytes <-> 7 pkts/4376 bytes][server: *.webex.com] - 28 TCP 10.8.0.1:49048 <-> 23.44.253.243:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][7 pkts/1181 bytes <-> 7 pkts/4021 bytes][server: www.webex.com] - 29 TCP 10.8.0.1:47116 <-> 114.29.202.139:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][7 pkts/461 bytes <-> 6 pkts/4231 bytes][server: *.webex.com] - 30 TCP 10.8.0.1:47841 <-> 114.29.200.11:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][6 pkts/407 bytes <-> 5 pkts/4177 bytes][server: *.webex.com] + 25 TCP 10.8.0.1:51646 <-> 114.29.204.49:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][9 pkts/895 bytes <-> 8 pkts/4398 bytes][server: *.webex.com] + 26 TCP 10.8.0.1:52219 <-> 64.68.121.100:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][8 pkts/841 bytes <-> 7 pkts/4376 bytes][server: *.webex.com] + 27 TCP 10.8.0.1:55969 <-> 64.68.121.99:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][8 pkts/841 bytes <-> 7 pkts/4376 bytes][server: *.webex.com] + 28 TCP 10.8.0.1:49048 <-> 23.44.253.243:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][7 pkts/1181 bytes <-> 7 pkts/4021 bytes][server: www.webex.com] + 29 TCP 10.8.0.1:47116 <-> 114.29.202.139:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][7 pkts/461 bytes <-> 6 pkts/4231 bytes][server: *.webex.com] + 30 TCP 10.8.0.1:47841 <-> 114.29.200.11:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][6 pkts/407 bytes <-> 5 pkts/4177 bytes][server: *.webex.com] 31 TCP 10.8.0.1:33551 <-> 80.74.110.68:443 [proto: 64/SSL_No_Cert][cat: Web/5][10 pkts/1465 bytes <-> 11 pkts/1065 bytes] 32 TCP 10.8.0.1:33553 <-> 80.74.110.68:443 [proto: 64/SSL_No_Cert][cat: Web/5][10 pkts/1388 bytes <-> 10 pkts/1087 bytes] 33 TCP 10.8.0.1:33512 <-> 80.74.110.68:443 [proto: 64/SSL_No_Cert][cat: Web/5][9 pkts/1357 bytes <-> 9 pkts/615 bytes] @@ -44,8 +44,8 @@ Amazon 3 174 1 36 TCP 10.8.0.1:33559 <-> 80.74.110.68:443 [proto: 64/SSL_No_Cert][cat: Web/5][7 pkts/1280 bytes <-> 6 pkts/453 bytes] 37 TCP 10.8.0.1:59757 <-> 78.46.237.91:80 [proto: 7/HTTP][cat: Web/5][5 pkts/624 bytes <-> 5 pkts/767 bytes][Host: cp.pushwoosh.com] 38 UDP 10.8.0.1:51772 <-> 62.109.229.158:9000 [proto: 141/Webex][14 pkts/1071 bytes <-> 2 pkts/100 bytes] - 39 TCP 10.8.0.1:41350 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][6 pkts/614 bytes <-> 5 pkts/399 bytes][client: radcom.webex.com] - 40 TCP 10.8.0.1:41351 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: Collaborative/15][5 pkts/560 bytes <-> 4 pkts/345 bytes][client: radcom.webex.com] + 39 TCP 10.8.0.1:41350 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][6 pkts/614 bytes <-> 5 pkts/399 bytes][client: radcom.webex.com] + 40 TCP 10.8.0.1:41351 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][5 pkts/560 bytes <-> 4 pkts/345 bytes][client: radcom.webex.com] 41 TCP 10.8.0.1:51190 <-> 62.109.224.120:443 [proto: 91.141/SSL.Webex][7 pkts/501 bytes <-> 4 pkts/216 bytes] 42 TCP 10.8.0.1:37139 <-> 64.68.105.98:443 [proto: 91.141/SSL.Webex][6 pkts/427 bytes <-> 5 pkts/270 bytes] 43 TCP 10.8.0.1:41394 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][6 pkts/427 bytes <-> 5 pkts/270 bytes] diff --git a/tests/result/whatsappfiles.pcap.out b/tests/result/whatsappfiles.pcap.out index e6e8f0fa7..40d4fa391 100644 --- a/tests/result/whatsappfiles.pcap.out +++ b/tests/result/whatsappfiles.pcap.out @@ -1,4 +1,4 @@ WhatsAppFiles 620 452233 2 - 1 TCP 192.168.2.29:49698 <-> 185.60.216.53:443 [proto: 242/WhatsAppFiles][cat: Download-FileTransfer-FileSharing/7][132 pkts/9906 bytes <-> 178 pkts/237405 bytes] - 2 TCP 192.168.2.29:49674 <-> 185.60.216.53:443 [proto: 242/WhatsAppFiles][cat: Download-FileTransfer-FileSharing/7][161 pkts/189194 bytes <-> 149 pkts/15728 bytes] + 1 TCP 192.168.2.29:49698 <-> 185.60.216.53:443 [proto: 91.242/SSL.WhatsAppFiles][cat: Download-FileTransfer-FileSharing/7][132 pkts/9906 bytes <-> 178 pkts/237405 bytes] + 2 TCP 192.168.2.29:49674 <-> 185.60.216.53:443 [proto: 91.242/SSL.WhatsAppFiles][cat: Download-FileTransfer-FileSharing/7][161 pkts/189194 bytes <-> 149 pkts/15728 bytes] -- cgit v1.2.3 From 92ad05733246738b0fc3bb6b2ddb83605e6babad Mon Sep 17 00:00:00 2001 From: Luca Deri Date: Mon, 17 Dec 2018 22:33:58 +0100 Subject: Added Ookla cache --- src/include/ndpi_protocols.h | 1 + src/include/ndpi_typedefs.h | 5 +- src/lib/ndpi_main.c | 14 +- src/lib/protocols/http.c | 31 ++-- src/lib/protocols/ookla.c | 66 +++++++++ src/lib/protocols/snmp_proto.c | 1 - src/lib/third_party/include/lruc.h | 55 +++++++ src/lib/third_party/src/lruc.c | 294 +++++++++++++++++++++++++++++++++++++ 8 files changed, 452 insertions(+), 15 deletions(-) create mode 100644 src/lib/protocols/ookla.c create mode 100644 src/lib/third_party/include/lruc.h create mode 100644 src/lib/third_party/src/lruc.c (limited to 'src/lib/protocols/http.c') diff --git a/src/include/ndpi_protocols.h b/src/include/ndpi_protocols.h index 8ac7d7247..5349237d4 100644 --- a/src/include/ndpi_protocols.h +++ b/src/include/ndpi_protocols.h @@ -362,4 +362,5 @@ void init_ajp_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int3 void init_fbzero_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask); void init_memcached_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask); void init_nest_log_sink_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask); +void init_ookla_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask); #endif /* __NDPI_PROTOCOLS_H__ */ diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index d48453baf..294af22b3 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -996,7 +996,10 @@ struct ndpi_detection_module_struct { struct bt_announce *bt_ann; int bt_ann_len; -/* NDPI_PROTOCOL_TINC */ + /* NDPI_PROTOCOL_OOKLA */ + void *ookla_cache; + + /* NDPI_PROTOCOL_TINC */ struct cache *tinc_cache; ndpi_proto_defaults_t proto_defaults[NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS]; diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index b5b3c9c6b..e882feaa6 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -30,6 +30,7 @@ #include #include "ahocorasick.h" #include "libcache.h" +#include "lruc.h" #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_UNKNOWN @@ -2427,14 +2428,16 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_struct ndpi_free(ndpi_struct->proto_defaults[i].protoName); } -/* NDPI_PROTOCOL_TINC */ + /* NDPI_PROTOCOL_TINC */ if(ndpi_struct->tinc_cache) cache_free((cache_t)(ndpi_struct->tinc_cache)); - if(ndpi_struct->protocols_ptree) - ndpi_Destroy_Patricia((patricia_tree_t*)ndpi_struct->protocols_ptree, - free_ptree_data); + if(ndpi_struct->ookla_cache) + lruc_free((lruc*)ndpi_struct->ookla_cache); + if(ndpi_struct->protocols_ptree) + ndpi_Destroy_Patricia((patricia_tree_t*)ndpi_struct->protocols_ptree, free_ptree_data); + if(ndpi_struct->udpRoot != NULL) ndpi_tdestroy(ndpi_struct->udpRoot, ndpi_free); if(ndpi_struct->tcpRoot != NULL) @@ -3293,6 +3296,9 @@ void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *n /* WHATSAPP */ init_whatsapp_dissector(ndpi_struct, &a, detection_bitmask); + /* OOKLA */ + init_ookla_dissector(ndpi_struct, &a, detection_bitmask); + /* AMQP */ init_amqp_dissector(ndpi_struct, &a, detection_bitmask); diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c index 94d918e76..09b816129 100644 --- a/src/lib/protocols/http.c +++ b/src/lib/protocols/http.c @@ -26,7 +26,7 @@ #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_HTTP #include "ndpi_api.h" - +#include "lruc.h" /* global variables used for 1kxun protocol and iqiyi service */ @@ -613,7 +613,23 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct */ + ookla_found: ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN); + + if(ndpi_struct->ookla_cache == NULL) + ndpi_struct->ookla_cache = lruc_new(4*1024, 1024); + + if(ndpi_struct->ookla_cache != NULL) { + u_int8_t *dummy = (u_int8_t*)ndpi_malloc(sizeof(u_int8_t)); + + if(dummy) { + if(packet->tcp->source == htons(8080)) + lruc_set((lruc*)ndpi_struct->ookla_cache, (void*)&packet->iph->saddr, 4, dummy, 1); + else + lruc_set((lruc*)ndpi_struct->ookla_cache, (void*)&packet->iph->daddr, 4, dummy, 1); + } + } + return; } @@ -663,9 +679,8 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct /* Check for Ookla */ if((packet->referer_line.len > 0) - && ndpi_strnstr((const char *)packet->referer_line.ptr, "www.speedtest.net", packet->referer_line.len)) { - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_HTTP); - return; + && ndpi_strnstr((const char *)packet->referer_line.ptr, "www.speedtest.net", packet->referer_line.len)) { + goto ookla_found; } /* Check for additional field introduced by Steam */ @@ -782,17 +797,15 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct if((packet->payload_packet_len == 34) && (flow->l4.tcp.http_stage == 1)) { if((packet->payload[5] == ' ') && (packet->payload[9] == ' ')) { - ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA); - return; + goto ookla_found; } } if((packet->payload_packet_len > 6) && memcmp(packet->payload, "HELLO ", 6) == 0) { /* This looks like Ookla */ - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN); - return; + goto ookla_found; } else - NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_OOKLA); + NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_OOKLA); /** At first check, if this is for sure a response packet (in another direction. If not, if HTTP is detected do nothing now and return, diff --git a/src/lib/protocols/ookla.c b/src/lib/protocols/ookla.c new file mode 100644 index 000000000..b1eb295a7 --- /dev/null +++ b/src/lib/protocols/ookla.c @@ -0,0 +1,66 @@ +/* + * ookla.c + * + * Copyright (C) 2018 - ntop.org + * + * nDPI is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nDPI is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with nDPI. If not, see . + * + */ +#include "ndpi_protocol_ids.h" + +#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_OOKLA + +#include "ndpi_api.h" +#include "lruc.h" + + +void ndpi_search_ookla(struct ndpi_detection_module_struct* ndpi_struct, struct ndpi_flow_struct* flow) { + struct ndpi_packet_struct* packet = &flow->packet; + u_int32_t addr = 0; + void *value; + + NDPI_LOG_DBG(ndpi_struct, "Ookla detection\n"); + + if(packet->tcp->source == htons(8080)) + addr = packet->iph->saddr; + else if(packet->tcp->dest == htons(8080)) + addr = packet->iph->daddr; + else + goto ookla_exclude; + + if(ndpi_struct->ookla_cache != NULL) { + if(lruc_get(ndpi_struct->ookla_cache, &addr, sizeof(addr), &value) == LRUC_NO_ERROR) { + /* Don't remove it as it can be used for other connections */ + NDPI_LOG_INFO(ndpi_struct, "found ookla tcp connection\n"); + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN); + return; + } + } + + ookla_exclude: + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); +} + +void init_ookla_dissector(struct ndpi_detection_module_struct *ndpi_struct, + u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { + ndpi_set_bitmask_protocol_detection("Ookla", ndpi_struct, detection_bitmask, *id, + NDPI_PROTOCOL_OOKLA, + ndpi_search_ookla, + NDPI_SELECTION_BITMASK_PROTOCOL_TCP, + SAVE_DETECTION_BITMASK_AS_UNKNOWN, + ADD_TO_DETECTION_BITMASK); + + *id += 1; +} + diff --git a/src/lib/protocols/snmp_proto.c b/src/lib/protocols/snmp_proto.c index 759d6bae0..77ad4d233 100644 --- a/src/lib/protocols/snmp_proto.c +++ b/src/lib/protocols/snmp_proto.c @@ -123,7 +123,6 @@ void ndpi_search_snmp(struct ndpi_detection_module_struct *ndpi_struct, struct n } excl: NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - } diff --git a/src/lib/third_party/include/lruc.h b/src/lib/third_party/include/lruc.h new file mode 100644 index 000000000..55fb271fe --- /dev/null +++ b/src/lib/third_party/include/lruc.h @@ -0,0 +1,55 @@ +#include +#include +#include + +#ifndef __lruc_header__ +#define __lruc_header__ + +// ------------------------------------------ +// errors +// ------------------------------------------ +typedef enum { + LRUC_NO_ERROR = 0, + LRUC_MISSING_CACHE, + LRUC_MISSING_KEY, + LRUC_MISSING_VALUE, + LRUC_PTHREAD_ERROR, + LRUC_VALUE_TOO_LARGE +} lruc_error; + + +// ------------------------------------------ +// types +// ------------------------------------------ +typedef struct { + void *value; + void *key; + uint32_t value_length; + uint32_t key_length; + uint64_t access_count; + void *next; +} lruc_item; + +typedef struct { + lruc_item **items; + uint64_t access_count; + uint64_t free_memory; + uint64_t total_memory; + uint64_t average_item_length; + uint32_t hash_table_size; + time_t seed; + lruc_item *free_items; + pthread_mutex_t *mutex; +} lruc; + + +// ------------------------------------------ +// api +// ------------------------------------------ +lruc *lruc_new(uint64_t cache_size, uint32_t average_length); +lruc_error lruc_free(lruc *cache); +lruc_error lruc_set(lruc *cache, void *key, uint32_t key_length, void *value, uint32_t value_length); +lruc_error lruc_get(lruc *cache, void *key, uint32_t key_length, void **value); +lruc_error lruc_delete(lruc *cache, void *key, uint32_t key_length); + +#endif diff --git a/src/lib/third_party/src/lruc.c b/src/lib/third_party/src/lruc.c new file mode 100644 index 000000000..f08fb2ce1 --- /dev/null +++ b/src/lib/third_party/src/lruc.c @@ -0,0 +1,294 @@ +/* https://github.com/willcannings/C-LRU-Cache */ + +#include "lruc.h" +#include +#include +#include +#include + +// ------------------------------------------ +// private functions +// ------------------------------------------ +// MurmurHash2, by Austin Appleby +// http://sites.google.com/site/murmurhash/ +uint32_t lruc_hash(lruc *cache, void *key, uint32_t key_length) { + uint32_t m = 0x5bd1e995; + uint32_t r = 24; + uint32_t h = cache->seed ^ key_length; + char* data = (char *)key; + + while(key_length >= 4) { + uint32_t k = *(uint32_t *)data; + k *= m; + k ^= k >> r; + k *= m; + h *= m; + h ^= k; + data += 4; + key_length -= 4; + } + + switch(key_length) { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + return h % cache->hash_table_size; +} + +// compare a key against an existing item's key +int lruc_cmp_keys(lruc_item *item, void *key, uint32_t key_length) { + if(key_length != item->key_length) + return 1; + else + return memcmp(key, item->key, key_length); +} + +// remove an item and push it to the free items queue +void lruc_remove_item(lruc *cache, lruc_item *prev, lruc_item *item, uint32_t hash_index) { + if(prev) + prev->next = item->next; + else + cache->items[hash_index] = (lruc_item *) item->next; + + // free memory and update the free memory counter + cache->free_memory += item->value_length; + free(item->value); + free(item->key); + + // push the item to the free items queue + memset(item, 0, sizeof(lruc_item)); + item->next = cache->free_items; + cache->free_items = item; +} + +// remove the least recently used item +// TODO: we can optimise this by finding the n lru items, where n = required_space / average_length +void lruc_remove_lru_item(lruc *cache) { + lruc_item *min_item = NULL, *min_prev = NULL; + lruc_item *item = NULL, *prev = NULL; + uint32_t i = 0, min_index = -1; + uint64_t min_access_count = -1; + + for(; i < cache->hash_table_size; i++) { + item = cache->items[i]; + prev = NULL; + + while(item) { + if(item->access_count < min_access_count || min_access_count == -1) { + min_access_count = item->access_count; + min_item = item; + min_prev = prev; + min_index = i; + } + prev = item; + item = item->next; + } + } + + if(min_item) + lruc_remove_item(cache, min_prev, min_item, min_index); +} + +// pop an existing item off the free queue, or create a new one +lruc_item *lruc_pop_or_create_item(lruc *cache) { + lruc_item *item = NULL; + + if(cache->free_items) { + item = cache->free_items; + cache->free_items = item->next; + } else { + item = (lruc_item *) calloc(sizeof(lruc_item), 1); + } + + return item; +} + +// error helpers +#define error_for(conditions, error) if(conditions) {return error;} +#define test_for_missing_cache() error_for(!cache, LRUC_MISSING_CACHE) +#define test_for_missing_key() error_for(!key || key_length == 0, LRUC_MISSING_KEY) +#define test_for_missing_value() error_for(!value || value_length == 0, LRUC_MISSING_VALUE) +#define test_for_value_too_large() error_for(value_length > cache->total_memory, LRUC_VALUE_TOO_LARGE) + +// lock helpers +#define lock_cache() if(pthread_mutex_lock(cache->mutex)) {\ + perror("LRU Cache unable to obtain mutex lock");\ + return LRUC_PTHREAD_ERROR;\ +} + +#define unlock_cache() if(pthread_mutex_unlock(cache->mutex)) {\ + perror("LRU Cache unable to release mutex lock");\ + return LRUC_PTHREAD_ERROR;\ +} + + +// ------------------------------------------ +// public api +// ------------------------------------------ +lruc *lruc_new(uint64_t cache_size, uint32_t average_length) { + // create the cache + lruc *cache = (lruc *) calloc(sizeof(lruc), 1); + if(!cache) { + perror("LRU Cache unable to create cache object"); + return NULL; + } + cache->hash_table_size = cache_size / average_length; + cache->average_item_length = average_length; + cache->free_memory = cache_size; + cache->total_memory = cache_size; + cache->seed = time(NULL); + + // size the hash table to a guestimate of the number of slots required (assuming a perfect hash) + cache->items = (lruc_item **) calloc(sizeof(lruc_item *), cache->hash_table_size); + if(!cache->items) { + perror("LRU Cache unable to create cache hash table"); + free(cache); + return NULL; + } + + // all cache calls are guarded by a mutex + cache->mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); + if(pthread_mutex_init(cache->mutex, NULL)) { + perror("LRU Cache unable to initialise mutex"); + free(cache->items); + free(cache); + return NULL; + } + return cache; +} + + +lruc_error lruc_free(lruc *cache) { + test_for_missing_cache(); + + // free each of the cached items, and the hash table + lruc_item *item = NULL, *next = NULL; + uint32_t i = 0; + if(cache->items) { + for(; i < cache->hash_table_size; i++) { + item = cache->items[i]; + while(item) { + next = (lruc_item *) item->next; + free(item); + item = next; + } + } + free(cache->items); + } + + // free the cache + if(cache->mutex) { + if(pthread_mutex_destroy(cache->mutex)) { + perror("LRU Cache unable to destroy mutex"); + return LRUC_PTHREAD_ERROR; + } + } + free(cache); + + return LRUC_NO_ERROR; +} + + +lruc_error lruc_set(lruc *cache, void *key, uint32_t key_length, void *value, uint32_t value_length) { + test_for_missing_cache(); + test_for_missing_key(); + test_for_missing_value(); + test_for_value_too_large(); + lock_cache(); + + // see if the key already exists + uint32_t hash_index = lruc_hash(cache, key, key_length), required = 0; + lruc_item *item = NULL, *prev = NULL; + item = cache->items[hash_index]; + + while(item && lruc_cmp_keys(item, key, key_length)) { + prev = item; + item = (lruc_item *) item->next; + } + + if(item) { + // update the value and value_lengths + required = value_length - item->value_length; + free(item->value); + item->value = value; + item->value_length = value_length; + + } else { + // insert a new item + item = lruc_pop_or_create_item(cache); + item->value = value; + item->key = key; + item->value_length = value_length; + item->key_length = key_length; + required = value_length; + + if(prev) + prev->next = item; + else + cache->items[hash_index] = item; + } + item->access_count = ++cache->access_count; + + // remove as many items as necessary to free enough space + if(required > 0 && required > cache->free_memory) { + while(cache->free_memory < required) + lruc_remove_lru_item(cache); + } + cache->free_memory -= required; + unlock_cache(); + return LRUC_NO_ERROR; +} + + +lruc_error lruc_get(lruc *cache, void *key, uint32_t key_length, void **value) { + test_for_missing_cache(); + test_for_missing_key(); + lock_cache(); + + // loop until we find the item, or hit the end of a chain + uint32_t hash_index = lruc_hash(cache, key, key_length); + lruc_item *item = cache->items[hash_index]; + + while(item && lruc_cmp_keys(item, key, key_length)) + item = (lruc_item *) item->next; + + if(item) { + *value = item->value; + item->access_count = ++cache->access_count; + } else { + *value = NULL; + } + + unlock_cache(); + return LRUC_NO_ERROR; +} + + +lruc_error lruc_delete(lruc *cache, void *key, uint32_t key_length) { + test_for_missing_cache(); + test_for_missing_key(); + lock_cache(); + + // loop until we find the item, or hit the end of a chain + lruc_item *item = NULL, *prev = NULL; + uint32_t hash_index = lruc_hash(cache, key, key_length); + item = cache->items[hash_index]; + + while(item && lruc_cmp_keys(item, key, key_length)) { + prev = item; + item = (lruc_item *) item->next; + } + + if(item) { + lruc_remove_item(cache, prev, item, hash_index); + } + + unlock_cache(); + return LRUC_NO_ERROR; +} -- cgit v1.2.3