diff options
author | Luca Deri <deri@ntop.org> | 2021-05-18 19:34:17 +0200 |
---|---|---|
committer | Luca Deri <deri@ntop.org> | 2021-05-18 19:34:17 +0200 |
commit | ca15e3295e217578fd08d6677e1f1a346ec15481 (patch) | |
tree | 56d6a63cbce0687558a5fd03ac14028fcdeabcd7 /src | |
parent | 0b3d627185db10c690026a32828d76d4db52eeef (diff) |
Added risk/score dump (ndpiReader -h)
Added ndpi_dump_risks_score() API score
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_api.h.in | 8 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 10 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 5258 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 24 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 24 |
5 files changed, 2705 insertions, 2619 deletions
diff --git a/src/include/ndpi_api.h.in b/src/include/ndpi_api.h.in index ecf696f7f..c44440cc8 100644 --- a/src/include/ndpi_api.h.in +++ b/src/include/ndpi_api.h.in @@ -681,6 +681,13 @@ extern "C" { void ndpi_dump_protocols(struct ndpi_detection_module_struct *mod); /** + * Write the list of the scores and their associated risks + * + * @par ndpi_mod = the detection module + */ + void ndpi_dump_risks_score(); + + /** * Read a file and load the protocols * * Format: <tcp|udp>:<port>,<tcp|udp>:<port>,.....@<proto> @@ -1512,6 +1519,7 @@ extern "C" { void ndpi_serialize_risk(ndpi_serializer *serializer, struct ndpi_flow_struct *flow); const char* ndpi_risk2str(ndpi_risk_enum risk); + const char* ndpi_severity2str(ndpi_risk_severity s); ndpi_risk_severity ndpi_risk2severity(ndpi_risk_enum risk); u_int16_t ndpi_risk2score(ndpi_risk risk); diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index ab8066aad..42c1e9f94 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -114,10 +114,12 @@ typedef enum { NDPI_RISK_SEVERE } ndpi_risk_severity; -#define NDPI_SCORE_RISK_LOW 10 -#define NDPI_SCORE_RISK_MEDIUM 50 -#define NDPI_SCORE_RISK_HIGH 100 -#define NDPI_SCORE_RISK_SEVERE 250 +typedef enum { + NDPI_SCORE_RISK_LOW = 10, + NDPI_SCORE_RISK_MEDIUM = 50, + NDPI_SCORE_RISK_HIGH = 100, + NDPI_SCORE_RISK_SEVERE = 250, +} ndpi_risk_score; /* NDPI_VISIT */ typedef enum { diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index d517e7540..b73dc0c21 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -325,10 +325,10 @@ void ndpi_set_proto_subprotocols(struct ndpi_detection_module_struct *ndpi_str, va_start(ap, protoId); while (current_arg != NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS) - { - ndpi_str->proto_defaults[protoId].subprotocol_count++; - current_arg = va_arg(ap, int); - } + { + ndpi_str->proto_defaults[protoId].subprotocol_count++; + current_arg = va_arg(ap, int); + } va_end(ap); ndpi_str->proto_defaults[protoId].subprotocols = NULL; @@ -337,9 +337,9 @@ void ndpi_set_proto_subprotocols(struct ndpi_detection_module_struct *ndpi_str, ndpi_str->proto_defaults[protoId].subprotocol_count--; /* No subprotocol was set before NDPI_NO_MORE_SUBPROTOCOLS. */ if (ndpi_str->proto_defaults[protoId].subprotocol_count == 0) - { - return; - } + { + return; + } ndpi_str->proto_defaults[protoId].subprotocols = ndpi_malloc(sizeof(protoId) * ndpi_str->proto_defaults[protoId].subprotocol_count); @@ -348,10 +348,10 @@ void ndpi_set_proto_subprotocols(struct ndpi_detection_module_struct *ndpi_str, va_start(ap, protoId); current_arg = va_arg(ap, int); while (current_arg != NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS) - { - ndpi_str->proto_defaults[protoId].subprotocols[i++] = current_arg; - current_arg = va_arg(ap, int); - } + { + ndpi_str->proto_defaults[protoId].subprotocols[i++] = current_arg; + current_arg = va_arg(ap, int); + } va_end(ap); } @@ -790,8 +790,8 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_build_default_ports(ports_a, 53, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 53, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_subprotocols(ndpi_str, NDPI_PROTOCOL_DNS, - NDPI_PROTOCOL_MATCHED_BY_CONTENT, - NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_DNS can have (content-matched) subprotocols */ + NDPI_PROTOCOL_MATCHED_BY_CONTENT, + NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_DNS can have (content-matched) subprotocols */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IPP, "IPP", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, @@ -805,16 +805,16 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_build_default_ports(ports_a, 80, 0 /* ntop */, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_subprotocols(ndpi_str, NDPI_PROTOCOL_HTTP, - NDPI_PROTOCOL_AIMINI, - NDPI_PROTOCOL_MATCHED_BY_CONTENT, - NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_HTTP can have (content-matched) subprotocols */ + NDPI_PROTOCOL_AIMINI, + NDPI_PROTOCOL_MATCHED_BY_CONTENT, + NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_HTTP can have (content-matched) subprotocols */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MDNS, "MDNS", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 5353, 5354, 0, 0, 0) /* UDP */); ndpi_set_proto_subprotocols(ndpi_str, NDPI_PROTOCOL_MDNS, - NDPI_PROTOCOL_MATCHED_BY_CONTENT, - NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_MDNS can have (content-matched) subprotocols */ + NDPI_PROTOCOL_MATCHED_BY_CONTENT, + NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_MDNS can have (content-matched) subprotocols */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_NTP, "NTP", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, @@ -1156,15 +1156,15 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_build_default_ports(ports_a, 443, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_subprotocols(ndpi_str, NDPI_PROTOCOL_TLS, - NDPI_PROTOCOL_MATCHED_BY_CONTENT, - NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_TLS can have (content-matched) subprotocols */ + NDPI_PROTOCOL_MATCHED_BY_CONTENT, + NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_TLS can have (content-matched) subprotocols */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_DTLS, "DTLS", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_subprotocols(ndpi_str, NDPI_PROTOCOL_DTLS, - NDPI_PROTOCOL_MATCHED_BY_CONTENT, - NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_DTLS can have (content-matched) subprotocols */ + NDPI_PROTOCOL_MATCHED_BY_CONTENT, + NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_DTLS can have (content-matched) subprotocols */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SSH, "SSH", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 22, 0, 0, 0, 0) /* TCP */, @@ -1290,15 +1290,15 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_subprotocols(ndpi_str, NDPI_PROTOCOL_HTTP_CONNECT, - NDPI_PROTOCOL_MATCHED_BY_CONTENT, - NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_HTTP_CONNECT can have (content-matched) subprotocols */ + NDPI_PROTOCOL_MATCHED_BY_CONTENT, + NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_HTTP_CONNECT can have (content-matched) subprotocols */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_HTTP_PROXY, "HTTP_Proxy", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 8080, 3128, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_subprotocols(ndpi_str, NDPI_PROTOCOL_HTTP_PROXY, - NDPI_PROTOCOL_MATCHED_BY_CONTENT, - NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_HTTP_PROXY can have (content-matched) subprotocols */ + NDPI_PROTOCOL_MATCHED_BY_CONTENT, + NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_HTTP_PROXY can have (content-matched) subprotocols */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_CITRIX, "Citrix", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 1494, 2598, 0, 0, 0) /* TCP */, @@ -1340,8 +1340,8 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 443, 80, 0, 0, 0) /* UDP */); ndpi_set_proto_subprotocols(ndpi_str, NDPI_PROTOCOL_QUIC, - NDPI_PROTOCOL_MATCHED_BY_CONTENT, - NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_QUIC can have (content-matched) subprotocols */ + NDPI_PROTOCOL_MATCHED_BY_CONTENT, + NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS); /* NDPI_PROTOCOL_QUIC can have (content-matched) subprotocols */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DIAMETER, "Diameter", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 3868, 0, 0, 0, 0) /* TCP */, @@ -1822,11 +1822,11 @@ u_int16_t ndpi_network_ptree_match(struct ndpi_detection_module_struct *ndpi_str if(ndpi_str->ndpi_num_custom_protocols == 0) { /* - In case we don't have defined any custom protocol we check the ptree - only in case of public IP addresses as in ndpi_content_match.c.inc - we only have public IP addresses. Instead with custom protocols, users - might have defined private protocols hence we should not skip - the checks below + In case we don't have defined any custom protocol we check the ptree + only in case of public IP addresses as in ndpi_content_match.c.inc + we only have public IP addresses. Instead with custom protocols, users + might have defined private protocols hence we should not skip + the checks below */ if(ndpi_is_public_ipv4(ntohl(pin->s_addr)) == 0) @@ -2607,7 +2607,7 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) { if(ndpi_str->malicious_sha1_automa.ac_automa != NULL) ac_automata_release((AC_AUTOMATA_t *) ndpi_str->malicious_sha1_automa.ac_automa, - 1 /* free patterns strings memory */); + 1 /* free patterns strings memory */); if(ndpi_str->custom_categories.hostnames.ac_automa != NULL) ac_automata_release((AC_AUTOMATA_t *) ndpi_str->custom_categories.hostnames.ac_automa, @@ -2972,7 +2972,7 @@ int ndpi_load_categories_file(struct ndpi_detection_module_struct *ndpi_str, con /* ******************************************************************** */ static int ndpi_load_risky_domain(struct ndpi_detection_module_struct *ndpi_str, - char* domain_name) { + char* domain_name) { if(ndpi_str->risky_domain_automa.ac_automa == NULL) ndpi_str->risky_domain_automa.ac_automa = ac_automata_init(ac_match_handler); @@ -4032,52 +4032,52 @@ void ndpi_apply_flow_protocol_to_packet(struct ndpi_flow_struct *flow, struct nd /* ****************************************************** */ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) { - if(flow) { - if(flow->http.url) - ndpi_free(flow->http.url); - - if(flow->http.content_type) - ndpi_free(flow->http.content_type); - - if(flow->http.request_content_type) - ndpi_free(flow->http.request_content_type); - - if(flow->http.user_agent) - ndpi_free(flow->http.user_agent); - - if(flow->kerberos_buf.pktbuf) - ndpi_free(flow->kerberos_buf.pktbuf); - - if(flow_is_proto(flow, NDPI_PROTOCOL_QUIC) || - flow_is_proto(flow, NDPI_PROTOCOL_TLS) || - flow_is_proto(flow, NDPI_PROTOCOL_DTLS) || - flow_is_proto(flow, NDPI_PROTOCOL_MAIL_SMTPS) || - flow_is_proto(flow, NDPI_PROTOCOL_MAIL_POPS) || - flow_is_proto(flow, NDPI_PROTOCOL_MAIL_IMAPS)) { - if(flow->protos.tls_quic_stun.tls_quic.server_names) - ndpi_free(flow->protos.tls_quic_stun.tls_quic.server_names); - - if(flow->protos.tls_quic_stun.tls_quic.alpn) - ndpi_free(flow->protos.tls_quic_stun.tls_quic.alpn); - - if(flow->protos.tls_quic_stun.tls_quic.tls_supported_versions) - ndpi_free(flow->protos.tls_quic_stun.tls_quic.tls_supported_versions); - - if(flow->protos.tls_quic_stun.tls_quic.issuerDN) - ndpi_free(flow->protos.tls_quic_stun.tls_quic.issuerDN); - - if(flow->protos.tls_quic_stun.tls_quic.subjectDN) - ndpi_free(flow->protos.tls_quic_stun.tls_quic.subjectDN); - - if(flow->protos.tls_quic_stun.tls_quic.encrypted_sni.esni) - ndpi_free(flow->protos.tls_quic_stun.tls_quic.encrypted_sni.esni); - } + if(flow) { + if(flow->http.url) + ndpi_free(flow->http.url); + + if(flow->http.content_type) + ndpi_free(flow->http.content_type); + + if(flow->http.request_content_type) + ndpi_free(flow->http.request_content_type); + + if(flow->http.user_agent) + ndpi_free(flow->http.user_agent); + + if(flow->kerberos_buf.pktbuf) + ndpi_free(flow->kerberos_buf.pktbuf); + + if(flow_is_proto(flow, NDPI_PROTOCOL_QUIC) || + flow_is_proto(flow, NDPI_PROTOCOL_TLS) || + flow_is_proto(flow, NDPI_PROTOCOL_DTLS) || + flow_is_proto(flow, NDPI_PROTOCOL_MAIL_SMTPS) || + flow_is_proto(flow, NDPI_PROTOCOL_MAIL_POPS) || + flow_is_proto(flow, NDPI_PROTOCOL_MAIL_IMAPS)) { + if(flow->protos.tls_quic_stun.tls_quic.server_names) + ndpi_free(flow->protos.tls_quic_stun.tls_quic.server_names); + + if(flow->protos.tls_quic_stun.tls_quic.alpn) + ndpi_free(flow->protos.tls_quic_stun.tls_quic.alpn); + + if(flow->protos.tls_quic_stun.tls_quic.tls_supported_versions) + ndpi_free(flow->protos.tls_quic_stun.tls_quic.tls_supported_versions); + + if(flow->protos.tls_quic_stun.tls_quic.issuerDN) + ndpi_free(flow->protos.tls_quic_stun.tls_quic.issuerDN); + + if(flow->protos.tls_quic_stun.tls_quic.subjectDN) + ndpi_free(flow->protos.tls_quic_stun.tls_quic.subjectDN); + + if(flow->protos.tls_quic_stun.tls_quic.encrypted_sni.esni) + ndpi_free(flow->protos.tls_quic_stun.tls_quic.encrypted_sni.esni); + } - if(flow->l4_proto == IPPROTO_TCP) { - if(flow->l4.tcp.tls.message.buffer) - ndpi_free(flow->l4.tcp.tls.message.buffer); - } + if(flow->l4_proto == IPPROTO_TCP) { + if(flow->l4.tcp.tls.message.buffer) + ndpi_free(flow->l4.tcp.tls.message.buffer); } + } } /* ************************************************ */ @@ -4114,7 +4114,7 @@ static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str if(decaps_iph && decaps_iph->version == IPVERSION && decaps_iph->ihl >= 5) { NDPI_LOG_DBG2(ndpi_str, "ipv4 header\n"); } else if(decaps_iph && decaps_iph->version == 6 && l3len >= sizeof(struct ndpi_ipv6hdr) && - (ndpi_str->ip_version_limit & NDPI_DETECTION_ONLY_IPV4) == 0) { + (ndpi_str->ip_version_limit & NDPI_DETECTION_ONLY_IPV4) == 0) { NDPI_LOG_DBG2(ndpi_str, "ipv6 header\n"); flow->packet.iphv6 = (struct ndpi_ipv6hdr *) flow->packet.iph; flow->packet.iph = NULL; @@ -4199,1675 +4199,1672 @@ static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str /* ************************************************ */ - void ndpi_connection_tracking(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow) { - if(!flow) { - return; - } else { - /* const for gcc code optimization and cleaner code */ - struct ndpi_packet_struct *packet = &flow->packet; - const struct ndpi_iphdr *iph = packet->iph; - const struct ndpi_ipv6hdr *iphv6 = packet->iphv6; - const struct ndpi_tcphdr *tcph = packet->tcp; - const struct ndpi_udphdr *udph = packet->udp; +void ndpi_connection_tracking(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow) { + if(!flow) { + return; + } else { + /* const for gcc code optimization and cleaner code */ + struct ndpi_packet_struct *packet = &flow->packet; + const struct ndpi_iphdr *iph = packet->iph; + const struct ndpi_ipv6hdr *iphv6 = packet->iphv6; + const struct ndpi_tcphdr *tcph = packet->tcp; + const struct ndpi_udphdr *udph = packet->udp; - packet->tcp_retransmission = 0, packet->packet_direction = 0; + packet->tcp_retransmission = 0, packet->packet_direction = 0; - if(ndpi_str->direction_detect_disable) { - packet->packet_direction = flow->packet_direction; - } else { - if(iph != NULL && ntohl(iph->saddr) < ntohl(iph->daddr)) - packet->packet_direction = 1; + if(ndpi_str->direction_detect_disable) { + packet->packet_direction = flow->packet_direction; + } else { + if(iph != NULL && ntohl(iph->saddr) < ntohl(iph->daddr)) + packet->packet_direction = 1; - if((iphv6 != NULL) - && NDPI_COMPARE_IPV6_ADDRESS_STRUCTS(&iphv6->ip6_src, &iphv6->ip6_dst) != 0) - packet->packet_direction = 1; - } + if((iphv6 != NULL) + && NDPI_COMPARE_IPV6_ADDRESS_STRUCTS(&iphv6->ip6_src, &iphv6->ip6_dst) != 0) + packet->packet_direction = 1; + } - packet->packet_lines_parsed_complete = 0; + packet->packet_lines_parsed_complete = 0; - if(flow->init_finished == 0) { - flow->init_finished = 1; - flow->setup_packet_direction = packet->packet_direction; - } + if(flow->init_finished == 0) { + flow->init_finished = 1; + flow->setup_packet_direction = packet->packet_direction; + } - if(tcph != NULL) { - /* reset retried bytes here before setting it */ - packet->num_retried_bytes = 0; + if(tcph != NULL) { + /* reset retried bytes here before setting it */ + packet->num_retried_bytes = 0; - if(!ndpi_str->direction_detect_disable) - packet->packet_direction = (ntohs(tcph->source) < ntohs(tcph->dest)) ? 1 : 0; + if(!ndpi_str->direction_detect_disable) + packet->packet_direction = (ntohs(tcph->source) < ntohs(tcph->dest)) ? 1 : 0; - if(tcph->syn != 0 && tcph->ack == 0 && flow->l4.tcp.seen_syn == 0 && flow->l4.tcp.seen_syn_ack == 0 && + if(tcph->syn != 0 && tcph->ack == 0 && flow->l4.tcp.seen_syn == 0 && flow->l4.tcp.seen_syn_ack == 0 && + flow->l4.tcp.seen_ack == 0) { + flow->l4.tcp.seen_syn = 1; + } else + if(tcph->syn != 0 && tcph->ack != 0 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 0 && flow->l4.tcp.seen_ack == 0) { - flow->l4.tcp.seen_syn = 1; + flow->l4.tcp.seen_syn_ack = 1; } else - if(tcph->syn != 0 && tcph->ack != 0 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 0 && + if(tcph->syn == 0 && tcph->ack == 1 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 1 && flow->l4.tcp.seen_ack == 0) { - flow->l4.tcp.seen_syn_ack = 1; - } else - if(tcph->syn == 0 && tcph->ack == 1 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 1 && - flow->l4.tcp.seen_ack == 0) { - flow->l4.tcp.seen_ack = 1; - } - - if((flow->next_tcp_seq_nr[0] == 0 && flow->next_tcp_seq_nr[1] == 0) || - (flow->next_tcp_seq_nr[0] == 0 || flow->next_tcp_seq_nr[1] == 0)) { - /* initialize tcp sequence counters */ - /* the ack flag needs to be set to get valid sequence numbers from the other - * direction. Usually it will catch the second packet syn+ack but it works - * also for asymmetric traffic where it will use the first data packet - * - * if the syn flag is set add one to the sequence number, - * otherwise use the payload length. - */ - if(tcph->ack != 0) { - flow->next_tcp_seq_nr[flow->packet.packet_direction] = - ntohl(tcph->seq) + (tcph->syn ? 1 : packet->payload_packet_len); - - /* - Check to avoid discrepancies in case we analyze a flow that does not start with SYN... - but that is already started when nDPI being to process it. See also (***) below - */ - if(flow->num_processed_pkts > 1) - flow->next_tcp_seq_nr[1 - flow->packet.packet_direction] = ntohl(tcph->ack_seq); - } - } else if(packet->payload_packet_len > 0) { - /* check tcp sequence counters */ - if(((u_int32_t)(ntohl(tcph->seq) - flow->next_tcp_seq_nr[packet->packet_direction])) > - ndpi_str->tcp_max_retransmission_window_size) { - packet->tcp_retransmission = 1; - - /* CHECK IF PARTIAL RETRY IS HAPPENING */ - if((flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq) < - packet->payload_packet_len)) { - /* num_retried_bytes actual_payload_len hold info about the partial retry - analyzer which require this info can make use of this info - Other analyzer can use packet->payload_packet_len */ - packet->num_retried_bytes = - (u_int16_t)(flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq)); - packet->actual_payload_len = packet->payload_packet_len - packet->num_retried_bytes; - - if(flow->num_processed_pkts > 1) /* See also (***) above */ - flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; - } + flow->l4.tcp.seen_ack = 1; } - /* normal path - actual_payload_len is initialized to payload_packet_len during tcp header parsing itself. - It will be changed only in case of retransmission */ - else { - packet->num_retried_bytes = 0; - flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; + if((flow->next_tcp_seq_nr[0] == 0 && flow->next_tcp_seq_nr[1] == 0) || + (flow->next_tcp_seq_nr[0] == 0 || flow->next_tcp_seq_nr[1] == 0)) { + /* initialize tcp sequence counters */ + /* the ack flag needs to be set to get valid sequence numbers from the other + * direction. Usually it will catch the second packet syn+ack but it works + * also for asymmetric traffic where it will use the first data packet + * + * if the syn flag is set add one to the sequence number, + * otherwise use the payload length. + */ + if(tcph->ack != 0) { + flow->next_tcp_seq_nr[flow->packet.packet_direction] = + ntohl(tcph->seq) + (tcph->syn ? 1 : packet->payload_packet_len); + + /* + Check to avoid discrepancies in case we analyze a flow that does not start with SYN... + but that is already started when nDPI being to process it. See also (***) below + */ + if(flow->num_processed_pkts > 1) + flow->next_tcp_seq_nr[1 - flow->packet.packet_direction] = ntohl(tcph->ack_seq); + } + } else if(packet->payload_packet_len > 0) { + /* check tcp sequence counters */ + if(((u_int32_t)(ntohl(tcph->seq) - flow->next_tcp_seq_nr[packet->packet_direction])) > + ndpi_str->tcp_max_retransmission_window_size) { + packet->tcp_retransmission = 1; + + /* CHECK IF PARTIAL RETRY IS HAPPENING */ + if((flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq) < + packet->payload_packet_len)) { + /* num_retried_bytes actual_payload_len hold info about the partial retry + analyzer which require this info can make use of this info + Other analyzer can use packet->payload_packet_len */ + packet->num_retried_bytes = + (u_int16_t)(flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq)); + packet->actual_payload_len = packet->payload_packet_len - packet->num_retried_bytes; + + if(flow->num_processed_pkts > 1) /* See also (***) above */ + flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; } } - if(tcph->rst) { - flow->next_tcp_seq_nr[0] = 0; - flow->next_tcp_seq_nr[1] = 0; + /* normal path + actual_payload_len is initialized to payload_packet_len during tcp header parsing itself. + It will be changed only in case of retransmission */ + else { + packet->num_retried_bytes = 0; + flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; } - } else if(udph != NULL) { - if(!ndpi_str->direction_detect_disable) - packet->packet_direction = (htons(udph->source) < htons(udph->dest)) ? 1 : 0; } - if(flow->packet_counter < MAX_PACKET_COUNTER && packet->payload_packet_len) { - flow->packet_counter++; + if(tcph->rst) { + flow->next_tcp_seq_nr[0] = 0; + flow->next_tcp_seq_nr[1] = 0; } + } else if(udph != NULL) { + if(!ndpi_str->direction_detect_disable) + packet->packet_direction = (htons(udph->source) < htons(udph->dest)) ? 1 : 0; + } - if(flow->packet_direction_counter[packet->packet_direction] < MAX_PACKET_COUNTER && - packet->payload_packet_len) { - flow->packet_direction_counter[packet->packet_direction]++; - } + if(flow->packet_counter < MAX_PACKET_COUNTER && packet->payload_packet_len) { + flow->packet_counter++; + } - if(flow->byte_counter[packet->packet_direction] + packet->payload_packet_len > - flow->byte_counter[packet->packet_direction]) { - flow->byte_counter[packet->packet_direction] += packet->payload_packet_len; - } + if(flow->packet_direction_counter[packet->packet_direction] < MAX_PACKET_COUNTER && + packet->payload_packet_len) { + flow->packet_direction_counter[packet->packet_direction]++; + } + + if(flow->byte_counter[packet->packet_direction] + packet->payload_packet_len > + flow->byte_counter[packet->packet_direction]) { + flow->byte_counter[packet->packet_direction] += packet->payload_packet_len; } } +} - /* ************************************************ */ +/* ************************************************ */ - static u_int32_t check_ndpi_detection_func(struct ndpi_detection_module_struct * const ndpi_str, - struct ndpi_flow_struct * const flow, - NDPI_SELECTION_BITMASK_PROTOCOL_SIZE const ndpi_selection_packet, - struct ndpi_call_function_struct const * const callback_buffer, - uint32_t callback_buffer_size) - { - void *func = NULL; - u_int8_t is_tcp_without_payload = (callback_buffer == ndpi_str->callback_buffer_tcp_no_payload); - u_int32_t num_calls = (is_tcp_without_payload != 0 ? 1 : 0); - u_int16_t proto_index = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoIdx; - u_int16_t proto_id = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoId; - NDPI_PROTOCOL_BITMASK detection_bitmask; - - NDPI_SAVE_AS_BITMASK(detection_bitmask, flow->packet.detected_protocol_stack[0]); - - if ((proto_id != NDPI_PROTOCOL_UNKNOWN) && - NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, - ndpi_str->callback_buffer[proto_index].excluded_protocol_bitmask) == 0 && - NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer[proto_index].detection_bitmask, detection_bitmask) != 0 && - (ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask & ndpi_selection_packet) == - ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask) +static u_int32_t check_ndpi_detection_func(struct ndpi_detection_module_struct * const ndpi_str, + struct ndpi_flow_struct * const flow, + NDPI_SELECTION_BITMASK_PROTOCOL_SIZE const ndpi_selection_packet, + struct ndpi_call_function_struct const * const callback_buffer, + uint32_t callback_buffer_size) +{ + void *func = NULL; + u_int8_t is_tcp_without_payload = (callback_buffer == ndpi_str->callback_buffer_tcp_no_payload); + u_int32_t num_calls = (is_tcp_without_payload != 0 ? 1 : 0); + u_int16_t proto_index = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoIdx; + u_int16_t proto_id = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoId; + NDPI_PROTOCOL_BITMASK detection_bitmask; + + NDPI_SAVE_AS_BITMASK(detection_bitmask, flow->packet.detected_protocol_stack[0]); + + if ((proto_id != NDPI_PROTOCOL_UNKNOWN) && + NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, + ndpi_str->callback_buffer[proto_index].excluded_protocol_bitmask) == 0 && + NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer[proto_index].detection_bitmask, detection_bitmask) != 0 && + (ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask & ndpi_selection_packet) == + ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask) { if ((flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) && (ndpi_str->proto_defaults[flow->guessed_protocol_id].func != NULL) && (is_tcp_without_payload == 0 || ((ndpi_str->callback_buffer[flow->guessed_protocol_id].ndpi_selection_bitmask & - NDPI_SELECTION_BITMASK_PROTOCOL_HAS_PAYLOAD) == 0))) - { - ndpi_str->proto_defaults[flow->guessed_protocol_id].func(ndpi_str, flow); - func = ndpi_str->proto_defaults[flow->guessed_protocol_id].func; - num_calls++; - } + NDPI_SELECTION_BITMASK_PROTOCOL_HAS_PAYLOAD) == 0))) + { + ndpi_str->proto_defaults[flow->guessed_protocol_id].func(ndpi_str, flow); + func = ndpi_str->proto_defaults[flow->guessed_protocol_id].func; + num_calls++; + } } - if (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) + if (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { for (u_int32_t a = 0; a < callback_buffer_size; a++) { if ((func != callback_buffer[a].func) && (callback_buffer[a].ndpi_selection_bitmask & ndpi_selection_packet) == - callback_buffer[a].ndpi_selection_bitmask && + callback_buffer[a].ndpi_selection_bitmask && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, callback_buffer[a].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(callback_buffer[a].detection_bitmask, detection_bitmask) != 0) - { - callback_buffer[a].func(ndpi_str, flow); - num_calls++; - - if (flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) - { - break; /* Stop after the first detected protocol. */ - } - } + { + callback_buffer[a].func(ndpi_str, flow); + num_calls++; + + if (flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) + { + break; /* Stop after the first detected protocol. */ + } + } } } - /* Check for subprotocols. */ - for (u_int32_t a = 0; a < ndpi_str->proto_defaults[flow->detected_protocol_stack[0]].subprotocol_count; a++) + /* Check for subprotocols. */ + for (u_int32_t a = 0; a < ndpi_str->proto_defaults[flow->detected_protocol_stack[0]].subprotocol_count; a++) { u_int16_t subproto_id = ndpi_str->proto_defaults[flow->detected_protocol_stack[0]].subprotocols[a]; if (subproto_id == (uint16_t)NDPI_PROTOCOL_MATCHED_BY_CONTENT) - { - continue; - } + { + continue; + } u_int16_t subproto_index = ndpi_str->proto_defaults[subproto_id].protoIdx; if ((func != ndpi_str->proto_defaults[subproto_id].func) && (ndpi_str->callback_buffer[subproto_index].ndpi_selection_bitmask & ndpi_selection_packet) == - ndpi_str->callback_buffer[subproto_index].ndpi_selection_bitmask && + ndpi_str->callback_buffer[subproto_index].ndpi_selection_bitmask && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer[subproto_index].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer[subproto_index].detection_bitmask, detection_bitmask) != 0) - { - ndpi_str->callback_buffer[subproto_index].func(ndpi_str, flow); - num_calls++; - } + { + ndpi_str->callback_buffer[subproto_index].func(ndpi_str, flow); + num_calls++; + } if (flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) - { - break; /* Stop after the first detected subprotocol. */ - } + { + break; /* Stop after the first detected subprotocol. */ + } } - return num_calls; - } + return num_calls; +} - /* ************************************************ */ +/* ************************************************ */ - u_int32_t check_ndpi_other_flow_func(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, - NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) - { - return check_ndpi_detection_func(ndpi_str, flow, *ndpi_selection_packet, - ndpi_str->callback_buffer_non_tcp_udp, - ndpi_str->callback_buffer_size_non_tcp_udp); - } +u_int32_t check_ndpi_other_flow_func(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) +{ + return check_ndpi_detection_func(ndpi_str, flow, *ndpi_selection_packet, + ndpi_str->callback_buffer_non_tcp_udp, + ndpi_str->callback_buffer_size_non_tcp_udp); +} - /* ************************************************ */ +/* ************************************************ */ - static u_int32_t check_ndpi_udp_flow_func(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, - NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) - { - return check_ndpi_detection_func(ndpi_str, flow, *ndpi_selection_packet, - ndpi_str->callback_buffer_udp, - ndpi_str->callback_buffer_size_udp); - } +static u_int32_t check_ndpi_udp_flow_func(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) +{ + return check_ndpi_detection_func(ndpi_str, flow, *ndpi_selection_packet, + ndpi_str->callback_buffer_udp, + ndpi_str->callback_buffer_size_udp); +} - /* ************************************************ */ +/* ************************************************ */ - static u_int32_t check_ndpi_tcp_flow_func(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, - NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) - { - if (flow->packet.payload_packet_len != 0) { - return check_ndpi_detection_func(ndpi_str, flow, *ndpi_selection_packet, - ndpi_str->callback_buffer_tcp_payload, - ndpi_str->callback_buffer_size_tcp_payload); - } else { - /* no payload */ - return check_ndpi_detection_func(ndpi_str, flow, *ndpi_selection_packet, - ndpi_str->callback_buffer_tcp_no_payload, - ndpi_str->callback_buffer_size_tcp_no_payload); - } +static u_int32_t check_ndpi_tcp_flow_func(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) +{ + if (flow->packet.payload_packet_len != 0) { + return check_ndpi_detection_func(ndpi_str, flow, *ndpi_selection_packet, + ndpi_str->callback_buffer_tcp_payload, + ndpi_str->callback_buffer_size_tcp_payload); + } else { + /* no payload */ + return check_ndpi_detection_func(ndpi_str, flow, *ndpi_selection_packet, + ndpi_str->callback_buffer_tcp_no_payload, + ndpi_str->callback_buffer_size_tcp_no_payload); } +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - u_int32_t ndpi_check_flow_func(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, - NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { - if(!flow) - return(0); - else if(flow->packet.tcp != NULL) - return(check_ndpi_tcp_flow_func(ndpi_str, flow, ndpi_selection_packet)); - else if(flow->packet.udp != NULL) - return(check_ndpi_udp_flow_func(ndpi_str, flow, ndpi_selection_packet)); - else - return(check_ndpi_other_flow_func(ndpi_str, flow, ndpi_selection_packet)); - } +u_int32_t ndpi_check_flow_func(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { + if(!flow) + return(0); + else if(flow->packet.tcp != NULL) + return(check_ndpi_tcp_flow_func(ndpi_str, flow, ndpi_selection_packet)); + else if(flow->packet.udp != NULL) + return(check_ndpi_udp_flow_func(ndpi_str, flow, ndpi_selection_packet)); + else + return(check_ndpi_other_flow_func(ndpi_str, flow, ndpi_selection_packet)); +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - u_int16_t ndpi_guess_host_protocol_id(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow) { - u_int16_t ret = NDPI_PROTOCOL_UNKNOWN; +u_int16_t ndpi_guess_host_protocol_id(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow) { + u_int16_t ret = NDPI_PROTOCOL_UNKNOWN; - if(flow->packet.iph) { - struct in_addr addr; - u_int16_t sport, dport; + if(flow->packet.iph) { + struct in_addr addr; + u_int16_t sport, dport; - addr.s_addr = flow->packet.iph->saddr; + addr.s_addr = flow->packet.iph->saddr; - if((flow->l4_proto == IPPROTO_TCP) && flow->packet.tcp) - sport = flow->packet.tcp->source, dport = flow->packet.tcp->dest; - else if((flow->l4_proto == IPPROTO_UDP) && flow->packet.udp) - sport = flow->packet.udp->source, dport = flow->packet.udp->dest; - else - sport = dport = 0; + if((flow->l4_proto == IPPROTO_TCP) && flow->packet.tcp) + sport = flow->packet.tcp->source, dport = flow->packet.tcp->dest; + else if((flow->l4_proto == IPPROTO_UDP) && flow->packet.udp) + sport = flow->packet.udp->source, dport = flow->packet.udp->dest; + else + sport = dport = 0; - /* guess host protocol */ - ret = ndpi_network_port_ptree_match(ndpi_str, &addr, sport); + /* guess host protocol */ + ret = ndpi_network_port_ptree_match(ndpi_str, &addr, sport); - if(ret == NDPI_PROTOCOL_UNKNOWN) { - addr.s_addr = flow->packet.iph->daddr; - ret = ndpi_network_port_ptree_match(ndpi_str, &addr, dport); - } + if(ret == NDPI_PROTOCOL_UNKNOWN) { + addr.s_addr = flow->packet.iph->daddr; + ret = ndpi_network_port_ptree_match(ndpi_str, &addr, dport); } - - return(ret); } - /* ********************************************************************************* */ + return(ret); +} - ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - u_int8_t enable_guess, u_int8_t *protocol_was_guessed) { - ndpi_protocol ret = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED}; +/* ********************************************************************************* */ - *protocol_was_guessed = 0; +ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + u_int8_t enable_guess, u_int8_t *protocol_was_guessed) { + ndpi_protocol ret = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED}; - if(flow == NULL) - return(ret); + *protocol_was_guessed = 0; - /* Init defaults */ - ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; - ret.category = flow->category; + if(flow == NULL) + return(ret); - /* Ensure that we don't change our mind if detection is already complete */ - if((ret.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (ret.app_protocol != NDPI_PROTOCOL_UNKNOWN)) - return(ret); + /* Init defaults */ + ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; + ret.category = flow->category; - if(ndpi_str->mining_cache && flow->packet.iph) { - u_int16_t cached_proto; - u_int32_t key = flow->packet.iph->saddr + flow->packet.iph->daddr; + /* Ensure that we don't change our mind if detection is already complete */ + if((ret.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (ret.app_protocol != NDPI_PROTOCOL_UNKNOWN)) + return(ret); + + if(ndpi_str->mining_cache && flow->packet.iph) { + u_int16_t cached_proto; + u_int32_t key = flow->packet.iph->saddr + flow->packet.iph->daddr; - if(ndpi_lru_find_cache(ndpi_str->mining_cache, key, - &cached_proto, 0 /* Don't remove it as it can be used for other connections */)) { - ndpi_set_detected_protocol(ndpi_str, flow, cached_proto, NDPI_PROTOCOL_UNKNOWN); - ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; - return(ret); - } + if(ndpi_lru_find_cache(ndpi_str->mining_cache, key, + &cached_proto, 0 /* Don't remove it as it can be used for other connections */)) { + ndpi_set_detected_protocol(ndpi_str, flow, cached_proto, NDPI_PROTOCOL_UNKNOWN); + ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; + return(ret); } + } - /* TODO: add the remaining stage_XXXX protocols */ - if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { - u_int16_t guessed_protocol_id = NDPI_PROTOCOL_UNKNOWN, guessed_host_protocol_id = NDPI_PROTOCOL_UNKNOWN; - - if(flow->guessed_protocol_id == NDPI_PROTOCOL_STUN) - goto check_stun_export; - else if((flow->guessed_protocol_id == NDPI_PROTOCOL_HANGOUT_DUO) || - (flow->guessed_protocol_id == NDPI_PROTOCOL_MESSENGER) || - (flow->guessed_protocol_id == NDPI_PROTOCOL_WHATSAPP_CALL)) { - *protocol_was_guessed = 1; - ndpi_set_detected_protocol(ndpi_str, flow, flow->guessed_protocol_id, NDPI_PROTOCOL_UNKNOWN); - } - else if((flow->l4.tcp.tls.hello_processed == 1) && - (flow->protos.tls_quic_stun.tls_quic.client_requested_server_name[0] != '\0')) { - *protocol_was_guessed = 1; - ndpi_set_detected_protocol(ndpi_str, flow, NDPI_PROTOCOL_TLS, NDPI_PROTOCOL_UNKNOWN); - } else if(enable_guess) { - if((flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) && (flow->packet.l4_protocol == IPPROTO_TCP) && - flow->l4.tcp.tls.hello_processed) - flow->guessed_protocol_id = NDPI_PROTOCOL_TLS; - - guessed_protocol_id = flow->guessed_protocol_id, guessed_host_protocol_id = flow->guessed_host_protocol_id; - - if((guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) && - ((flow->packet.l4_protocol == IPPROTO_UDP) && - NDPI_ISSET(&flow->excluded_protocol_bitmask, guessed_host_protocol_id) && - is_udp_guessable_protocol(guessed_host_protocol_id))) - flow->guessed_host_protocol_id = guessed_host_protocol_id = NDPI_PROTOCOL_UNKNOWN; - - /* Ignore guessed protocol if they have been discarded */ - if((guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) - // && (guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) - && (flow->packet.l4_protocol == IPPROTO_UDP) && - NDPI_ISSET(&flow->excluded_protocol_bitmask, guessed_protocol_id) && - is_udp_guessable_protocol(guessed_protocol_id)) - flow->guessed_protocol_id = guessed_protocol_id = NDPI_PROTOCOL_UNKNOWN; - - if((guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) || (guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN)) { - if((guessed_protocol_id == 0) && (flow->protos.tls_quic_stun.stun.num_binding_requests > 0) && - (flow->protos.tls_quic_stun.stun.num_processed_pkts > 0)) - guessed_protocol_id = NDPI_PROTOCOL_STUN; - - if(flow->host_server_name[0] != '\0') { - ndpi_protocol_match_result ret_match; - - memset(&ret_match, 0, sizeof(ret_match)); - - ndpi_match_host_subprotocol(ndpi_str, flow, (char *) flow->host_server_name, - strlen((const char *) flow->host_server_name), &ret_match, - NDPI_PROTOCOL_DNS); - - if(ret_match.protocol_id != NDPI_PROTOCOL_UNKNOWN) - guessed_host_protocol_id = ret_match.protocol_id; - } - - *protocol_was_guessed = 1; - ndpi_int_change_protocol(ndpi_str, flow, guessed_host_protocol_id, guessed_protocol_id); - } - } + /* TODO: add the remaining stage_XXXX protocols */ + if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { + u_int16_t guessed_protocol_id = NDPI_PROTOCOL_UNKNOWN, guessed_host_protocol_id = NDPI_PROTOCOL_UNKNOWN; + + if(flow->guessed_protocol_id == NDPI_PROTOCOL_STUN) + goto check_stun_export; + else if((flow->guessed_protocol_id == NDPI_PROTOCOL_HANGOUT_DUO) || + (flow->guessed_protocol_id == NDPI_PROTOCOL_MESSENGER) || + (flow->guessed_protocol_id == NDPI_PROTOCOL_WHATSAPP_CALL)) { + *protocol_was_guessed = 1; + ndpi_set_detected_protocol(ndpi_str, flow, flow->guessed_protocol_id, NDPI_PROTOCOL_UNKNOWN); + } + else if((flow->l4.tcp.tls.hello_processed == 1) && + (flow->protos.tls_quic_stun.tls_quic.client_requested_server_name[0] != '\0')) { + *protocol_was_guessed = 1; + ndpi_set_detected_protocol(ndpi_str, flow, NDPI_PROTOCOL_TLS, NDPI_PROTOCOL_UNKNOWN); } else if(enable_guess) { - if(flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) { - *protocol_was_guessed = 1; - flow->detected_protocol_stack[1] = flow->guessed_protocol_id; - } - - if(flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) { - *protocol_was_guessed = 1; - flow->detected_protocol_stack[0] = flow->guessed_host_protocol_id; - } + if((flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) && (flow->packet.l4_protocol == IPPROTO_TCP) && + flow->l4.tcp.tls.hello_processed) + flow->guessed_protocol_id = NDPI_PROTOCOL_TLS; + + guessed_protocol_id = flow->guessed_protocol_id, guessed_host_protocol_id = flow->guessed_host_protocol_id; + + if((guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) && + ((flow->packet.l4_protocol == IPPROTO_UDP) && + NDPI_ISSET(&flow->excluded_protocol_bitmask, guessed_host_protocol_id) && + is_udp_guessable_protocol(guessed_host_protocol_id))) + flow->guessed_host_protocol_id = guessed_host_protocol_id = NDPI_PROTOCOL_UNKNOWN; + + /* Ignore guessed protocol if they have been discarded */ + if((guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) + // && (guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) + && (flow->packet.l4_protocol == IPPROTO_UDP) && + NDPI_ISSET(&flow->excluded_protocol_bitmask, guessed_protocol_id) && + is_udp_guessable_protocol(guessed_protocol_id)) + flow->guessed_protocol_id = guessed_protocol_id = NDPI_PROTOCOL_UNKNOWN; + + if((guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) || (guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN)) { + if((guessed_protocol_id == 0) && (flow->protos.tls_quic_stun.stun.num_binding_requests > 0) && + (flow->protos.tls_quic_stun.stun.num_processed_pkts > 0)) + guessed_protocol_id = NDPI_PROTOCOL_STUN; + + if(flow->host_server_name[0] != '\0') { + ndpi_protocol_match_result ret_match; + + memset(&ret_match, 0, sizeof(ret_match)); + + ndpi_match_host_subprotocol(ndpi_str, flow, (char *) flow->host_server_name, + strlen((const char *) flow->host_server_name), &ret_match, + NDPI_PROTOCOL_DNS); + + if(ret_match.protocol_id != NDPI_PROTOCOL_UNKNOWN) + guessed_host_protocol_id = ret_match.protocol_id; + } - if(flow->detected_protocol_stack[1] == flow->detected_protocol_stack[0]) { *protocol_was_guessed = 1; - flow->detected_protocol_stack[1] = flow->guessed_host_protocol_id; + ndpi_int_change_protocol(ndpi_str, flow, guessed_host_protocol_id, guessed_protocol_id); } } - - if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) && - (flow->guessed_protocol_id == NDPI_PROTOCOL_STUN)) { - check_stun_export: - /* if(flow->protos.tls_quic_stun.stun.num_processed_pkts || flow->protos.tls_quic_stun.stun.num_udp_pkts) */ - { - // if(/* (flow->protos.tls_quic_stun.stun.num_processed_pkts >= NDPI_MIN_NUM_STUN_DETECTION) */ - *protocol_was_guessed = 1; - ndpi_set_detected_protocol(ndpi_str, flow, flow->guessed_host_protocol_id, NDPI_PROTOCOL_STUN); - } + } else if(enable_guess) { + if(flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) { + *protocol_was_guessed = 1; + flow->detected_protocol_stack[1] = flow->guessed_protocol_id; } - ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; + if(flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) { + *protocol_was_guessed = 1; + flow->detected_protocol_stack[0] = flow->guessed_host_protocol_id; + } - if(ret.master_protocol == NDPI_PROTOCOL_STUN) { - if(ret.app_protocol == NDPI_PROTOCOL_FACEBOOK) - ret.app_protocol = NDPI_PROTOCOL_MESSENGER; - else if(ret.app_protocol == NDPI_PROTOCOL_GOOGLE) { - /* - As Google has recently introduced Duo, - we need to distinguish between it and hangout - thing that should be handled by the STUN dissector - */ - ret.app_protocol = NDPI_PROTOCOL_HANGOUT_DUO; - } + if(flow->detected_protocol_stack[1] == flow->detected_protocol_stack[0]) { + *protocol_was_guessed = 1; + flow->detected_protocol_stack[1] = flow->guessed_host_protocol_id; } + } - if(ret.app_protocol != NDPI_PROTOCOL_UNKNOWN) { + if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) && + (flow->guessed_protocol_id == NDPI_PROTOCOL_STUN)) { + check_stun_export: + /* if(flow->protos.tls_quic_stun.stun.num_processed_pkts || flow->protos.tls_quic_stun.stun.num_udp_pkts) */ + { + // if(/* (flow->protos.tls_quic_stun.stun.num_processed_pkts >= NDPI_MIN_NUM_STUN_DETECTION) */ *protocol_was_guessed = 1; - ndpi_fill_protocol_category(ndpi_str, flow, &ret); + ndpi_set_detected_protocol(ndpi_str, flow, flow->guessed_host_protocol_id, NDPI_PROTOCOL_STUN); } + } - return(ret); + ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; + + if(ret.master_protocol == NDPI_PROTOCOL_STUN) { + if(ret.app_protocol == NDPI_PROTOCOL_FACEBOOK) + ret.app_protocol = NDPI_PROTOCOL_MESSENGER; + else if(ret.app_protocol == NDPI_PROTOCOL_GOOGLE) { + /* + As Google has recently introduced Duo, + we need to distinguish between it and hangout + thing that should be handled by the STUN dissector + */ + ret.app_protocol = NDPI_PROTOCOL_HANGOUT_DUO; + } } - /* ********************************************************************************* */ + if(ret.app_protocol != NDPI_PROTOCOL_UNKNOWN) { + *protocol_was_guessed = 1; + ndpi_fill_protocol_category(ndpi_str, flow, &ret); + } - void ndpi_process_extra_packet(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - const unsigned char *packet, const unsigned short packetlen, - const u_int64_t current_time_ms, struct ndpi_id_struct *src, struct ndpi_id_struct *dst) { - if(flow == NULL) - return; + return(ret); +} - if(flow->server_id == NULL) - flow->server_id = dst; /* Default */ +/* ********************************************************************************* */ - /* need at least 20 bytes for ip header */ - if(packetlen < 20) { - return; - } +void ndpi_process_extra_packet(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + const unsigned char *packet, const unsigned short packetlen, + const u_int64_t current_time_ms, struct ndpi_id_struct *src, struct ndpi_id_struct *dst) { + if(flow == NULL) + return; - flow->packet.current_time_ms = current_time_ms; + if(flow->server_id == NULL) + flow->server_id = dst; /* Default */ - /* parse packet */ - flow->packet.iph = (struct ndpi_iphdr *) packet; - /* we are interested in ipv4 packet */ + /* need at least 20 bytes for ip header */ + if(packetlen < 20) { + return; + } - /* set up the packet headers for the extra packet function to use if it wants */ - if(ndpi_init_packet_header(ndpi_str, flow, packetlen) != 0) - return; + flow->packet.current_time_ms = current_time_ms; - /* detect traffic for tcp or udp only */ - flow->src = src, flow->dst = dst; + /* parse packet */ + flow->packet.iph = (struct ndpi_iphdr *) packet; + /* we are interested in ipv4 packet */ - ndpi_connection_tracking(ndpi_str, flow); + /* set up the packet headers for the extra packet function to use if it wants */ + if(ndpi_init_packet_header(ndpi_str, flow, packetlen) != 0) + return; - /* call the extra packet function (which may add more data/info to flow) */ - if(flow->extra_packets_func) { - if((flow->extra_packets_func(ndpi_str, flow)) == 0) - flow->check_extra_packets = 0; + /* detect traffic for tcp or udp only */ + flow->src = src, flow->dst = dst; - if(++flow->num_extra_packets_checked == flow->max_extra_packets_to_check) - flow->extra_packets_func = NULL; /* Enough packets detected */ - } - } + ndpi_connection_tracking(ndpi_str, flow); - /* ********************************************************************************* */ + /* call the extra packet function (which may add more data/info to flow) */ + if(flow->extra_packets_func) { + if((flow->extra_packets_func(ndpi_str, flow)) == 0) + flow->check_extra_packets = 0; - int ndpi_load_ip_category(struct ndpi_detection_module_struct *ndpi_str, const char *ip_address_and_mask, - ndpi_protocol_category_t category) { - ndpi_patricia_node_t *node; - struct in_addr pin; - int bits = 32; - char *ptr; - char ipbuf[64]; + if(++flow->num_extra_packets_checked == flow->max_extra_packets_to_check) + flow->extra_packets_func = NULL; /* Enough packets detected */ + } +} - strncpy(ipbuf, ip_address_and_mask, sizeof(ipbuf)); - ipbuf[sizeof(ipbuf) - 1] = '\0'; +/* ********************************************************************************* */ - ptr = strrchr(ipbuf, '/'); +int ndpi_load_ip_category(struct ndpi_detection_module_struct *ndpi_str, const char *ip_address_and_mask, + ndpi_protocol_category_t category) { + ndpi_patricia_node_t *node; + struct in_addr pin; + int bits = 32; + char *ptr; + char ipbuf[64]; - if(ptr) { - *(ptr++) = '\0'; - if(atoi(ptr) >= 0 && atoi(ptr) <= 32) - bits = atoi(ptr); - } + strncpy(ipbuf, ip_address_and_mask, sizeof(ipbuf)); + ipbuf[sizeof(ipbuf) - 1] = '\0'; - if(inet_pton(AF_INET, ipbuf, &pin) != 1) { - NDPI_LOG_DBG2(ndpi_str, "Invalid ip/ip+netmask: %s\n", ip_address_and_mask); - return(-1); - } + ptr = strrchr(ipbuf, '/'); - if((node = add_to_ptree(ndpi_str->custom_categories.ipAddresses_shadow, AF_INET, &pin, bits)) != NULL) { - node->value.u.uv32.user_value = (u_int16_t)category, node->value.u.uv32.additional_user_value = 0; - } + if(ptr) { + *(ptr++) = '\0'; + if(atoi(ptr) >= 0 && atoi(ptr) <= 32) + bits = atoi(ptr); + } - return(0); + if(inet_pton(AF_INET, ipbuf, &pin) != 1) { + NDPI_LOG_DBG2(ndpi_str, "Invalid ip/ip+netmask: %s\n", ip_address_and_mask); + return(-1); } + if((node = add_to_ptree(ndpi_str->custom_categories.ipAddresses_shadow, AF_INET, &pin, bits)) != NULL) { + node->value.u.uv32.user_value = (u_int16_t)category, node->value.u.uv32.additional_user_value = 0; + } - /* ********************************************************************************* */ + return(0); +} - int ndpi_load_hostname_category(struct ndpi_detection_module_struct *ndpi_str, const char *name_to_add, - ndpi_protocol_category_t category) { - char *name; - u_int len; - AC_PATTERN_t ac_pattern; - AC_ERROR_t rc; - if(name_to_add == NULL) - return(-1); - else - len = strlen(name_to_add); +/* ********************************************************************************* */ - if((name = (char*)ndpi_malloc(len+3)) == NULL) - return(-1); +int ndpi_load_hostname_category(struct ndpi_detection_module_struct *ndpi_str, const char *name_to_add, + ndpi_protocol_category_t category) { + char *name; + u_int len; + AC_PATTERN_t ac_pattern; + AC_ERROR_t rc; - memset(&ac_pattern, 0, sizeof(ac_pattern)); - ac_pattern.length = snprintf(name, len+2, "%s%s", name_to_add, - ndpi_is_middle_string_char(name_to_add[len-1]) ? "" : "$"); + if(name_to_add == NULL) + return(-1); + else + len = strlen(name_to_add); -#if 0 - printf("===> %s() Loading %s as %u\n", __FUNCTION__, name, category); -#endif + if((name = (char*)ndpi_malloc(len+3)) == NULL) + return(-1); - if(ndpi_str->custom_categories.hostnames_shadow.ac_automa == NULL) { - ndpi_free(name); - return(-1); - } + memset(&ac_pattern, 0, sizeof(ac_pattern)); + ac_pattern.length = snprintf(name, len+2, "%s%s", name_to_add, + ndpi_is_middle_string_char(name_to_add[len-1]) ? "" : "$"); - ac_pattern.astring = name; - ac_pattern.rep.number = (u_int32_t) category, ac_pattern.rep.category = category; +#if 0 + printf("===> %s() Loading %s as %u\n", __FUNCTION__, name, category); +#endif - rc = ac_automata_add(ndpi_str->custom_categories.hostnames_shadow.ac_automa, &ac_pattern); - if(rc != ACERR_DUPLICATE_PATTERN && rc != ACERR_SUCCESS) { - ndpi_free(name); - return(-1); - } + if(ndpi_str->custom_categories.hostnames_shadow.ac_automa == NULL) { + ndpi_free(name); + return(-1); + } - if(rc == ACERR_DUPLICATE_PATTERN) - ndpi_free(name); + ac_pattern.astring = name; + ac_pattern.rep.number = (u_int32_t) category, ac_pattern.rep.category = category; - return(0); + rc = ac_automata_add(ndpi_str->custom_categories.hostnames_shadow.ac_automa, &ac_pattern); + if(rc != ACERR_DUPLICATE_PATTERN && rc != ACERR_SUCCESS) { + ndpi_free(name); + return(-1); } - /* ********************************************************************************* */ + if(rc == ACERR_DUPLICATE_PATTERN) + ndpi_free(name); - /* Loads an IP or name category */ - int ndpi_load_category(struct ndpi_detection_module_struct *ndpi_struct, const char *ip_or_name, - ndpi_protocol_category_t category) { - int rv; + return(0); +} - /* Try to load as IP address first */ - rv = ndpi_load_ip_category(ndpi_struct, ip_or_name, category); +/* ********************************************************************************* */ - if(rv < 0) { - /* IP load failed, load as hostname */ - rv = ndpi_load_hostname_category(ndpi_struct, ip_or_name, category); - } +/* Loads an IP or name category */ +int ndpi_load_category(struct ndpi_detection_module_struct *ndpi_struct, const char *ip_or_name, + ndpi_protocol_category_t category) { + int rv; - return(rv); - } + /* Try to load as IP address first */ + rv = ndpi_load_ip_category(ndpi_struct, ip_or_name, category); - /* ********************************************************************************* */ + if(rv < 0) { + /* IP load failed, load as hostname */ + rv = ndpi_load_hostname_category(ndpi_struct, ip_or_name, category); + } - int ndpi_enable_loaded_categories(struct ndpi_detection_module_struct *ndpi_str) { - int i; + return(rv); +} - /* First add the nDPI known categories matches */ - for(i = 0; category_match[i].string_to_match != NULL; i++) - ndpi_load_category(ndpi_str, category_match[i].string_to_match, category_match[i].protocol_category); +/* ********************************************************************************* */ - /* Free */ - ac_automata_release((AC_AUTOMATA_t *) ndpi_str->custom_categories.hostnames.ac_automa, - 1 /* free patterns strings memory */); +int ndpi_enable_loaded_categories(struct ndpi_detection_module_struct *ndpi_str) { + int i; - /* Finalize */ - ac_automata_finalize((AC_AUTOMATA_t *) ndpi_str->custom_categories.hostnames_shadow.ac_automa); + /* First add the nDPI known categories matches */ + for(i = 0; category_match[i].string_to_match != NULL; i++) + ndpi_load_category(ndpi_str, category_match[i].string_to_match, category_match[i].protocol_category); - /* Swap */ - ndpi_str->custom_categories.hostnames.ac_automa = ndpi_str->custom_categories.hostnames_shadow.ac_automa; + /* Free */ + ac_automata_release((AC_AUTOMATA_t *) ndpi_str->custom_categories.hostnames.ac_automa, + 1 /* free patterns strings memory */); - /* Realloc */ - ndpi_str->custom_categories.hostnames_shadow.ac_automa = ac_automata_init(ac_match_handler); + /* Finalize */ + ac_automata_finalize((AC_AUTOMATA_t *) ndpi_str->custom_categories.hostnames_shadow.ac_automa); - if(ndpi_str->custom_categories.ipAddresses != NULL) - ndpi_patricia_destroy((ndpi_patricia_tree_t *) ndpi_str->custom_categories.ipAddresses, free_ptree_data); + /* Swap */ + ndpi_str->custom_categories.hostnames.ac_automa = ndpi_str->custom_categories.hostnames_shadow.ac_automa; - ndpi_str->custom_categories.ipAddresses = ndpi_str->custom_categories.ipAddresses_shadow; - ndpi_str->custom_categories.ipAddresses_shadow = ndpi_patricia_new(32 /* IPv4 */); + /* Realloc */ + ndpi_str->custom_categories.hostnames_shadow.ac_automa = ac_automata_init(ac_match_handler); - ndpi_str->custom_categories.categories_loaded = 1; + if(ndpi_str->custom_categories.ipAddresses != NULL) + ndpi_patricia_destroy((ndpi_patricia_tree_t *) ndpi_str->custom_categories.ipAddresses, free_ptree_data); - return(0); - } + ndpi_str->custom_categories.ipAddresses = ndpi_str->custom_categories.ipAddresses_shadow; + ndpi_str->custom_categories.ipAddresses_shadow = ndpi_patricia_new(32 /* IPv4 */); - /* ********************************************************************************* */ + ndpi_str->custom_categories.categories_loaded = 1; - int ndpi_fill_ip_protocol_category(struct ndpi_detection_module_struct *ndpi_str, u_int32_t saddr, u_int32_t daddr, - ndpi_protocol *ret) { - if(ndpi_str->custom_categories.categories_loaded) { - ndpi_prefix_t prefix; - ndpi_patricia_node_t *node; + return(0); +} - if(saddr == 0) - node = NULL; - else { - /* Make sure all in network byte order otherwise compares wont work */ - ndpi_fill_prefix_v4(&prefix, (struct in_addr *) &saddr, 32, - ((ndpi_patricia_tree_t *) ndpi_str->protocols_ptree)->maxbits); - node = ndpi_patricia_search_best(ndpi_str->custom_categories.ipAddresses, &prefix); - } +/* ********************************************************************************* */ - if(!node) { - if(daddr != 0) { - ndpi_fill_prefix_v4(&prefix, (struct in_addr *) &daddr, 32, - ((ndpi_patricia_tree_t *) ndpi_str->protocols_ptree)->maxbits); - node = ndpi_patricia_search_best(ndpi_str->custom_categories.ipAddresses, &prefix); - } - } +int ndpi_fill_ip_protocol_category(struct ndpi_detection_module_struct *ndpi_str, u_int32_t saddr, u_int32_t daddr, + ndpi_protocol *ret) { + if(ndpi_str->custom_categories.categories_loaded) { + ndpi_prefix_t prefix; + ndpi_patricia_node_t *node; - if(node) { - ret->category = (ndpi_protocol_category_t) node->value.u.uv32.user_value; + if(saddr == 0) + node = NULL; + else { + /* Make sure all in network byte order otherwise compares wont work */ + ndpi_fill_prefix_v4(&prefix, (struct in_addr *) &saddr, 32, + ((ndpi_patricia_tree_t *) ndpi_str->protocols_ptree)->maxbits); + node = ndpi_patricia_search_best(ndpi_str->custom_categories.ipAddresses, &prefix); + } - return(1); + if(!node) { + if(daddr != 0) { + ndpi_fill_prefix_v4(&prefix, (struct in_addr *) &daddr, 32, + ((ndpi_patricia_tree_t *) ndpi_str->protocols_ptree)->maxbits); + node = ndpi_patricia_search_best(ndpi_str->custom_categories.ipAddresses, &prefix); } } - ret->category = ndpi_get_proto_category(ndpi_str, *ret); + if(node) { + ret->category = (ndpi_protocol_category_t) node->value.u.uv32.user_value; - return(0); + return(1); + } } - /* ********************************************************************************* */ + ret->category = ndpi_get_proto_category(ndpi_str, *ret); - void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - ndpi_protocol *ret) { - if((ret->master_protocol == NDPI_PROTOCOL_UNKNOWN) && (ret->app_protocol == NDPI_PROTOCOL_UNKNOWN)) - return; + return(0); +} - if(ndpi_str->custom_categories.categories_loaded) { - if(flow->guessed_header_category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) { - flow->category = ret->category = flow->guessed_header_category; - return; - } +/* ********************************************************************************* */ - if(flow->host_server_name[0] != '\0') { - u_int32_t id; - int rc = ndpi_match_custom_category(ndpi_str, (char *) flow->host_server_name, - strlen((char *) flow->host_server_name), &id); +void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + ndpi_protocol *ret) { + if((ret->master_protocol == NDPI_PROTOCOL_UNKNOWN) && (ret->app_protocol == NDPI_PROTOCOL_UNKNOWN)) + return; - if(rc == 0) { - flow->category = ret->category = (ndpi_protocol_category_t) id; - return; - } - } + if(ndpi_str->custom_categories.categories_loaded) { + if(flow->guessed_header_category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) { + flow->category = ret->category = flow->guessed_header_category; + return; + } - if(flow->l4.tcp.tls.hello_processed == 1 && - flow->protos.tls_quic_stun.tls_quic.client_requested_server_name[0] != '\0') { - u_int32_t id; - int rc = ndpi_match_custom_category(ndpi_str, (char *) flow->protos.tls_quic_stun.tls_quic.client_requested_server_name, - strlen(flow->protos.tls_quic_stun.tls_quic.client_requested_server_name), &id); + if(flow->host_server_name[0] != '\0') { + u_int32_t id; + int rc = ndpi_match_custom_category(ndpi_str, (char *) flow->host_server_name, + strlen((char *) flow->host_server_name), &id); - if(rc == 0) { - flow->category = ret->category = (ndpi_protocol_category_t) id; - return; - } + if(rc == 0) { + flow->category = ret->category = (ndpi_protocol_category_t) id; + return; } } - flow->category = ret->category = ndpi_get_proto_category(ndpi_str, *ret); + if(flow->l4.tcp.tls.hello_processed == 1 && + flow->protos.tls_quic_stun.tls_quic.client_requested_server_name[0] != '\0') { + u_int32_t id; + int rc = ndpi_match_custom_category(ndpi_str, (char *) flow->protos.tls_quic_stun.tls_quic.client_requested_server_name, + strlen(flow->protos.tls_quic_stun.tls_quic.client_requested_server_name), &id); + + if(rc == 0) { + flow->category = ret->category = (ndpi_protocol_category_t) id; + return; + } + } } - /* ********************************************************************************* */ + flow->category = ret->category = ndpi_get_proto_category(ndpi_str, *ret); +} - static void ndpi_reset_packet_line_info(struct ndpi_packet_struct *packet) { - packet->parsed_lines = 0, packet->empty_line_position_set = 0, packet->host_line.ptr = NULL, - packet->host_line.len = 0, packet->referer_line.ptr = NULL, packet->referer_line.len = 0, - packet->content_line.ptr = NULL, packet->content_line.len = 0, packet->accept_line.ptr = NULL, - packet->accept_line.len = 0, packet->user_agent_line.ptr = NULL, packet->user_agent_line.len = 0, - packet->http_url_name.ptr = NULL, packet->http_url_name.len = 0, packet->http_encoding.ptr = NULL, - packet->http_encoding.len = 0, packet->http_transfer_encoding.ptr = NULL, packet->http_transfer_encoding.len = 0, - packet->http_contentlen.ptr = NULL, packet->http_contentlen.len = 0, packet->content_disposition_line.ptr = NULL, - packet->content_disposition_line.len = 0, packet->http_cookie.ptr = NULL, - packet->http_cookie.len = 0, packet->http_origin.len = 0, packet->http_origin.ptr = NULL, - packet->http_x_session_type.ptr = NULL, packet->http_x_session_type.len = 0, packet->server_line.ptr = NULL, - packet->server_line.len = 0, packet->http_method.ptr = NULL, packet->http_method.len = 0, - packet->http_response.ptr = NULL, packet->http_response.len = 0, packet->http_num_headers = 0, - packet->forwarded_line.ptr = NULL, packet->forwarded_line.len = 0; - } +/* ********************************************************************************* */ + +static void ndpi_reset_packet_line_info(struct ndpi_packet_struct *packet) { + packet->parsed_lines = 0, packet->empty_line_position_set = 0, packet->host_line.ptr = NULL, + packet->host_line.len = 0, packet->referer_line.ptr = NULL, packet->referer_line.len = 0, + packet->content_line.ptr = NULL, packet->content_line.len = 0, packet->accept_line.ptr = NULL, + packet->accept_line.len = 0, packet->user_agent_line.ptr = NULL, packet->user_agent_line.len = 0, + packet->http_url_name.ptr = NULL, packet->http_url_name.len = 0, packet->http_encoding.ptr = NULL, + packet->http_encoding.len = 0, packet->http_transfer_encoding.ptr = NULL, packet->http_transfer_encoding.len = 0, + packet->http_contentlen.ptr = NULL, packet->http_contentlen.len = 0, packet->content_disposition_line.ptr = NULL, + packet->content_disposition_line.len = 0, packet->http_cookie.ptr = NULL, + packet->http_cookie.len = 0, packet->http_origin.len = 0, packet->http_origin.ptr = NULL, + packet->http_x_session_type.ptr = NULL, packet->http_x_session_type.len = 0, packet->server_line.ptr = NULL, + packet->server_line.len = 0, packet->http_method.ptr = NULL, packet->http_method.len = 0, + packet->http_response.ptr = NULL, packet->http_response.len = 0, packet->http_num_headers = 0, + packet->forwarded_line.ptr = NULL, packet->forwarded_line.len = 0; +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - static int ndpi_is_ntop_protocol(ndpi_protocol *ret) { - if((ret->master_protocol == NDPI_PROTOCOL_HTTP) && (ret->app_protocol == NDPI_PROTOCOL_NTOP)) - return(1); - else - return(0); - } +static int ndpi_is_ntop_protocol(ndpi_protocol *ret) { + if((ret->master_protocol == NDPI_PROTOCOL_HTTP) && (ret->app_protocol == NDPI_PROTOCOL_NTOP)) + return(1); + else + return(0); +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - static int ndpi_check_protocol_port_mismatch_exceptions(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, - ndpi_default_ports_tree_node_t *expected_proto, - ndpi_protocol *returned_proto) { - /* - For TLS (and other protocols) it is not simple to guess the exact protocol so before - triggering an alert we need to make sure what we have exhausted all the possible - options available - */ +static int ndpi_check_protocol_port_mismatch_exceptions(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + ndpi_default_ports_tree_node_t *expected_proto, + ndpi_protocol *returned_proto) { + /* + For TLS (and other protocols) it is not simple to guess the exact protocol so before + triggering an alert we need to make sure what we have exhausted all the possible + options available + */ - if(ndpi_is_ntop_protocol(returned_proto)) return(1); + if(ndpi_is_ntop_protocol(returned_proto)) return(1); - if(returned_proto->master_protocol == NDPI_PROTOCOL_TLS) { - switch(expected_proto->proto->protoId) { - case NDPI_PROTOCOL_MAIL_IMAPS: - case NDPI_PROTOCOL_MAIL_POPS: - case NDPI_PROTOCOL_MAIL_SMTPS: - return(1); /* This is a reasonable exception */ - break; - } + if(returned_proto->master_protocol == NDPI_PROTOCOL_TLS) { + switch(expected_proto->proto->protoId) { + case NDPI_PROTOCOL_MAIL_IMAPS: + case NDPI_PROTOCOL_MAIL_POPS: + case NDPI_PROTOCOL_MAIL_SMTPS: + return(1); /* This is a reasonable exception */ + break; } - - return(0); } - /* ********************************************************************************* */ + return(0); +} - static void ndpi_reconcile_protocols(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, - ndpi_protocol *ret) { +/* ********************************************************************************* */ + +static void ndpi_reconcile_protocols(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + ndpi_protocol *ret) { #if 0 - if(flow) { - /* Do not go for DNS when there is an application protocol. Example DNS.Apple */ - if((flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) - && (flow->detected_protocol_stack[0] /* app */ != flow->detected_protocol_stack[1] /* major */)) - NDPI_CLR_BIT(flow->risk, NDPI_SUSPICIOUS_DGA_DOMAIN); - } + if(flow) { + /* Do not go for DNS when there is an application protocol. Example DNS.Apple */ + if((flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) + && (flow->detected_protocol_stack[0] /* app */ != flow->detected_protocol_stack[1] /* major */)) + NDPI_CLR_BIT(flow->risk, NDPI_SUSPICIOUS_DGA_DOMAIN); + } #endif - // printf("====>> %u.%u [%u]\n", ret->master_protocol, ret->app_protocol, flow->detected_protocol_stack[0]); + // printf("====>> %u.%u [%u]\n", ret->master_protocol, ret->app_protocol, flow->detected_protocol_stack[0]); - switch(ret->app_protocol) { - /* + switch(ret->app_protocol) { + /* Skype for a host doing MS Teams means MS Teams (MS Teams uses Skype as transport protocol for voice/video) */ - case NDPI_PROTOCOL_MSTEAMS: - if(flow->packet.iph && flow->packet.tcp) { - // printf("====>> NDPI_PROTOCOL_MSTEAMS\n"); + case NDPI_PROTOCOL_MSTEAMS: + if(flow->packet.iph && flow->packet.tcp) { + // printf("====>> NDPI_PROTOCOL_MSTEAMS\n"); + + if(ndpi_str->msteams_cache == NULL) + ndpi_str->msteams_cache = ndpi_lru_cache_init(1024); + + if(ndpi_str->msteams_cache) + ndpi_lru_add_to_cache(ndpi_str->msteams_cache, + flow->packet.iph->saddr, + (flow->packet.current_time_ms / 1000) & 0xFFFF /* 16 bit */); + } + break; + + case NDPI_PROTOCOL_SKYPE: + case NDPI_PROTOCOL_SKYPE_CALL: + if(flow->packet.iph + && flow->packet.udp + && ndpi_str->msteams_cache) { + u_int16_t when; - if(ndpi_str->msteams_cache == NULL) - ndpi_str->msteams_cache = ndpi_lru_cache_init(1024); + if(ndpi_lru_find_cache(ndpi_str->msteams_cache, flow->packet.iph->saddr, + &when, 0 /* Don't remove it as it can be used for other connections */)) { + u_int16_t tdiff = ((flow->packet.current_time_ms /1000) & 0xFFFF) - when; - if(ndpi_str->msteams_cache) + if(tdiff < 60 /* sec */) { + // printf("====>> NDPI_PROTOCOL_SKYPE(_CALL) -> NDPI_PROTOCOL_MSTEAMS [%u]\n", tdiff); + ret->app_protocol = NDPI_PROTOCOL_MSTEAMS; + + /* Refresh cache */ ndpi_lru_add_to_cache(ndpi_str->msteams_cache, flow->packet.iph->saddr, (flow->packet.current_time_ms / 1000) & 0xFFFF /* 16 bit */); - } - break; - - case NDPI_PROTOCOL_SKYPE: - case NDPI_PROTOCOL_SKYPE_CALL: - if(flow->packet.iph - && flow->packet.udp - && ndpi_str->msteams_cache) { - u_int16_t when; - - if(ndpi_lru_find_cache(ndpi_str->msteams_cache, flow->packet.iph->saddr, - &when, 0 /* Don't remove it as it can be used for other connections */)) { - u_int16_t tdiff = ((flow->packet.current_time_ms /1000) & 0xFFFF) - when; - - if(tdiff < 60 /* sec */) { - // printf("====>> NDPI_PROTOCOL_SKYPE(_CALL) -> NDPI_PROTOCOL_MSTEAMS [%u]\n", tdiff); - ret->app_protocol = NDPI_PROTOCOL_MSTEAMS; - - /* Refresh cache */ - ndpi_lru_add_to_cache(ndpi_str->msteams_cache, - flow->packet.iph->saddr, - (flow->packet.current_time_ms / 1000) & 0xFFFF /* 16 bit */); - } } } - break; + } + break; - case NDPI_PROTOCOL_ANYDESK: - if(flow->packet.tcp) /* TCP only */ - ndpi_set_risk(flow, NDPI_DESKTOP_OR_FILE_SHARING_SESSION); /* Remote assistance */ + case NDPI_PROTOCOL_ANYDESK: + if(flow->packet.tcp) /* TCP only */ + ndpi_set_risk(flow, NDPI_DESKTOP_OR_FILE_SHARING_SESSION); /* Remote assistance */ + break; + } /* switch */ + + if(flow) { + switch(ndpi_get_proto_breed(ndpi_str, ret->app_protocol)) { + case NDPI_PROTOCOL_UNSAFE: + case NDPI_PROTOCOL_POTENTIALLY_DANGEROUS: + case NDPI_PROTOCOL_DANGEROUS: + ndpi_set_risk(flow, NDPI_UNSAFE_PROTOCOL); + break; + default: + /* Nothing to do */ break; - } /* switch */ - - if(flow) { - switch(ndpi_get_proto_breed(ndpi_str, ret->app_protocol)) { - case NDPI_PROTOCOL_UNSAFE: - case NDPI_PROTOCOL_POTENTIALLY_DANGEROUS: - case NDPI_PROTOCOL_DANGEROUS: - ndpi_set_risk(flow, NDPI_UNSAFE_PROTOCOL); - break; - default: - /* Nothing to do */ - break; - } } - } - /* ****************************************************** */ +} - static int ndpi_do_guess(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, ndpi_protocol *ret) { - ret->master_protocol = ret->app_protocol = NDPI_PROTOCOL_UNKNOWN, ret->category = 0; +/* ****************************************************** */ - if(flow->packet.iphv6 || flow->packet.iph) { - u_int16_t sport, dport; - u_int8_t protocol; - u_int8_t user_defined_proto; +static int ndpi_do_guess(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, ndpi_protocol *ret) { + ret->master_protocol = ret->app_protocol = NDPI_PROTOCOL_UNKNOWN, ret->category = 0; - if(flow->packet.iphv6 != NULL) { - protocol = flow->packet.iphv6->ip6_hdr.ip6_un1_nxt; - } else - protocol = flow->packet.iph->protocol; + if(flow->packet.iphv6 || flow->packet.iph) { + u_int16_t sport, dport; + u_int8_t protocol; + u_int8_t user_defined_proto; - if(flow->packet.udp) - sport = ntohs(flow->packet.udp->source), dport = ntohs(flow->packet.udp->dest); - else if(flow->packet.tcp) - sport = ntohs(flow->packet.tcp->source), dport = ntohs(flow->packet.tcp->dest); - else - sport = dport = 0; + if(flow->packet.iphv6 != NULL) { + protocol = flow->packet.iphv6->ip6_hdr.ip6_un1_nxt; + } else + protocol = flow->packet.iph->protocol; - /* guess protocol */ - flow->guessed_protocol_id = (int16_t) ndpi_guess_protocol_id(ndpi_str, flow, protocol, sport, dport, &user_defined_proto); - flow->guessed_host_protocol_id = ndpi_guess_host_protocol_id(ndpi_str, flow); + if(flow->packet.udp) + sport = ntohs(flow->packet.udp->source), dport = ntohs(flow->packet.udp->dest); + else if(flow->packet.tcp) + sport = ntohs(flow->packet.tcp->source), dport = ntohs(flow->packet.tcp->dest); + else + sport = dport = 0; - if(ndpi_str->custom_categories.categories_loaded && flow->packet.iph) { - if(ndpi_str->ndpi_num_custom_protocols != 0) - ndpi_fill_ip_protocol_category(ndpi_str, flow->packet.iph->saddr, flow->packet.iph->daddr, ret); - flow->guessed_header_category = ret->category; - } else - flow->guessed_header_category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED; + /* guess protocol */ + flow->guessed_protocol_id = (int16_t) ndpi_guess_protocol_id(ndpi_str, flow, protocol, sport, dport, &user_defined_proto); + flow->guessed_host_protocol_id = ndpi_guess_host_protocol_id(ndpi_str, flow); - if(flow->guessed_protocol_id >= NDPI_MAX_SUPPORTED_PROTOCOLS) { - /* This is a custom protocol and it has priority over everything else */ - ret->master_protocol = NDPI_PROTOCOL_UNKNOWN, - ret->app_protocol = flow->guessed_protocol_id ? flow->guessed_protocol_id : flow->guessed_host_protocol_id; + if(ndpi_str->custom_categories.categories_loaded && flow->packet.iph) { + if(ndpi_str->ndpi_num_custom_protocols != 0) + ndpi_fill_ip_protocol_category(ndpi_str, flow->packet.iph->saddr, flow->packet.iph->daddr, ret); + flow->guessed_header_category = ret->category; + } else + flow->guessed_header_category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED; - // if(ndpi_str->ndpi_num_custom_protocols != 0) - ndpi_fill_protocol_category(ndpi_str, flow, ret); - return(-1); - } + if(flow->guessed_protocol_id >= NDPI_MAX_SUPPORTED_PROTOCOLS) { + /* This is a custom protocol and it has priority over everything else */ + ret->master_protocol = NDPI_PROTOCOL_UNKNOWN, + ret->app_protocol = flow->guessed_protocol_id ? flow->guessed_protocol_id : flow->guessed_host_protocol_id; - if(user_defined_proto && flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) { - if(flow->packet.iph) { - if(flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) { - u_int8_t protocol_was_guessed; + // if(ndpi_str->ndpi_num_custom_protocols != 0) + ndpi_fill_protocol_category(ndpi_str, flow, ret); + return(-1); + } - /* ret->master_protocol = flow->guessed_protocol_id , ret->app_protocol = flow->guessed_host_protocol_id; /\* ****** *\/ */ - *ret = ndpi_detection_giveup(ndpi_str, flow, 0, &protocol_was_guessed); - } + if(user_defined_proto && flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) { + if(flow->packet.iph) { + if(flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) { + u_int8_t protocol_was_guessed; - // if(ndpi_str->ndpi_num_custom_protocols != 0) - ndpi_fill_protocol_category(ndpi_str, flow, ret); - return(-1); + /* ret->master_protocol = flow->guessed_protocol_id , ret->app_protocol = flow->guessed_host_protocol_id; /\* ****** *\/ */ + *ret = ndpi_detection_giveup(ndpi_str, flow, 0, &protocol_was_guessed); } - } else { - /* guess host protocol */ - if(flow->packet.iph) { - flow->guessed_host_protocol_id = ndpi_guess_host_protocol_id(ndpi_str, flow); - /* - We could implement a shortcut here skipping dissectors for - protocols we have identified by other means such as with the IP + // if(ndpi_str->ndpi_num_custom_protocols != 0) + ndpi_fill_protocol_category(ndpi_str, flow, ret); + return(-1); + } + } else { + /* guess host protocol */ + if(flow->packet.iph) { + flow->guessed_host_protocol_id = ndpi_guess_host_protocol_id(ndpi_str, flow); - However we do NOT stop here and skip invoking the dissectors - because we want to dissect the flow (e.g. dissect the TLS) - and extract metadata. - */ + /* + We could implement a shortcut here skipping dissectors for + protocols we have identified by other means such as with the IP + + However we do NOT stop here and skip invoking the dissectors + because we want to dissect the flow (e.g. dissect the TLS) + and extract metadata. + */ #if SKIP_INVOKING_THE_DISSECTORS - if(flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) { - /* - We have identified a protocol using the IP address so - it is not worth to dissect the traffic as we already have - the solution - */ - ret->master_protocol = flow->guessed_protocol_id, ret->app_protocol = flow->guessed_host_protocol_id; - } -#endif + if(flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) { + /* + We have identified a protocol using the IP address so + it is not worth to dissect the traffic as we already have + the solution + */ + ret->master_protocol = flow->guessed_protocol_id, ret->app_protocol = flow->guessed_host_protocol_id; } +#endif } } + } - if(flow->guessed_host_protocol_id >= NDPI_MAX_SUPPORTED_PROTOCOLS) { - //u_int32_t num_calls; - NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_packet; - - /* This is a custom protocol and it has priority over everything else */ - ret->master_protocol = flow->guessed_protocol_id, ret->app_protocol = flow->guessed_host_protocol_id; + if(flow->guessed_host_protocol_id >= NDPI_MAX_SUPPORTED_PROTOCOLS) { + //u_int32_t num_calls; + NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_packet; - //num_calls = - ndpi_check_flow_func(ndpi_str, flow, &ndpi_selection_packet); + /* This is a custom protocol and it has priority over everything else */ + ret->master_protocol = flow->guessed_protocol_id, ret->app_protocol = flow->guessed_host_protocol_id; - //if(ndpi_str->ndpi_num_custom_protocols != 0) - ndpi_fill_protocol_category(ndpi_str, flow, ret); - return(-1); - } + //num_calls = + ndpi_check_flow_func(ndpi_str, flow, &ndpi_selection_packet); - return(0); + //if(ndpi_str->ndpi_num_custom_protocols != 0) + ndpi_fill_protocol_category(ndpi_str, flow, ret); + return(-1); } - /* ********************************************************************************* */ + return(0); +} - ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, const unsigned char *packet, - const unsigned short packetlen, const u_int64_t current_time_ms, - struct ndpi_id_struct *src, struct ndpi_id_struct *dst) { - NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_packet; - u_int32_t a, num_calls = 0; - ndpi_protocol ret = { flow->detected_protocol_stack[1], flow->detected_protocol_stack[0], flow->category }; +/* ********************************************************************************* */ - if(ndpi_str->ndpi_log_level >= NDPI_LOG_TRACE) - NDPI_LOG(flow ? flow->detected_protocol_stack[0] : NDPI_PROTOCOL_UNKNOWN, ndpi_str, NDPI_LOG_TRACE, - "START packet processing\n"); +ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, const unsigned char *packet, + const unsigned short packetlen, const u_int64_t current_time_ms, + struct ndpi_id_struct *src, struct ndpi_id_struct *dst) { + NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_packet; + u_int32_t a, num_calls = 0; + ndpi_protocol ret = { flow->detected_protocol_stack[1], flow->detected_protocol_stack[0], flow->category }; - if(flow == NULL) - return(ret); - else - ret.category = flow->category; + if(ndpi_str->ndpi_log_level >= NDPI_LOG_TRACE) + NDPI_LOG(flow ? flow->detected_protocol_stack[0] : NDPI_PROTOCOL_UNKNOWN, ndpi_str, NDPI_LOG_TRACE, + "START packet processing\n"); - if(flow->fail_with_unknown) { - // printf("%s(): FAIL_WITH_UNKNOWN\n", __FUNCTION__); - return(ret); - } + if(flow == NULL) + return(ret); + else + ret.category = flow->category; - flow->num_processed_pkts++; + if(flow->fail_with_unknown) { + // printf("%s(): FAIL_WITH_UNKNOWN\n", __FUNCTION__); + return(ret); + } - /* Init default */ - ret.master_protocol = flow->detected_protocol_stack[1], - ret.app_protocol = flow->detected_protocol_stack[0]; + flow->num_processed_pkts++; - if(flow->server_id == NULL) - flow->server_id = dst; /* Default */ + /* Init default */ + ret.master_protocol = flow->detected_protocol_stack[1], + ret.app_protocol = flow->detected_protocol_stack[0]; - if(flow->check_extra_packets) { - ndpi_process_extra_packet(ndpi_str, flow, packet, packetlen, current_time_ms, src, dst); - /* Update in case of new match */ - ret.master_protocol = flow->detected_protocol_stack[1], - ret.app_protocol = flow->detected_protocol_stack[0], - ret.category = flow->category; - goto invalidate_ptr; - } else if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) - goto ret_protocols; + if(flow->server_id == NULL) + flow->server_id = dst; /* Default */ - /* need at least 20 bytes for ip header */ - if(packetlen < 20) { - /* reset protocol which is normally done in init_packet_header */ - ndpi_int_reset_packet_protocol(&flow->packet); - goto invalidate_ptr; - } + if(flow->check_extra_packets) { + ndpi_process_extra_packet(ndpi_str, flow, packet, packetlen, current_time_ms, src, dst); + /* Update in case of new match */ + ret.master_protocol = flow->detected_protocol_stack[1], + ret.app_protocol = flow->detected_protocol_stack[0], + ret.category = flow->category; + goto invalidate_ptr; + } else if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) + goto ret_protocols; - flow->packet.current_time_ms = current_time_ms; + /* need at least 20 bytes for ip header */ + if(packetlen < 20) { + /* reset protocol which is normally done in init_packet_header */ + ndpi_int_reset_packet_protocol(&flow->packet); + goto invalidate_ptr; + } - /* parse packet */ - flow->packet.iph = (struct ndpi_iphdr *) packet; - /* we are interested in ipv4 packet */ + flow->packet.current_time_ms = current_time_ms; - if(ndpi_init_packet_header(ndpi_str, flow, packetlen) != 0) - goto invalidate_ptr; + /* parse packet */ + flow->packet.iph = (struct ndpi_iphdr *) packet; + /* we are interested in ipv4 packet */ - /* detect traffic for tcp or udp only */ - flow->src = src, flow->dst = dst; + if(ndpi_init_packet_header(ndpi_str, flow, packetlen) != 0) + goto invalidate_ptr; - ndpi_connection_tracking(ndpi_str, flow); + /* detect traffic for tcp or udp only */ + flow->src = src, flow->dst = dst; - /* build ndpi_selection packet bitmask */ - ndpi_selection_packet = NDPI_SELECTION_BITMASK_PROTOCOL_COMPLETE_TRAFFIC; - if(flow->packet.iph != NULL) - ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_IP | NDPI_SELECTION_BITMASK_PROTOCOL_IPV4_OR_IPV6; + ndpi_connection_tracking(ndpi_str, flow); - if(flow->packet.tcp != NULL) - ndpi_selection_packet |= - (NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP); + /* build ndpi_selection packet bitmask */ + ndpi_selection_packet = NDPI_SELECTION_BITMASK_PROTOCOL_COMPLETE_TRAFFIC; + if(flow->packet.iph != NULL) + ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_IP | NDPI_SELECTION_BITMASK_PROTOCOL_IPV4_OR_IPV6; - if(flow->packet.udp != NULL) - ndpi_selection_packet |= - (NDPI_SELECTION_BITMASK_PROTOCOL_INT_UDP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP); + if(flow->packet.tcp != NULL) + ndpi_selection_packet |= + (NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP); - if(flow->packet.payload_packet_len != 0) - ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_HAS_PAYLOAD; + if(flow->packet.udp != NULL) + ndpi_selection_packet |= + (NDPI_SELECTION_BITMASK_PROTOCOL_INT_UDP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP); - if(flow->packet.tcp_retransmission == 0) - ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_NO_TCP_RETRANSMISSION; + if(flow->packet.payload_packet_len != 0) + ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_HAS_PAYLOAD; - if(flow->packet.iphv6 != NULL) - ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_IPV6 | NDPI_SELECTION_BITMASK_PROTOCOL_IPV4_OR_IPV6; + if(flow->packet.tcp_retransmission == 0) + ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_NO_TCP_RETRANSMISSION; - if(!flow->protocol_id_already_guessed) { - flow->protocol_id_already_guessed = 1; + if(flow->packet.iphv6 != NULL) + ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_IPV6 | NDPI_SELECTION_BITMASK_PROTOCOL_IPV4_OR_IPV6; - if(ndpi_do_guess(ndpi_str, flow, &ret) == -1) - goto invalidate_ptr; - } + if(!flow->protocol_id_already_guessed) { + flow->protocol_id_already_guessed = 1; - num_calls = ndpi_check_flow_func(ndpi_str, flow, &ndpi_selection_packet); + if(ndpi_do_guess(ndpi_str, flow, &ret) == -1) + goto invalidate_ptr; + } - a = flow->packet.detected_protocol_stack[0]; - if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_str->detection_bitmask, a) == 0) - a = NDPI_PROTOCOL_UNKNOWN; + num_calls = ndpi_check_flow_func(ndpi_str, flow, &ndpi_selection_packet); - if(a != NDPI_PROTOCOL_UNKNOWN) { - int i; + a = flow->packet.detected_protocol_stack[0]; + if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_str->detection_bitmask, a) == 0) + a = NDPI_PROTOCOL_UNKNOWN; - for(i = 0; i < sizeof(flow->host_server_name); i++) { - if(flow->host_server_name[i] != '\0') - flow->host_server_name[i] = tolower(flow->host_server_name[i]); - else { - flow->host_server_name[i] = '\0'; - break; - } + if(a != NDPI_PROTOCOL_UNKNOWN) { + int i; + + for(i = 0; i < sizeof(flow->host_server_name); i++) { + if(flow->host_server_name[i] != '\0') + flow->host_server_name[i] = tolower(flow->host_server_name[i]); + else { + flow->host_server_name[i] = '\0'; + break; } } + } - ret_protocols: - if(flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) { - ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; - - if(ret.app_protocol == ret.master_protocol) - ret.master_protocol = NDPI_PROTOCOL_UNKNOWN; - } else - ret.app_protocol = flow->detected_protocol_stack[0]; - - /* Don't overwrite the category if already set */ - if((flow->category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) && (ret.app_protocol != NDPI_PROTOCOL_UNKNOWN)) - ndpi_fill_protocol_category(ndpi_str, flow, &ret); - else - ret.category = flow->category; - - if((flow->num_processed_pkts == 1) && (ret.master_protocol == NDPI_PROTOCOL_UNKNOWN) && - (ret.app_protocol == NDPI_PROTOCOL_UNKNOWN) && flow->packet.tcp && (flow->packet.tcp->syn == 0) && - (flow->guessed_protocol_id == 0)) { - u_int8_t protocol_was_guessed; - - /* - This is a TCP flow - - whose first packet is NOT a SYN - - no protocol has been detected + ret_protocols: + if(flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) { + ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; - We don't see how future packets can match anything - hence we giveup here - */ - ret = ndpi_detection_giveup(ndpi_str, flow, 0, &protocol_was_guessed); - } + if(ret.app_protocol == ret.master_protocol) + ret.master_protocol = NDPI_PROTOCOL_UNKNOWN; + } else + ret.app_protocol = flow->detected_protocol_stack[0]; - if((ret.master_protocol == NDPI_PROTOCOL_UNKNOWN) && (ret.app_protocol != NDPI_PROTOCOL_UNKNOWN) && - (flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN)) { - ret.master_protocol = ret.app_protocol; - ret.app_protocol = flow->guessed_host_protocol_id; - } + /* Don't overwrite the category if already set */ + if((flow->category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) && (ret.app_protocol != NDPI_PROTOCOL_UNKNOWN)) + ndpi_fill_protocol_category(ndpi_str, flow, &ret); + else + ret.category = flow->category; - if((!flow->risk_checked) && (ret.master_protocol != NDPI_PROTOCOL_UNKNOWN)) { - ndpi_default_ports_tree_node_t *found; - u_int16_t *default_ports, sport, dport; - - if(flow->packet.udp) - found = ndpi_get_guessed_protocol_id(ndpi_str, IPPROTO_UDP, - sport = ntohs(flow->packet.udp->source), - dport = ntohs(flow->packet.udp->dest)), - default_ports = ndpi_str->proto_defaults[ret.master_protocol].udp_default_ports; - else if(flow->packet.tcp) - found = ndpi_get_guessed_protocol_id(ndpi_str, IPPROTO_TCP, - sport = ntohs(flow->packet.tcp->source), - dport = ntohs(flow->packet.tcp->dest)), - default_ports = ndpi_str->proto_defaults[ret.master_protocol].tcp_default_ports; - else - found = NULL, default_ports = NULL, sport = dport = 0; + if((flow->num_processed_pkts == 1) && (ret.master_protocol == NDPI_PROTOCOL_UNKNOWN) && + (ret.app_protocol == NDPI_PROTOCOL_UNKNOWN) && flow->packet.tcp && (flow->packet.tcp->syn == 0) && + (flow->guessed_protocol_id == 0)) { + u_int8_t protocol_was_guessed; - if(found - && (found->proto->protoId != NDPI_PROTOCOL_UNKNOWN) - && (found->proto->protoId != ret.master_protocol) - && (found->proto->protoId != ret.app_protocol) - ) { - // printf("******** %u / %u\n", found->proto->protoId, ret.master_protocol); + /* + This is a TCP flow + - whose first packet is NOT a SYN + - no protocol has been detected - if(!ndpi_check_protocol_port_mismatch_exceptions(ndpi_str, flow, found, &ret)) - ndpi_set_risk(flow, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT); - } else if((!ndpi_is_ntop_protocol(&ret)) && default_ports && (default_ports[0] != 0)) { - u_int8_t found = 0, i, num_loops = 0; + We don't see how future packets can match anything + hence we giveup here + */ + ret = ndpi_detection_giveup(ndpi_str, flow, 0, &protocol_was_guessed); + } - check_default_ports: - for(i=0; (i<MAX_DEFAULT_PORTS) && (default_ports[i] != 0); i++) { - if((default_ports[i] == sport) || (default_ports[i] == dport)) { - found = 1; - break; - } - } /* for */ + if((ret.master_protocol == NDPI_PROTOCOL_UNKNOWN) && (ret.app_protocol != NDPI_PROTOCOL_UNKNOWN) && + (flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN)) { + ret.master_protocol = ret.app_protocol; + ret.app_protocol = flow->guessed_host_protocol_id; + } - if((num_loops == 0) && (!found)) { - if(flow->packet.udp) - default_ports = ndpi_str->proto_defaults[ret.app_protocol].udp_default_ports; - else - default_ports = ndpi_str->proto_defaults[ret.app_protocol].tcp_default_ports; + if((!flow->risk_checked) && (ret.master_protocol != NDPI_PROTOCOL_UNKNOWN)) { + ndpi_default_ports_tree_node_t *found; + u_int16_t *default_ports, sport, dport; - num_loops = 1; - goto check_default_ports; + if(flow->packet.udp) + found = ndpi_get_guessed_protocol_id(ndpi_str, IPPROTO_UDP, + sport = ntohs(flow->packet.udp->source), + dport = ntohs(flow->packet.udp->dest)), + default_ports = ndpi_str->proto_defaults[ret.master_protocol].udp_default_ports; + else if(flow->packet.tcp) + found = ndpi_get_guessed_protocol_id(ndpi_str, IPPROTO_TCP, + sport = ntohs(flow->packet.tcp->source), + dport = ntohs(flow->packet.tcp->dest)), + default_ports = ndpi_str->proto_defaults[ret.master_protocol].tcp_default_ports; + else + found = NULL, default_ports = NULL, sport = dport = 0; + + if(found + && (found->proto->protoId != NDPI_PROTOCOL_UNKNOWN) + && (found->proto->protoId != ret.master_protocol) + && (found->proto->protoId != ret.app_protocol) + ) { + // printf("******** %u / %u\n", found->proto->protoId, ret.master_protocol); + + if(!ndpi_check_protocol_port_mismatch_exceptions(ndpi_str, flow, found, &ret)) + ndpi_set_risk(flow, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT); + } else if((!ndpi_is_ntop_protocol(&ret)) && default_ports && (default_ports[0] != 0)) { + u_int8_t found = 0, i, num_loops = 0; + + check_default_ports: + for(i=0; (i<MAX_DEFAULT_PORTS) && (default_ports[i] != 0); i++) { + if((default_ports[i] == sport) || (default_ports[i] == dport)) { + found = 1; + break; } + } /* for */ - if(!found) { - // printf("******** Invalid default port\n"); - ndpi_set_risk(flow, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT); - } + if((num_loops == 0) && (!found)) { + if(flow->packet.udp) + default_ports = ndpi_str->proto_defaults[ret.app_protocol].udp_default_ports; + else + default_ports = ndpi_str->proto_defaults[ret.app_protocol].tcp_default_ports; + + num_loops = 1; + goto check_default_ports; } - flow->risk_checked = 1; + if(!found) { + // printf("******** Invalid default port\n"); + ndpi_set_risk(flow, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT); + } } - ndpi_reconcile_protocols(ndpi_str, flow, &ret); + flow->risk_checked = 1; + } - if(num_calls == 0) - flow->fail_with_unknown = 1; + ndpi_reconcile_protocols(ndpi_str, flow, &ret); - invalidate_ptr: - /* - Invalidate packet memory to avoid accessing the pointers below - when the packet is no longer accessible - */ - flow->packet.iph = NULL, flow->packet.tcp = NULL, flow->packet.udp = NULL, flow->packet.payload = NULL; - ndpi_reset_packet_line_info(&flow->packet); + if(num_calls == 0) + flow->fail_with_unknown = 1; - return(ret); - } + invalidate_ptr: + /* + Invalidate packet memory to avoid accessing the pointers below + when the packet is no longer accessible + */ + flow->packet.iph = NULL, flow->packet.tcp = NULL, flow->packet.udp = NULL, flow->packet.payload = NULL; + ndpi_reset_packet_line_info(&flow->packet); - /* ********************************************************************************* */ + return(ret); +} - 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_int32_t val; - val = 0; +/* ********************************************************************************* */ - // cancel if eof, ' ' or line end chars are reached - while(*str >= '0' && *str <= '9' && max_chars_to_read > 0) { - val *= 10; - val += *str - '0'; - str++; - max_chars_to_read = max_chars_to_read - 1; - *bytes_read = *bytes_read + 1; - } +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_int32_t val; + val = 0; - return(val); + // cancel if eof, ' ' or line end chars are reached + while(*str >= '0' && *str <= '9' && max_chars_to_read > 0) { + val *= 10; + val += *str - '0'; + str++; + max_chars_to_read = max_chars_to_read - 1; + *bytes_read = *bytes_read + 1; } - /* ********************************************************************************* */ + return(val); +} + +/* ********************************************************************************* */ #ifdef CODE_UNUSED - 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_int32_t val; - val = 0; - if(max_chars_to_read <= 2 || str[0] != '0' || str[1] != 'x') { - return(ndpi_bytestream_to_number(str, max_chars_to_read, bytes_read)); - } else { - /*use base 16 system */ - str += 2; - max_chars_to_read -= 2; - *bytes_read = *bytes_read + 2; - - while(max_chars_to_read > 0) { - if(*str >= '0' && *str <= '9') { - val *= 16; - val += *str - '0'; - } else if(*str >= 'a' && *str <= 'f') { - val *= 16; - val += *str + 10 - 'a'; - } else if(*str >= 'A' && *str <= 'F') { - val *= 16; - val += *str + 10 - 'A'; - } else { - break; - } - str++; - max_chars_to_read = max_chars_to_read - 1; - *bytes_read = *bytes_read + 1; +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_int32_t val; + val = 0; + if(max_chars_to_read <= 2 || str[0] != '0' || str[1] != 'x') { + return(ndpi_bytestream_to_number(str, max_chars_to_read, bytes_read)); + } else { + /*use base 16 system */ + str += 2; + max_chars_to_read -= 2; + *bytes_read = *bytes_read + 2; + + while(max_chars_to_read > 0) { + if(*str >= '0' && *str <= '9') { + val *= 16; + val += *str - '0'; + } else if(*str >= 'a' && *str <= 'f') { + val *= 16; + val += *str + 10 - 'a'; + } else if(*str >= 'A' && *str <= 'F') { + val *= 16; + val += *str + 10 - 'A'; + } else { + break; } + str++; + max_chars_to_read = max_chars_to_read - 1; + *bytes_read = *bytes_read + 1; } - - return(val); } + return(val); +} + #endif - /* ********************************************************************************* */ +/* ********************************************************************************* */ - 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_int64_t val; - val = 0; - // cancel if eof, ' ' or line end chars are reached - while(max_chars_to_read > 0 && *str >= '0' && *str <= '9') { - val *= 10; - val += *str - '0'; - str++; - max_chars_to_read = max_chars_to_read - 1; - *bytes_read = *bytes_read + 1; - } - return(val); +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_int64_t val; + val = 0; + // cancel if eof, ' ' or line end chars are reached + while(max_chars_to_read > 0 && *str >= '0' && *str <= '9') { + val *= 10; + val += *str - '0'; + str++; + max_chars_to_read = max_chars_to_read - 1; + *bytes_read = *bytes_read + 1; } + return(val); +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - 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_int64_t val; - val = 0; - if(max_chars_to_read <= 2 || str[0] != '0' || str[1] != 'x') { - return(ndpi_bytestream_to_number64(str, max_chars_to_read, bytes_read)); - } else { - /*use base 16 system */ - str += 2; - max_chars_to_read -= 2; - *bytes_read = *bytes_read + 2; - while(max_chars_to_read > 0) { - if(*str >= '0' && *str <= '9') { - val *= 16; - val += *str - '0'; - } else if(*str >= 'a' && *str <= 'f') { - val *= 16; - val += *str + 10 - 'a'; - } else if(*str >= 'A' && *str <= 'F') { - val *= 16; - val += *str + 10 - 'A'; - } else { - break; - } - str++; - max_chars_to_read = max_chars_to_read - 1; - *bytes_read = *bytes_read + 1; +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_int64_t val; + val = 0; + if(max_chars_to_read <= 2 || str[0] != '0' || str[1] != 'x') { + return(ndpi_bytestream_to_number64(str, max_chars_to_read, bytes_read)); + } else { + /*use base 16 system */ + str += 2; + max_chars_to_read -= 2; + *bytes_read = *bytes_read + 2; + while(max_chars_to_read > 0) { + if(*str >= '0' && *str <= '9') { + val *= 16; + val += *str - '0'; + } else if(*str >= 'a' && *str <= 'f') { + val *= 16; + val += *str + 10 - 'a'; + } else if(*str >= 'A' && *str <= 'F') { + val *= 16; + val += *str + 10 - 'A'; + } else { + break; } + str++; + max_chars_to_read = max_chars_to_read - 1; + *bytes_read = *bytes_read + 1; } - return(val); } + return(val); +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - 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_int32_t val; - u_int16_t read = 0; - u_int16_t oldread; - u_int32_t c; +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_int32_t val; + u_int16_t read = 0; + u_int16_t oldread; + u_int32_t c; - /* ip address must be X.X.X.X with each X between 0 and 255 */ - oldread = read; - c = ndpi_bytestream_to_number(str, max_chars_to_read, &read); - if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') - return(0); + /* ip address must be X.X.X.X with each X between 0 and 255 */ + oldread = read; + c = ndpi_bytestream_to_number(str, max_chars_to_read, &read); + if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') + return(0); - read++; - val = c << 24; - oldread = read; - c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); - if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') - return(0); + read++; + val = c << 24; + oldread = read; + c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); + if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') + return(0); - read++; - val = val + (c << 16); - oldread = read; - c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); - if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') - return(0); + read++; + val = val + (c << 16); + oldread = read; + c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); + if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') + return(0); - read++; - val = val + (c << 8); - oldread = read; - c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); - if(c > 255 || oldread == read || max_chars_to_read == read) - return(0); + read++; + val = val + (c << 8); + oldread = read; + c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); + if(c > 255 || oldread == read || max_chars_to_read == read) + return(0); - val = val + c; + val = val + c; - *bytes_read = *bytes_read + read; + *bytes_read = *bytes_read + read; - return(htonl(val)); - } + return(htonl(val)); +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - /* internal function for every detection to parse one packet and to increase the info buffer */ - void ndpi_parse_packet_line_info(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { - u_int32_t a; - struct ndpi_packet_struct *packet = &flow->packet; +/* internal function for every detection to parse one packet and to increase the info buffer */ +void ndpi_parse_packet_line_info(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { + u_int32_t a; + struct ndpi_packet_struct *packet = &flow->packet; - if((packet->payload_packet_len < 3) || (packet->payload == NULL)) - return; + if((packet->payload_packet_len < 3) || (packet->payload == NULL)) + return; - if(packet->packet_lines_parsed_complete != 0) - return; + if(packet->packet_lines_parsed_complete != 0) + return; - packet->packet_lines_parsed_complete = 1; - ndpi_reset_packet_line_info(packet); + packet->packet_lines_parsed_complete = 1; + ndpi_reset_packet_line_info(packet); - packet->line[packet->parsed_lines].ptr = packet->payload; - packet->line[packet->parsed_lines].len = 0; + packet->line[packet->parsed_lines].ptr = packet->payload; + packet->line[packet->parsed_lines].len = 0; - for(a = 0; ((a+1) < packet->payload_packet_len) && (packet->parsed_lines < NDPI_MAX_PARSE_LINES_PER_PACKET); a++) { - if((packet->payload[a] == 0x0d) && (packet->payload[a+1] == 0x0a)) { - /* If end of line char sequence CR+NL "\r\n", process line */ + for(a = 0; ((a+1) < packet->payload_packet_len) && (packet->parsed_lines < NDPI_MAX_PARSE_LINES_PER_PACKET); a++) { + if((packet->payload[a] == 0x0d) && (packet->payload[a+1] == 0x0a)) { + /* If end of line char sequence CR+NL "\r\n", process line */ - if(((a + 3) < packet->payload_packet_len) - && (packet->payload[a+2] == 0x0d) - && (packet->payload[a+3] == 0x0a)) { - /* \r\n\r\n */ - int diff; /* No unsigned ! */ - u_int32_t a1 = a + 4; + if(((a + 3) < packet->payload_packet_len) + && (packet->payload[a+2] == 0x0d) + && (packet->payload[a+3] == 0x0a)) { + /* \r\n\r\n */ + int diff; /* No unsigned ! */ + u_int32_t a1 = a + 4; - diff = packet->payload_packet_len - a1; + diff = packet->payload_packet_len - a1; - if(diff > 0) { - diff = ndpi_min(diff, sizeof(flow->initial_binary_bytes)); - memcpy(&flow->initial_binary_bytes, &packet->payload[a1], diff); - flow->initial_binary_bytes_len = diff; - } + if(diff > 0) { + diff = ndpi_min(diff, sizeof(flow->initial_binary_bytes)); + memcpy(&flow->initial_binary_bytes, &packet->payload[a1], diff); + flow->initial_binary_bytes_len = diff; } + } + + packet->line[packet->parsed_lines].len = + (u_int16_t)(((size_t) &packet->payload[a]) - ((size_t) packet->line[packet->parsed_lines].ptr)); - packet->line[packet->parsed_lines].len = - (u_int16_t)(((size_t) &packet->payload[a]) - ((size_t) packet->line[packet->parsed_lines].ptr)); + /* First line of a HTTP response parsing. Expected a "HTTP/1.? ???" */ + if(packet->parsed_lines == 0 && packet->line[0].len >= NDPI_STATICSTRING_LEN("HTTP/1.X 200 ") && + strncasecmp((const char *) packet->line[0].ptr, "HTTP/1.", NDPI_STATICSTRING_LEN("HTTP/1.")) == 0 && + packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.X ")] > '0' && /* response code between 000 and 699 */ + packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.X ")] < '6') { + packet->http_response.ptr = &packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.1 ")]; + packet->http_response.len = packet->line[0].len - NDPI_STATICSTRING_LEN("HTTP/1.1 "); + packet->http_num_headers++; - /* First line of a HTTP response parsing. Expected a "HTTP/1.? ???" */ - if(packet->parsed_lines == 0 && packet->line[0].len >= NDPI_STATICSTRING_LEN("HTTP/1.X 200 ") && - strncasecmp((const char *) packet->line[0].ptr, "HTTP/1.", NDPI_STATICSTRING_LEN("HTTP/1.")) == 0 && - packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.X ")] > '0' && /* response code between 000 and 699 */ - packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.X ")] < '6') { - packet->http_response.ptr = &packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.1 ")]; - packet->http_response.len = packet->line[0].len - NDPI_STATICSTRING_LEN("HTTP/1.1 "); - packet->http_num_headers++; + /* Set server HTTP response code */ + if(packet->payload_packet_len >= 12) { + char buf[4]; /* Set server HTTP response code */ - if(packet->payload_packet_len >= 12) { - char buf[4]; - - /* Set server HTTP response code */ - strncpy(buf, (char *) &packet->payload[9], 3); - buf[3] = '\0'; + strncpy(buf, (char *) &packet->payload[9], 3); + buf[3] = '\0'; - flow->http.response_status_code = atoi(buf); - /* https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ - if((flow->http.response_status_code < 100) || (flow->http.response_status_code > 509)) - flow->http.response_status_code = 0; /* Out of range */ - } + flow->http.response_status_code = atoi(buf); + /* https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ + if((flow->http.response_status_code < 100) || (flow->http.response_status_code > 509)) + flow->http.response_status_code = 0; /* Out of range */ } + } - /* "Server:" header line in HTTP response */ - if(packet->line[packet->parsed_lines].len > NDPI_STATICSTRING_LEN("Server:") + 1 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, - "Server:", NDPI_STATICSTRING_LEN("Server:")) == 0) { - // some stupid clients omit a space and place the servername directly after the colon - if(packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:")] == ' ') { - packet->server_line.ptr = - &packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:") + 1]; - packet->server_line.len = - packet->line[packet->parsed_lines].len - (NDPI_STATICSTRING_LEN("Server:") + 1); - } else { - packet->server_line.ptr = &packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:")]; - packet->server_line.len = packet->line[packet->parsed_lines].len - NDPI_STATICSTRING_LEN("Server:"); - } - packet->http_num_headers++; + /* "Server:" header line in HTTP response */ + if(packet->line[packet->parsed_lines].len > NDPI_STATICSTRING_LEN("Server:") + 1 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, + "Server:", NDPI_STATICSTRING_LEN("Server:")) == 0) { + // some stupid clients omit a space and place the servername directly after the colon + if(packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:")] == ' ') { + packet->server_line.ptr = + &packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:") + 1]; + packet->server_line.len = + packet->line[packet->parsed_lines].len - (NDPI_STATICSTRING_LEN("Server:") + 1); + } else { + packet->server_line.ptr = &packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:")]; + packet->server_line.len = packet->line[packet->parsed_lines].len - NDPI_STATICSTRING_LEN("Server:"); } - /* "Host:" header line in HTTP request */ - if(packet->line[packet->parsed_lines].len > 6 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Host:", 5) == 0) { - // some stupid clients omit a space and place the hostname directly after the colon - if(packet->line[packet->parsed_lines].ptr[5] == ' ') { - packet->host_line.ptr = &packet->line[packet->parsed_lines].ptr[6]; - packet->host_line.len = packet->line[packet->parsed_lines].len - 6; - } else { - packet->host_line.ptr = &packet->line[packet->parsed_lines].ptr[5]; - packet->host_line.len = packet->line[packet->parsed_lines].len - 5; - } - packet->http_num_headers++; + packet->http_num_headers++; + } + /* "Host:" header line in HTTP request */ + if(packet->line[packet->parsed_lines].len > 6 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Host:", 5) == 0) { + // some stupid clients omit a space and place the hostname directly after the colon + if(packet->line[packet->parsed_lines].ptr[5] == ' ') { + packet->host_line.ptr = &packet->line[packet->parsed_lines].ptr[6]; + packet->host_line.len = packet->line[packet->parsed_lines].len - 6; + } else { + packet->host_line.ptr = &packet->line[packet->parsed_lines].ptr[5]; + packet->host_line.len = packet->line[packet->parsed_lines].len - 5; } - /* "X-Forwarded-For:" header line in HTTP request. Commonly used for HTTP proxies. */ - if(packet->line[packet->parsed_lines].len > 17 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "X-Forwarded-For:", 16) == 0) { - // some stupid clients omit a space and place the hostname directly after the colon - if(packet->line[packet->parsed_lines].ptr[16] == ' ') { - packet->forwarded_line.ptr = &packet->line[packet->parsed_lines].ptr[17]; - packet->forwarded_line.len = packet->line[packet->parsed_lines].len - 17; - } else { - packet->forwarded_line.ptr = &packet->line[packet->parsed_lines].ptr[16]; - packet->forwarded_line.len = packet->line[packet->parsed_lines].len - 16; - } - packet->http_num_headers++; + packet->http_num_headers++; + } + /* "X-Forwarded-For:" header line in HTTP request. Commonly used for HTTP proxies. */ + if(packet->line[packet->parsed_lines].len > 17 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "X-Forwarded-For:", 16) == 0) { + // some stupid clients omit a space and place the hostname directly after the colon + if(packet->line[packet->parsed_lines].ptr[16] == ' ') { + packet->forwarded_line.ptr = &packet->line[packet->parsed_lines].ptr[17]; + packet->forwarded_line.len = packet->line[packet->parsed_lines].len - 17; + } else { + packet->forwarded_line.ptr = &packet->line[packet->parsed_lines].ptr[16]; + packet->forwarded_line.len = packet->line[packet->parsed_lines].len - 16; } - /* "Content-Type:" header line in HTTP. */ - if(packet->line[packet->parsed_lines].len > 14 && - (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-Type: ", 14) == 0 || - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-type: ", 14) == 0)) { - packet->content_line.ptr = &packet->line[packet->parsed_lines].ptr[14]; - packet->content_line.len = packet->line[packet->parsed_lines].len - 14; + packet->http_num_headers++; + } + /* "Content-Type:" header line in HTTP. */ + if(packet->line[packet->parsed_lines].len > 14 && + (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-Type: ", 14) == 0 || + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-type: ", 14) == 0)) { + packet->content_line.ptr = &packet->line[packet->parsed_lines].ptr[14]; + packet->content_line.len = packet->line[packet->parsed_lines].len - 14; - while((packet->content_line.len > 0) && (packet->content_line.ptr[0] == ' ')) - packet->content_line.len--, packet->content_line.ptr++; + while((packet->content_line.len > 0) && (packet->content_line.ptr[0] == ' ')) + packet->content_line.len--, packet->content_line.ptr++; - packet->http_num_headers++; - } - /* "Content-Type:" header line in HTTP AGAIN. Probably a bogus response without space after ":" */ - if((packet->content_line.len == 0) && (packet->line[packet->parsed_lines].len > 13) && - (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-type:", 13) == 0)) { - packet->content_line.ptr = &packet->line[packet->parsed_lines].ptr[13]; - packet->content_line.len = packet->line[packet->parsed_lines].len - 13; - packet->http_num_headers++; - } + packet->http_num_headers++; + } + /* "Content-Type:" header line in HTTP AGAIN. Probably a bogus response without space after ":" */ + if((packet->content_line.len == 0) && (packet->line[packet->parsed_lines].len > 13) && + (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-type:", 13) == 0)) { + packet->content_line.ptr = &packet->line[packet->parsed_lines].ptr[13]; + packet->content_line.len = packet->line[packet->parsed_lines].len - 13; + packet->http_num_headers++; + } - if(packet->content_line.len > 0) { - /* application/json; charset=utf-8 */ - char separator[] = {';', '\r', '\0'}; - int i; + if(packet->content_line.len > 0) { + /* application/json; charset=utf-8 */ + char separator[] = {';', '\r', '\0'}; + int i; - for(i = 0; separator[i] != '\0'; i++) { - char *c = memchr((char *) packet->content_line.ptr, separator[i], packet->content_line.len); + for(i = 0; separator[i] != '\0'; i++) { + char *c = memchr((char *) packet->content_line.ptr, separator[i], packet->content_line.len); - if(c != NULL) - packet->content_line.len = c - (char *) packet->content_line.ptr; - } + if(c != NULL) + packet->content_line.len = c - (char *) packet->content_line.ptr; } + } - /* "Accept:" header line in HTTP request. */ - if(packet->line[packet->parsed_lines].len > 8 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Accept: ", 8) == 0) { - packet->accept_line.ptr = &packet->line[packet->parsed_lines].ptr[8]; - packet->accept_line.len = packet->line[packet->parsed_lines].len - 8; - packet->http_num_headers++; - } - /* "Referer:" header line in HTTP request. */ - if(packet->line[packet->parsed_lines].len > 9 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Referer: ", 9) == 0) { - packet->referer_line.ptr = &packet->line[packet->parsed_lines].ptr[9]; - packet->referer_line.len = packet->line[packet->parsed_lines].len - 9; - packet->http_num_headers++; - } - /* "User-Agent:" header line in HTTP request. */ - if(packet->line[packet->parsed_lines].len > 12 && - (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "User-Agent: ", 12) == 0 || - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "User-agent: ", 12) == 0)) { - packet->user_agent_line.ptr = &packet->line[packet->parsed_lines].ptr[12]; - packet->user_agent_line.len = packet->line[packet->parsed_lines].len - 12; - packet->http_num_headers++; - } - /* "Content-Encoding:" header line in HTTP response (and request?). */ - if(packet->line[packet->parsed_lines].len > 18 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-Encoding: ", 18) == 0) { - packet->http_encoding.ptr = &packet->line[packet->parsed_lines].ptr[18]; - packet->http_encoding.len = packet->line[packet->parsed_lines].len - 18; - packet->http_num_headers++; - } - /* "Transfer-Encoding:" header line in HTTP. */ - if(packet->line[packet->parsed_lines].len > 19 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Transfer-Encoding: ", 19) == 0) { - packet->http_transfer_encoding.ptr = &packet->line[packet->parsed_lines].ptr[19]; - packet->http_transfer_encoding.len = packet->line[packet->parsed_lines].len - 19; - packet->http_num_headers++; - } - /* "Content-Length:" header line in HTTP. */ - if(packet->line[packet->parsed_lines].len > 16 && - ((strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-Length: ", 16) == 0) || - (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "content-length: ", 16) == 0))) { - packet->http_contentlen.ptr = &packet->line[packet->parsed_lines].ptr[16]; - packet->http_contentlen.len = packet->line[packet->parsed_lines].len - 16; - packet->http_num_headers++; - } - /* "Content-Disposition"*/ - if(packet->line[packet->parsed_lines].len > 21 && - ((strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-Disposition: ", 21) == 0))) { - packet->content_disposition_line.ptr = &packet->line[packet->parsed_lines].ptr[21]; - packet->content_disposition_line.len = packet->line[packet->parsed_lines].len - 21; - packet->http_num_headers++; - } - /* "Cookie:" header line in HTTP. */ - if(packet->line[packet->parsed_lines].len > 8 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Cookie: ", 8) == 0) { - packet->http_cookie.ptr = &packet->line[packet->parsed_lines].ptr[8]; - packet->http_cookie.len = packet->line[packet->parsed_lines].len - 8; - packet->http_num_headers++; - } - /* "Origin:" header line in HTTP. */ - if(packet->line[packet->parsed_lines].len > 8 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Origin: ", 8) == 0) { - packet->http_origin.ptr = &packet->line[packet->parsed_lines].ptr[8]; - packet->http_origin.len = packet->line[packet->parsed_lines].len - 8; - packet->http_num_headers++; - } - /* "X-Session-Type:" header line in HTTP. */ - if(packet->line[packet->parsed_lines].len > 16 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "X-Session-Type: ", 16) == 0) { - packet->http_x_session_type.ptr = &packet->line[packet->parsed_lines].ptr[16]; - packet->http_x_session_type.len = packet->line[packet->parsed_lines].len - 16; - packet->http_num_headers++; - } - /* Identification and counting of other HTTP headers. - * We consider the most common headers, but there are many others, - * which can be seen at references below: - * - https://tools.ietf.org/html/rfc7230 - * - https://en.wikipedia.org/wiki/List_of_HTTP_header_fields - */ - if((packet->line[packet->parsed_lines].len > 6 && - (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Date: ", 6) == 0 || - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Vary: ", 6) == 0 || - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "ETag: ", 6) == 0)) || - (packet->line[packet->parsed_lines].len > 8 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Pragma: ", 8) == 0) || - (packet->line[packet->parsed_lines].len > 9 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Expires: ", 9) == 0) || - (packet->line[packet->parsed_lines].len > 12 && - (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Set-Cookie: ", 12) == 0 || - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Keep-Alive: ", 12) == 0 || - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Connection: ", 12) == 0)) || - (packet->line[packet->parsed_lines].len > 15 && - (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Last-Modified: ", 15) == 0 || - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Accept-Ranges: ", 15) == 0)) || - (packet->line[packet->parsed_lines].len > 17 && - (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Accept-Language: ", 17) == 0 || - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Accept-Encoding: ", 17) == 0)) || - (packet->line[packet->parsed_lines].len > 27 && - strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, - "Upgrade-Insecure-Requests: ", 27) == 0)) { - /* Just count. In the future, if needed, this if can be splited to parse these headers */ - packet->http_num_headers++; - } + /* "Accept:" header line in HTTP request. */ + if(packet->line[packet->parsed_lines].len > 8 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Accept: ", 8) == 0) { + packet->accept_line.ptr = &packet->line[packet->parsed_lines].ptr[8]; + packet->accept_line.len = packet->line[packet->parsed_lines].len - 8; + packet->http_num_headers++; + } + /* "Referer:" header line in HTTP request. */ + if(packet->line[packet->parsed_lines].len > 9 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Referer: ", 9) == 0) { + packet->referer_line.ptr = &packet->line[packet->parsed_lines].ptr[9]; + packet->referer_line.len = packet->line[packet->parsed_lines].len - 9; + packet->http_num_headers++; + } + /* "User-Agent:" header line in HTTP request. */ + if(packet->line[packet->parsed_lines].len > 12 && + (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "User-Agent: ", 12) == 0 || + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "User-agent: ", 12) == 0)) { + packet->user_agent_line.ptr = &packet->line[packet->parsed_lines].ptr[12]; + packet->user_agent_line.len = packet->line[packet->parsed_lines].len - 12; + packet->http_num_headers++; + } + /* "Content-Encoding:" header line in HTTP response (and request?). */ + if(packet->line[packet->parsed_lines].len > 18 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-Encoding: ", 18) == 0) { + packet->http_encoding.ptr = &packet->line[packet->parsed_lines].ptr[18]; + packet->http_encoding.len = packet->line[packet->parsed_lines].len - 18; + packet->http_num_headers++; + } + /* "Transfer-Encoding:" header line in HTTP. */ + if(packet->line[packet->parsed_lines].len > 19 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Transfer-Encoding: ", 19) == 0) { + packet->http_transfer_encoding.ptr = &packet->line[packet->parsed_lines].ptr[19]; + packet->http_transfer_encoding.len = packet->line[packet->parsed_lines].len - 19; + packet->http_num_headers++; + } + /* "Content-Length:" header line in HTTP. */ + if(packet->line[packet->parsed_lines].len > 16 && + ((strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-Length: ", 16) == 0) || + (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "content-length: ", 16) == 0))) { + packet->http_contentlen.ptr = &packet->line[packet->parsed_lines].ptr[16]; + packet->http_contentlen.len = packet->line[packet->parsed_lines].len - 16; + packet->http_num_headers++; + } + /* "Content-Disposition"*/ + if(packet->line[packet->parsed_lines].len > 21 && + ((strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Content-Disposition: ", 21) == 0))) { + packet->content_disposition_line.ptr = &packet->line[packet->parsed_lines].ptr[21]; + packet->content_disposition_line.len = packet->line[packet->parsed_lines].len - 21; + packet->http_num_headers++; + } + /* "Cookie:" header line in HTTP. */ + if(packet->line[packet->parsed_lines].len > 8 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Cookie: ", 8) == 0) { + packet->http_cookie.ptr = &packet->line[packet->parsed_lines].ptr[8]; + packet->http_cookie.len = packet->line[packet->parsed_lines].len - 8; + packet->http_num_headers++; + } + /* "Origin:" header line in HTTP. */ + if(packet->line[packet->parsed_lines].len > 8 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Origin: ", 8) == 0) { + packet->http_origin.ptr = &packet->line[packet->parsed_lines].ptr[8]; + packet->http_origin.len = packet->line[packet->parsed_lines].len - 8; + packet->http_num_headers++; + } + /* "X-Session-Type:" header line in HTTP. */ + if(packet->line[packet->parsed_lines].len > 16 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "X-Session-Type: ", 16) == 0) { + packet->http_x_session_type.ptr = &packet->line[packet->parsed_lines].ptr[16]; + packet->http_x_session_type.len = packet->line[packet->parsed_lines].len - 16; + packet->http_num_headers++; + } + /* Identification and counting of other HTTP headers. + * We consider the most common headers, but there are many others, + * which can be seen at references below: + * - https://tools.ietf.org/html/rfc7230 + * - https://en.wikipedia.org/wiki/List_of_HTTP_header_fields + */ + if((packet->line[packet->parsed_lines].len > 6 && + (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Date: ", 6) == 0 || + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Vary: ", 6) == 0 || + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "ETag: ", 6) == 0)) || + (packet->line[packet->parsed_lines].len > 8 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Pragma: ", 8) == 0) || + (packet->line[packet->parsed_lines].len > 9 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Expires: ", 9) == 0) || + (packet->line[packet->parsed_lines].len > 12 && + (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Set-Cookie: ", 12) == 0 || + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Keep-Alive: ", 12) == 0 || + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Connection: ", 12) == 0)) || + (packet->line[packet->parsed_lines].len > 15 && + (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Last-Modified: ", 15) == 0 || + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Accept-Ranges: ", 15) == 0)) || + (packet->line[packet->parsed_lines].len > 17 && + (strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Accept-Language: ", 17) == 0 || + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, "Accept-Encoding: ", 17) == 0)) || + (packet->line[packet->parsed_lines].len > 27 && + strncasecmp((const char *) packet->line[packet->parsed_lines].ptr, + "Upgrade-Insecure-Requests: ", 27) == 0)) { + /* Just count. In the future, if needed, this if can be splited to parse these headers */ + packet->http_num_headers++; + } - if(packet->line[packet->parsed_lines].len == 0) { - packet->empty_line_position = a; - packet->empty_line_position_set = 1; - } + if(packet->line[packet->parsed_lines].len == 0) { + packet->empty_line_position = a; + packet->empty_line_position_set = 1; + } - if(packet->parsed_lines >= (NDPI_MAX_PARSE_LINES_PER_PACKET - 1)) - return; + if(packet->parsed_lines >= (NDPI_MAX_PARSE_LINES_PER_PACKET - 1)) + return; - packet->parsed_lines++; - packet->line[packet->parsed_lines].ptr = &packet->payload[a + 2]; - packet->line[packet->parsed_lines].len = 0; + packet->parsed_lines++; + packet->line[packet->parsed_lines].ptr = &packet->payload[a + 2]; + packet->line[packet->parsed_lines].len = 0; - a++; /* next char in the payload */ - } + a++; /* next char in the payload */ } + } - if(packet->parsed_lines >= 1) { - packet->line[packet->parsed_lines].len = - (u_int16_t)(((size_t) &packet->payload[packet->payload_packet_len]) - - ((size_t) packet->line[packet->parsed_lines].ptr)); - packet->parsed_lines++; - } + if(packet->parsed_lines >= 1) { + packet->line[packet->parsed_lines].len = + (u_int16_t)(((size_t) &packet->payload[packet->payload_packet_len]) - + ((size_t) packet->line[packet->parsed_lines].ptr)); + packet->parsed_lines++; } +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - void ndpi_parse_packet_line_info_any(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { - struct ndpi_packet_struct *packet = &flow->packet; - u_int32_t a; - u_int16_t end = packet->payload_packet_len; +void ndpi_parse_packet_line_info_any(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { + struct ndpi_packet_struct *packet = &flow->packet; + u_int32_t a; + u_int16_t end = packet->payload_packet_len; - if(packet->packet_lines_parsed_complete != 0) - return; + if(packet->packet_lines_parsed_complete != 0) + return; - packet->packet_lines_parsed_complete = 1; - packet->parsed_lines = 0; + packet->packet_lines_parsed_complete = 1; + packet->parsed_lines = 0; - if(packet->payload_packet_len == 0) - return; + if(packet->payload_packet_len == 0) + return; - packet->line[packet->parsed_lines].ptr = packet->payload; - packet->line[packet->parsed_lines].len = 0; + packet->line[packet->parsed_lines].ptr = packet->payload; + packet->line[packet->parsed_lines].len = 0; - for(a = 0; a < end; a++) { - if(packet->payload[a] == 0x0a) { - packet->line[packet->parsed_lines].len = (u_int16_t)( - ((size_t) &packet->payload[a]) - ((size_t) packet->line[packet->parsed_lines].ptr)); + for(a = 0; a < end; a++) { + if(packet->payload[a] == 0x0a) { + packet->line[packet->parsed_lines].len = (u_int16_t)( + ((size_t) &packet->payload[a]) - ((size_t) packet->line[packet->parsed_lines].ptr)); - if(a > 0 && packet->payload[a - 1] == 0x0d) - packet->line[packet->parsed_lines].len--; + if(a > 0 && packet->payload[a - 1] == 0x0d) + packet->line[packet->parsed_lines].len--; - if(packet->parsed_lines >= (NDPI_MAX_PARSE_LINES_PER_PACKET - 1)) - break; + if(packet->parsed_lines >= (NDPI_MAX_PARSE_LINES_PER_PACKET - 1)) + break; - packet->parsed_lines++; - packet->line[packet->parsed_lines].ptr = &packet->payload[a + 1]; - packet->line[packet->parsed_lines].len = 0; + packet->parsed_lines++; + packet->line[packet->parsed_lines].ptr = &packet->payload[a + 1]; + packet->line[packet->parsed_lines].len = 0; - if((a + 1) >= packet->payload_packet_len) - break; + if((a + 1) >= packet->payload_packet_len) + break; - //a++; - } + //a++; } } +} - /* ********************************************************************************* */ - - u_int16_t ndpi_check_for_email_address(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - u_int16_t counter) { - struct ndpi_packet_struct *packet = &flow->packet; +/* ********************************************************************************* */ - NDPI_LOG_DBG2(ndpi_str, "called ndpi_check_for_email_address\n"); +u_int16_t ndpi_check_for_email_address(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + u_int16_t counter) { + struct ndpi_packet_struct *packet = &flow->packet; - if(packet->payload_packet_len > counter && ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || - (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || - (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || - packet->payload[counter] == '-' || packet->payload[counter] == '_')) { - NDPI_LOG_DBG2(ndpi_str, "first letter\n"); + NDPI_LOG_DBG2(ndpi_str, "called ndpi_check_for_email_address\n"); + + if(packet->payload_packet_len > counter && ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || + (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || + (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || + packet->payload[counter] == '-' || packet->payload[counter] == '_')) { + NDPI_LOG_DBG2(ndpi_str, "first letter\n"); + counter++; + while(packet->payload_packet_len > counter && + ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || + (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || + (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || + packet->payload[counter] == '-' || packet->payload[counter] == '_' || + packet->payload[counter] == '.')) { + NDPI_LOG_DBG2(ndpi_str, "further letter\n"); counter++; - while(packet->payload_packet_len > counter && - ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || - (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || - (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || - packet->payload[counter] == '-' || packet->payload[counter] == '_' || - packet->payload[counter] == '.')) { - NDPI_LOG_DBG2(ndpi_str, "further letter\n"); + if(packet->payload_packet_len > counter && packet->payload[counter] == '@') { + NDPI_LOG_DBG2(ndpi_str, "@\n"); counter++; - if(packet->payload_packet_len > counter && packet->payload[counter] == '@') { - NDPI_LOG_DBG2(ndpi_str, "@\n"); + while(packet->payload_packet_len > counter && + ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || + (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || + (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || + packet->payload[counter] == '-' || packet->payload[counter] == '_')) { + NDPI_LOG_DBG2(ndpi_str, "letter\n"); counter++; - while(packet->payload_packet_len > counter && - ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || - (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || - (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || - packet->payload[counter] == '-' || packet->payload[counter] == '_')) { - NDPI_LOG_DBG2(ndpi_str, "letter\n"); + if(packet->payload_packet_len > counter && packet->payload[counter] == '.') { + NDPI_LOG_DBG2(ndpi_str, ".\n"); counter++; - if(packet->payload_packet_len > counter && packet->payload[counter] == '.') { - NDPI_LOG_DBG2(ndpi_str, ".\n"); - counter++; - if(packet->payload_packet_len > counter + 1 && - ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') && - (packet->payload[counter + 1] >= 'a' && packet->payload[counter + 1] <= 'z'))) { - NDPI_LOG_DBG2(ndpi_str, "two letters\n"); - counter += 2; + if(packet->payload_packet_len > counter + 1 && + ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') && + (packet->payload[counter + 1] >= 'a' && packet->payload[counter + 1] <= 'z'))) { + NDPI_LOG_DBG2(ndpi_str, "two letters\n"); + counter += 2; + if(packet->payload_packet_len > counter && + (packet->payload[counter] == ' ' || packet->payload[counter] == ';')) { + NDPI_LOG_DBG2(ndpi_str, "whitespace1\n"); + return(counter); + } else if(packet->payload_packet_len > counter && packet->payload[counter] >= 'a' && + packet->payload[counter] <= 'z') { + NDPI_LOG_DBG2(ndpi_str, "one letter\n"); + counter++; if(packet->payload_packet_len > counter && (packet->payload[counter] == ' ' || packet->payload[counter] == ';')) { - NDPI_LOG_DBG2(ndpi_str, "whitespace1\n"); + NDPI_LOG_DBG2(ndpi_str, "whitespace2\n"); return(counter); } else if(packet->payload_packet_len > counter && packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') { - NDPI_LOG_DBG2(ndpi_str, "one letter\n"); counter++; if(packet->payload_packet_len > counter && (packet->payload[counter] == ' ' || packet->payload[counter] == ';')) { - NDPI_LOG_DBG2(ndpi_str, "whitespace2\n"); + NDPI_LOG_DBG2(ndpi_str, "whitespace3\n"); return(counter); - } else if(packet->payload_packet_len > counter && packet->payload[counter] >= 'a' && - packet->payload[counter] <= 'z') { - counter++; - if(packet->payload_packet_len > counter && - (packet->payload[counter] == ' ' || packet->payload[counter] == ';')) { - NDPI_LOG_DBG2(ndpi_str, "whitespace3\n"); - return(counter); - } else { - return(0); - } } else { return(0); } @@ -5877,1664 +5874,1705 @@ static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str } else { return(0); } + } else { + return(0); } } - return(0); } + return(0); } } - return(0); } + return(0); +} #ifdef NDPI_ENABLE_DEBUG_MESSAGES - /* ********************************************************************************* */ +/* ********************************************************************************* */ - void ndpi_debug_get_last_log_function_line(struct ndpi_detection_module_struct *ndpi_str, const char **file, - const char **func, u_int32_t *line) { - *file = ""; - *func = ""; +void ndpi_debug_get_last_log_function_line(struct ndpi_detection_module_struct *ndpi_str, const char **file, + const char **func, u_int32_t *line) { + *file = ""; + *func = ""; - if(ndpi_str->ndpi_debug_print_file != NULL) - *file = ndpi_str->ndpi_debug_print_file; + if(ndpi_str->ndpi_debug_print_file != NULL) + *file = ndpi_str->ndpi_debug_print_file; - if(ndpi_str->ndpi_debug_print_function != NULL) - *func = ndpi_str->ndpi_debug_print_function; + if(ndpi_str->ndpi_debug_print_function != NULL) + *func = ndpi_str->ndpi_debug_print_function; - *line = ndpi_str->ndpi_debug_print_line; - } + *line = ndpi_str->ndpi_debug_print_line; +} #endif - /* ********************************************************************************* */ +/* ********************************************************************************* */ - 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)); +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - void ndpi_set_detected_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { - struct ndpi_id_struct *src = flow->src, *dst = flow->dst; +void ndpi_set_detected_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { + struct ndpi_id_struct *src = flow->src, *dst = flow->dst; - ndpi_int_change_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); + ndpi_int_change_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); - if(src != NULL) { - NDPI_ADD_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, upper_detected_protocol); + if(src != NULL) { + NDPI_ADD_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, upper_detected_protocol); - if(lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN) - NDPI_ADD_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, lower_detected_protocol); - } + if(lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN) + NDPI_ADD_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, lower_detected_protocol); + } - if(dst != NULL) { - NDPI_ADD_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, upper_detected_protocol); + if(dst != NULL) { + NDPI_ADD_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, upper_detected_protocol); - if(lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN) - NDPI_ADD_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, lower_detected_protocol); - } + if(lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN) + NDPI_ADD_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, lower_detected_protocol); } +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - u_int16_t ndpi_get_flow_masterprotocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { - return(flow->detected_protocol_stack[1]); - } +u_int16_t ndpi_get_flow_masterprotocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { + return(flow->detected_protocol_stack[1]); +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - void ndpi_int_change_flow_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { - if(!flow) - return; +void ndpi_int_change_flow_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + u_int16_t upper_detected_protocol, 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; +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - void ndpi_int_change_packet_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { - struct ndpi_packet_struct *packet = &flow->packet; - /* NOTE: everything below is identically to change_flow_protocol - * except flow->packet If you want to change something here, - * don't! Change it for the flow function and apply it here - * as well */ +void ndpi_int_change_packet_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { + struct ndpi_packet_struct *packet = &flow->packet; + /* NOTE: everything below is identically to change_flow_protocol + * except flow->packet If you want to change something here, + * don't! Change it for the flow function and apply it here + * as well */ - if(!packet) - return; + if(!packet) + return; - packet->detected_protocol_stack[0] = upper_detected_protocol, - packet->detected_protocol_stack[1] = lower_detected_protocol; - } + packet->detected_protocol_stack[0] = upper_detected_protocol, + packet->detected_protocol_stack[1] = lower_detected_protocol; +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - /* generic function for changing the protocol - * - * what it does is: - * 1.update the flow protocol stack with the new protocol - * 2.update the packet protocol stack with the new protocol - */ - void ndpi_int_change_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { - if((upper_detected_protocol == NDPI_PROTOCOL_UNKNOWN) && (lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN)) - upper_detected_protocol = lower_detected_protocol; - - if(upper_detected_protocol == lower_detected_protocol) - lower_detected_protocol = NDPI_PROTOCOL_UNKNOWN; - - if((upper_detected_protocol != NDPI_PROTOCOL_UNKNOWN) && (lower_detected_protocol == NDPI_PROTOCOL_UNKNOWN)) { - if((flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) && - (upper_detected_protocol != flow->guessed_host_protocol_id)) { - if(ndpi_str->proto_defaults[upper_detected_protocol].subprotocol_count > 0) { - lower_detected_protocol = upper_detected_protocol; - upper_detected_protocol = flow->guessed_host_protocol_id; - } +/* generic function for changing the protocol + * + * what it does is: + * 1.update the flow protocol stack with the new protocol + * 2.update the packet protocol stack with the new protocol + */ +void ndpi_int_change_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { + if((upper_detected_protocol == NDPI_PROTOCOL_UNKNOWN) && (lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN)) + upper_detected_protocol = lower_detected_protocol; + + if(upper_detected_protocol == lower_detected_protocol) + lower_detected_protocol = NDPI_PROTOCOL_UNKNOWN; + + if((upper_detected_protocol != NDPI_PROTOCOL_UNKNOWN) && (lower_detected_protocol == NDPI_PROTOCOL_UNKNOWN)) { + if((flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) && + (upper_detected_protocol != flow->guessed_host_protocol_id)) { + if(ndpi_str->proto_defaults[upper_detected_protocol].subprotocol_count > 0) { + lower_detected_protocol = upper_detected_protocol; + upper_detected_protocol = flow->guessed_host_protocol_id; } } - - ndpi_int_change_flow_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); - ndpi_int_change_packet_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); } - /* ********************************************************************************* */ + ndpi_int_change_flow_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); + ndpi_int_change_packet_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); +} - void ndpi_int_change_category(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, - ndpi_protocol_category_t protocol_category) { - flow->category = protocol_category; - } +/* ********************************************************************************* */ - /* ********************************************************************************* */ +void ndpi_int_change_category(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, + ndpi_protocol_category_t protocol_category) { + flow->category = protocol_category; +} - /* turns a packet back to unknown */ - void ndpi_int_reset_packet_protocol(struct ndpi_packet_struct *packet) { - int a; +/* ********************************************************************************* */ - for(a = 0; a < NDPI_PROTOCOL_SIZE; a++) - packet->detected_protocol_stack[a] = NDPI_PROTOCOL_UNKNOWN; - } +/* turns a packet back to unknown */ +void ndpi_int_reset_packet_protocol(struct ndpi_packet_struct *packet) { + int a; - /* ********************************************************************************* */ + for(a = 0; a < NDPI_PROTOCOL_SIZE; a++) + packet->detected_protocol_stack[a] = NDPI_PROTOCOL_UNKNOWN; +} - void ndpi_int_reset_protocol(struct ndpi_flow_struct *flow) { - if(flow) { - int a; +/* ********************************************************************************* */ - for(a = 0; a < NDPI_PROTOCOL_SIZE; a++) - flow->detected_protocol_stack[a] = NDPI_PROTOCOL_UNKNOWN; - } +void ndpi_int_reset_protocol(struct ndpi_flow_struct *flow) { + if(flow) { + int a; + + for(a = 0; a < NDPI_PROTOCOL_SIZE; a++) + flow->detected_protocol_stack[a] = NDPI_PROTOCOL_UNKNOWN; } +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - void NDPI_PROTOCOL_IP_clear(ndpi_ip_addr_t *ip) { - memset(ip, 0, sizeof(ndpi_ip_addr_t)); - } +void NDPI_PROTOCOL_IP_clear(ndpi_ip_addr_t *ip) { + memset(ip, 0, sizeof(ndpi_ip_addr_t)); +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ #ifdef CODE_UNUSED - /* NTOP */ - int NDPI_PROTOCOL_IP_is_set(const ndpi_ip_addr_t *ip) { - return(memcmp(ip, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(ndpi_ip_addr_t)) != 0); - } +/* NTOP */ +int NDPI_PROTOCOL_IP_is_set(const ndpi_ip_addr_t *ip) { + return(memcmp(ip, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(ndpi_ip_addr_t)) != 0); +} #endif - /* ********************************************************************************* */ - - /* check if the source ip address in packet and ip are equal */ - /* NTOP */ - int ndpi_packet_src_ip_eql(const struct ndpi_packet_struct *packet, const ndpi_ip_addr_t *ip) { - /* IPv6 */ - if(packet->iphv6 != NULL) { - if(packet->iphv6->ip6_src.u6_addr.u6_addr32[0] == ip->ipv6.u6_addr.u6_addr32[0] && - packet->iphv6->ip6_src.u6_addr.u6_addr32[1] == ip->ipv6.u6_addr.u6_addr32[1] && - packet->iphv6->ip6_src.u6_addr.u6_addr32[2] == ip->ipv6.u6_addr.u6_addr32[2] && - packet->iphv6->ip6_src.u6_addr.u6_addr32[3] == ip->ipv6.u6_addr.u6_addr32[3]) - return(1); - //else - return(0); - } - - /* IPv4 */ - if(packet->iph->saddr == ip->ipv4) +/* ********************************************************************************* */ + +/* check if the source ip address in packet and ip are equal */ +/* NTOP */ +int ndpi_packet_src_ip_eql(const struct ndpi_packet_struct *packet, const ndpi_ip_addr_t *ip) { + /* IPv6 */ + if(packet->iphv6 != NULL) { + if(packet->iphv6->ip6_src.u6_addr.u6_addr32[0] == ip->ipv6.u6_addr.u6_addr32[0] && + packet->iphv6->ip6_src.u6_addr.u6_addr32[1] == ip->ipv6.u6_addr.u6_addr32[1] && + packet->iphv6->ip6_src.u6_addr.u6_addr32[2] == ip->ipv6.u6_addr.u6_addr32[2] && + packet->iphv6->ip6_src.u6_addr.u6_addr32[3] == ip->ipv6.u6_addr.u6_addr32[3]) return(1); + //else return(0); } - /* ********************************************************************************* */ + /* IPv4 */ + if(packet->iph->saddr == ip->ipv4) + return(1); + return(0); +} - /* check if the destination ip address in packet and ip are equal */ - int ndpi_packet_dst_ip_eql(const struct ndpi_packet_struct *packet, const ndpi_ip_addr_t *ip) { - /* IPv6 */ - if(packet->iphv6 != NULL) { - if(packet->iphv6->ip6_dst.u6_addr.u6_addr32[0] == ip->ipv6.u6_addr.u6_addr32[0] && - packet->iphv6->ip6_dst.u6_addr.u6_addr32[1] == ip->ipv6.u6_addr.u6_addr32[1] && - packet->iphv6->ip6_dst.u6_addr.u6_addr32[2] == ip->ipv6.u6_addr.u6_addr32[2] && - packet->iphv6->ip6_dst.u6_addr.u6_addr32[3] == ip->ipv6.u6_addr.u6_addr32[3]) - return(1); - //else - return(0); - } +/* ********************************************************************************* */ - /* IPv4 */ - if(packet->iph->saddr == ip->ipv4) +/* check if the destination ip address in packet and ip are equal */ +int ndpi_packet_dst_ip_eql(const struct ndpi_packet_struct *packet, const ndpi_ip_addr_t *ip) { + /* IPv6 */ + if(packet->iphv6 != NULL) { + if(packet->iphv6->ip6_dst.u6_addr.u6_addr32[0] == ip->ipv6.u6_addr.u6_addr32[0] && + packet->iphv6->ip6_dst.u6_addr.u6_addr32[1] == ip->ipv6.u6_addr.u6_addr32[1] && + packet->iphv6->ip6_dst.u6_addr.u6_addr32[2] == ip->ipv6.u6_addr.u6_addr32[2] && + packet->iphv6->ip6_dst.u6_addr.u6_addr32[3] == ip->ipv6.u6_addr.u6_addr32[3]) return(1); - + //else return(0); } - /* ********************************************************************************* */ + /* IPv4 */ + if(packet->iph->saddr == ip->ipv4) + return(1); - /* get the source ip address from packet and put it into ip */ - /* NTOP */ - void ndpi_packet_src_ip_get(const struct ndpi_packet_struct *packet, ndpi_ip_addr_t *ip) { - NDPI_PROTOCOL_IP_clear(ip); + return(0); +} - /* IPv6 */ - if(packet->iphv6 != NULL) { - ip->ipv6.u6_addr.u6_addr32[0] = packet->iphv6->ip6_src.u6_addr.u6_addr32[0]; - ip->ipv6.u6_addr.u6_addr32[1] = packet->iphv6->ip6_src.u6_addr.u6_addr32[1]; - ip->ipv6.u6_addr.u6_addr32[2] = packet->iphv6->ip6_src.u6_addr.u6_addr32[2]; - ip->ipv6.u6_addr.u6_addr32[3] = packet->iphv6->ip6_src.u6_addr.u6_addr32[3]; - } else { - /* IPv4 */ - ip->ipv4 = packet->iph->saddr; - } - } +/* ********************************************************************************* */ - /* ********************************************************************************* */ +/* get the source ip address from packet and put it into ip */ +/* NTOP */ +void ndpi_packet_src_ip_get(const struct ndpi_packet_struct *packet, ndpi_ip_addr_t *ip) { + NDPI_PROTOCOL_IP_clear(ip); - /* get the destination ip address from packet and put it into ip */ - /* NTOP */ - void ndpi_packet_dst_ip_get(const struct ndpi_packet_struct *packet, ndpi_ip_addr_t *ip) { - NDPI_PROTOCOL_IP_clear(ip); + /* IPv6 */ + if(packet->iphv6 != NULL) { + ip->ipv6.u6_addr.u6_addr32[0] = packet->iphv6->ip6_src.u6_addr.u6_addr32[0]; + ip->ipv6.u6_addr.u6_addr32[1] = packet->iphv6->ip6_src.u6_addr.u6_addr32[1]; + ip->ipv6.u6_addr.u6_addr32[2] = packet->iphv6->ip6_src.u6_addr.u6_addr32[2]; + ip->ipv6.u6_addr.u6_addr32[3] = packet->iphv6->ip6_src.u6_addr.u6_addr32[3]; + } else { + /* IPv4 */ + ip->ipv4 = packet->iph->saddr; + } +} - if(packet->iphv6 != NULL) { - ip->ipv6.u6_addr.u6_addr32[0] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[0]; - ip->ipv6.u6_addr.u6_addr32[1] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[1]; - ip->ipv6.u6_addr.u6_addr32[2] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[2]; - ip->ipv6.u6_addr.u6_addr32[3] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[3]; +/* ********************************************************************************* */ - } else - ip->ipv4 = packet->iph->daddr; - } +/* get the destination ip address from packet and put it into ip */ +/* NTOP */ +void ndpi_packet_dst_ip_get(const struct ndpi_packet_struct *packet, ndpi_ip_addr_t *ip) { + NDPI_PROTOCOL_IP_clear(ip); - /* ********************************************************************************* */ + if(packet->iphv6 != NULL) { + ip->ipv6.u6_addr.u6_addr32[0] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[0]; + ip->ipv6.u6_addr.u6_addr32[1] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[1]; + ip->ipv6.u6_addr.u6_addr32[2] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[2]; + ip->ipv6.u6_addr.u6_addr32[3] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[3]; - u_int8_t ndpi_is_ipv6(const ndpi_ip_addr_t *ip) { - return(ip->ipv6.u6_addr.u6_addr32[1] != 0 || ip->ipv6.u6_addr.u6_addr32[2] != 0 || - ip->ipv6.u6_addr.u6_addr32[3] != 0); - } + } else + ip->ipv4 = packet->iph->daddr; +} - /* ********************************************************************************* */ +/* ********************************************************************************* */ - char *ndpi_get_ip_string(const ndpi_ip_addr_t *ip, char *buf, u_int buf_len) { - const u_int8_t *a = (const u_int8_t *) &ip->ipv4; +u_int8_t ndpi_is_ipv6(const ndpi_ip_addr_t *ip) { + return(ip->ipv6.u6_addr.u6_addr32[1] != 0 || ip->ipv6.u6_addr.u6_addr32[2] != 0 || + ip->ipv6.u6_addr.u6_addr32[3] != 0); +} - if(ndpi_is_ipv6(ip)) { - if(inet_ntop(AF_INET6, &ip->ipv6.u6_addr, buf, buf_len) == NULL) - buf[0] = '\0'; +/* ********************************************************************************* */ - return(buf); - } +char *ndpi_get_ip_string(const ndpi_ip_addr_t *ip, char *buf, u_int buf_len) { + const u_int8_t *a = (const u_int8_t *) &ip->ipv4; - snprintf(buf, buf_len, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); + if(ndpi_is_ipv6(ip)) { + if(inet_ntop(AF_INET6, &ip->ipv6.u6_addr, buf, buf_len) == NULL) + buf[0] = '\0'; return(buf); } - /* ****************************************************** */ + snprintf(buf, buf_len, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); - /* Returns -1 on failutre, otherwise fills parsed_ip and returns the IP version */ - int ndpi_parse_ip_string(const char *ip_str, ndpi_ip_addr_t *parsed_ip) { - int rv = -1; - memset(parsed_ip, 0, sizeof(*parsed_ip)); + return(buf); +} - if(strchr(ip_str, '.')) { - if(inet_pton(AF_INET, ip_str, &parsed_ip->ipv4) > 0) - rv = 4; - } else { - if(inet_pton(AF_INET6, ip_str, &parsed_ip->ipv6) > 0) - rv = 6; - } +/* ****************************************************** */ + +/* Returns -1 on failutre, otherwise fills parsed_ip and returns the IP version */ +int ndpi_parse_ip_string(const char *ip_str, ndpi_ip_addr_t *parsed_ip) { + int rv = -1; + memset(parsed_ip, 0, sizeof(*parsed_ip)); - return(rv); + if(strchr(ip_str, '.')) { + if(inet_pton(AF_INET, ip_str, &parsed_ip->ipv4) > 0) + rv = 4; + } else { + if(inet_pton(AF_INET6, ip_str, &parsed_ip->ipv6) > 0) + rv = 6; } - /* ****************************************************** */ + return(rv); +} - 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_int16_t val = ndpi_bytestream_to_number(str, max_chars_to_read, bytes_read); - return(ntohs(val)); - } +/* ****************************************************** */ - /* ****************************************************** */ +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_int16_t val = ndpi_bytestream_to_number(str, max_chars_to_read, bytes_read); + return(ntohs(val)); +} - u_int8_t ndpi_is_proto(ndpi_protocol proto, u_int16_t p) { - return(((proto.app_protocol == p) || (proto.master_protocol == p)) ? 1 : 0); - } +/* ****************************************************** */ - /* ****************************************************** */ +u_int8_t ndpi_is_proto(ndpi_protocol proto, u_int16_t p) { + return(((proto.app_protocol == p) || (proto.master_protocol == p)) ? 1 : 0); +} - u_int16_t ndpi_get_lower_proto(ndpi_protocol proto) { - return((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) ? proto.master_protocol : proto.app_protocol); - } +/* ****************************************************** */ - /* ****************************************************** */ +u_int16_t ndpi_get_lower_proto(ndpi_protocol proto) { + return((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) ? proto.master_protocol : proto.app_protocol); +} - u_int16_t ndpi_get_upper_proto(ndpi_protocol proto) { - return((proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) ? proto.app_protocol : proto.master_protocol); - } +/* ****************************************************** */ + +u_int16_t ndpi_get_upper_proto(ndpi_protocol proto) { + return((proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) ? proto.app_protocol : proto.master_protocol); +} /* ****************************************************** */ - ndpi_protocol ndpi_guess_undetected_protocol(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, u_int8_t proto, - u_int32_t shost /* host byte order */, u_int16_t sport, - u_int32_t dhost /* host byte order */, u_int16_t dport) { - u_int32_t rc; - struct in_addr addr; - ndpi_protocol ret = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED}; - u_int8_t user_defined_proto; +ndpi_protocol ndpi_guess_undetected_protocol(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, u_int8_t proto, + u_int32_t shost /* host byte order */, u_int16_t sport, + u_int32_t dhost /* host byte order */, u_int16_t dport) { + u_int32_t rc; + struct in_addr addr; + ndpi_protocol ret = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED}; + u_int8_t user_defined_proto; - if((proto == IPPROTO_TCP) || (proto == IPPROTO_UDP)) { - rc = ndpi_search_tcp_or_udp_raw(ndpi_str, flow, proto, shost, dhost, sport, dport); + if((proto == IPPROTO_TCP) || (proto == IPPROTO_UDP)) { + rc = ndpi_search_tcp_or_udp_raw(ndpi_str, flow, proto, shost, dhost, sport, dport); - if(rc != NDPI_PROTOCOL_UNKNOWN) { - if(flow && (proto == IPPROTO_UDP) && - NDPI_COMPARE_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, rc) && is_udp_guessable_protocol(rc)) - ; - else { - ret.app_protocol = rc, - ret.master_protocol = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); + if(rc != NDPI_PROTOCOL_UNKNOWN) { + if(flow && (proto == IPPROTO_UDP) && + NDPI_COMPARE_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, rc) && is_udp_guessable_protocol(rc)) + ; + else { + ret.app_protocol = rc, + ret.master_protocol = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); - if(ret.app_protocol == ret.master_protocol) - ret.master_protocol = NDPI_PROTOCOL_UNKNOWN; + if(ret.app_protocol == ret.master_protocol) + ret.master_protocol = NDPI_PROTOCOL_UNKNOWN; - ret.category = ndpi_get_proto_category(ndpi_str, ret); - return(ret); - } + ret.category = ndpi_get_proto_category(ndpi_str, ret); + return(ret); } + } - rc = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); - if(rc != NDPI_PROTOCOL_UNKNOWN) { - if(flow && (proto == IPPROTO_UDP) && - NDPI_COMPARE_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, rc) && is_udp_guessable_protocol(rc)) - ; - else { - ret.app_protocol = rc; + rc = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); + if(rc != NDPI_PROTOCOL_UNKNOWN) { + if(flow && (proto == IPPROTO_UDP) && + NDPI_COMPARE_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, rc) && is_udp_guessable_protocol(rc)) + ; + else { + ret.app_protocol = rc; - if(rc == NDPI_PROTOCOL_TLS) - goto check_guessed_skype; - else { - ret.category = ndpi_get_proto_category(ndpi_str, ret); - return(ret); - } + if(rc == NDPI_PROTOCOL_TLS) + goto check_guessed_skype; + else { + ret.category = ndpi_get_proto_category(ndpi_str, ret); + return(ret); } } + } - check_guessed_skype: - addr.s_addr = htonl(shost); - if(ndpi_network_ptree_match(ndpi_str, &addr) == NDPI_PROTOCOL_SKYPE) { + check_guessed_skype: + addr.s_addr = htonl(shost); + if(ndpi_network_ptree_match(ndpi_str, &addr) == NDPI_PROTOCOL_SKYPE) { + ret.app_protocol = NDPI_PROTOCOL_SKYPE; + } else { + addr.s_addr = htonl(dhost); + if(ndpi_network_ptree_match(ndpi_str, &addr) == NDPI_PROTOCOL_SKYPE) ret.app_protocol = NDPI_PROTOCOL_SKYPE; - } else { - addr.s_addr = htonl(dhost); - if(ndpi_network_ptree_match(ndpi_str, &addr) == NDPI_PROTOCOL_SKYPE) - ret.app_protocol = NDPI_PROTOCOL_SKYPE; - } - } else - ret.app_protocol = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); + } + } else + ret.app_protocol = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); - ret.category = ndpi_get_proto_category(ndpi_str, ret); - return(ret); - } + ret.category = ndpi_get_proto_category(ndpi_str, ret); + return(ret); +} + +/* ****************************************************** */ + +char *ndpi_protocol2id(struct ndpi_detection_module_struct *ndpi_str, + ndpi_protocol proto, char *buf, u_int buf_len) { + if((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (proto.master_protocol != proto.app_protocol)) { + if(proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) + snprintf(buf, buf_len, "%u.%u", proto.master_protocol, proto.app_protocol); + else + snprintf(buf, buf_len, "%u", proto.master_protocol); + } else + snprintf(buf, buf_len, "%u", proto.app_protocol); - /* ****************************************************** */ + return(buf); +} + +/* ****************************************************** */ - char *ndpi_protocol2id(struct ndpi_detection_module_struct *ndpi_str, +char *ndpi_protocol2name(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol proto, char *buf, u_int buf_len) { - if((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (proto.master_protocol != proto.app_protocol)) { - if(proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) - snprintf(buf, buf_len, "%u.%u", proto.master_protocol, proto.app_protocol); - else - snprintf(buf, buf_len, "%u", proto.master_protocol); - } else - snprintf(buf, buf_len, "%u", proto.app_protocol); + if((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (proto.master_protocol != proto.app_protocol)) { + if(proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) + snprintf(buf, buf_len, "%s.%s", ndpi_get_proto_name(ndpi_str, proto.master_protocol), + ndpi_get_proto_name(ndpi_str, proto.app_protocol)); + else + snprintf(buf, buf_len, "%s", ndpi_get_proto_name(ndpi_str, proto.master_protocol)); + } else + snprintf(buf, buf_len, "%s", ndpi_get_proto_name(ndpi_str, proto.app_protocol)); - return(buf); + return(buf); +} + +/* ****************************************************** */ + +int ndpi_is_custom_category(ndpi_protocol_category_t category) { + switch(category) { + case NDPI_PROTOCOL_CATEGORY_CUSTOM_1: + case NDPI_PROTOCOL_CATEGORY_CUSTOM_2: + case NDPI_PROTOCOL_CATEGORY_CUSTOM_3: + case NDPI_PROTOCOL_CATEGORY_CUSTOM_4: + case NDPI_PROTOCOL_CATEGORY_CUSTOM_5: + return(1); + break; + + default: + return(0); + break; } +} - /* ****************************************************** */ +/* ****************************************************** */ - char *ndpi_protocol2name(struct ndpi_detection_module_struct *ndpi_str, - ndpi_protocol proto, char *buf, u_int buf_len) { - if((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (proto.master_protocol != proto.app_protocol)) { - if(proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) - snprintf(buf, buf_len, "%s.%s", ndpi_get_proto_name(ndpi_str, proto.master_protocol), - ndpi_get_proto_name(ndpi_str, proto.app_protocol)); - else - snprintf(buf, buf_len, "%s", ndpi_get_proto_name(ndpi_str, proto.master_protocol)); - } else - snprintf(buf, buf_len, "%s", ndpi_get_proto_name(ndpi_str, proto.app_protocol)); +void ndpi_category_set_name(struct ndpi_detection_module_struct *ndpi_str, + ndpi_protocol_category_t category, + char *name) { + if(!name) + return; - return(buf); + switch(category) { + case NDPI_PROTOCOL_CATEGORY_CUSTOM_1: + snprintf(ndpi_str->custom_category_labels[0], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); + break; + + case NDPI_PROTOCOL_CATEGORY_CUSTOM_2: + snprintf(ndpi_str->custom_category_labels[1], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); + break; + + case NDPI_PROTOCOL_CATEGORY_CUSTOM_3: + snprintf(ndpi_str->custom_category_labels[2], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); + break; + + case NDPI_PROTOCOL_CATEGORY_CUSTOM_4: + snprintf(ndpi_str->custom_category_labels[3], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); + break; + + case NDPI_PROTOCOL_CATEGORY_CUSTOM_5: + snprintf(ndpi_str->custom_category_labels[4], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); + break; + + default: + break; } +} + +/* ****************************************************** */ + +const char *ndpi_category_get_name(struct ndpi_detection_module_struct *ndpi_str, + ndpi_protocol_category_t category) { + if((!ndpi_str) || (category >= NDPI_PROTOCOL_NUM_CATEGORIES)) { + static char b[24]; - /* ****************************************************** */ + if(!ndpi_str) + snprintf(b, sizeof(b), "NULL nDPI"); + else + snprintf(b, sizeof(b), "Invalid category %d", (int) category); + return(b); + } - int ndpi_is_custom_category(ndpi_protocol_category_t category) { + if((category >= NDPI_PROTOCOL_CATEGORY_CUSTOM_1) && (category <= NDPI_PROTOCOL_CATEGORY_CUSTOM_5)) { switch(category) { case NDPI_PROTOCOL_CATEGORY_CUSTOM_1: + return(ndpi_str->custom_category_labels[0]); case NDPI_PROTOCOL_CATEGORY_CUSTOM_2: + return(ndpi_str->custom_category_labels[1]); case NDPI_PROTOCOL_CATEGORY_CUSTOM_3: + return(ndpi_str->custom_category_labels[2]); case NDPI_PROTOCOL_CATEGORY_CUSTOM_4: + return(ndpi_str->custom_category_labels[3]); case NDPI_PROTOCOL_CATEGORY_CUSTOM_5: - return(1); - break; - + return(ndpi_str->custom_category_labels[4]); + case NDPI_PROTOCOL_NUM_CATEGORIES: + return("Code should not use this internal constant"); default: - return(0); - break; + return("Unspecified"); } - } + } else + return(categories[category]); +} - /* ****************************************************** */ +/* ****************************************************** */ - void ndpi_category_set_name(struct ndpi_detection_module_struct *ndpi_str, - ndpi_protocol_category_t category, - char *name) { - if(!name) - return; +ndpi_protocol_category_t ndpi_get_proto_category(struct ndpi_detection_module_struct *ndpi_str, + ndpi_protocol proto) { + if(proto.category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) + return(proto.category); - switch(category) { - case NDPI_PROTOCOL_CATEGORY_CUSTOM_1: - snprintf(ndpi_str->custom_category_labels[0], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); - break; + /* simple rule: sub protocol first, master after */ + else if((proto.master_protocol == NDPI_PROTOCOL_UNKNOWN) || + (ndpi_str->proto_defaults[proto.app_protocol].protoCategory != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED)) { + if(proto.app_protocol < (NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) + return(ndpi_str->proto_defaults[proto.app_protocol].protoCategory); + } else if(proto.master_protocol < (NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) + return(ndpi_str->proto_defaults[proto.master_protocol].protoCategory); - case NDPI_PROTOCOL_CATEGORY_CUSTOM_2: - snprintf(ndpi_str->custom_category_labels[1], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); - break; + return(NDPI_PROTOCOL_CATEGORY_UNSPECIFIED); +} - case NDPI_PROTOCOL_CATEGORY_CUSTOM_3: - snprintf(ndpi_str->custom_category_labels[2], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); - break; +/* ****************************************************** */ - case NDPI_PROTOCOL_CATEGORY_CUSTOM_4: - snprintf(ndpi_str->custom_category_labels[3], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); - break; +char *ndpi_get_proto_name(struct ndpi_detection_module_struct *ndpi_str, + u_int16_t proto_id) { + if((proto_id >= ndpi_str->ndpi_num_supported_protocols) || + (proto_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) || + (ndpi_str->proto_defaults[proto_id].protoName == NULL)) + proto_id = NDPI_PROTOCOL_UNKNOWN; - case NDPI_PROTOCOL_CATEGORY_CUSTOM_5: - snprintf(ndpi_str->custom_category_labels[4], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); - break; + return(ndpi_str->proto_defaults[proto_id].protoName); +} - default: - break; - } - } +/* ****************************************************** */ - /* ****************************************************** */ +ndpi_protocol_breed_t ndpi_get_proto_breed(struct ndpi_detection_module_struct *ndpi_str, + u_int16_t proto_id) { + if((proto_id >= ndpi_str->ndpi_num_supported_protocols) || + (proto_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) || + (ndpi_str->proto_defaults[proto_id].protoName == NULL)) + proto_id = NDPI_PROTOCOL_UNKNOWN; - const char *ndpi_category_get_name(struct ndpi_detection_module_struct *ndpi_str, - ndpi_protocol_category_t category) { - if((!ndpi_str) || (category >= NDPI_PROTOCOL_NUM_CATEGORIES)) { - static char b[24]; + return(ndpi_str->proto_defaults[proto_id].protoBreed); +} - if(!ndpi_str) - snprintf(b, sizeof(b), "NULL nDPI"); - else - snprintf(b, sizeof(b), "Invalid category %d", (int) category); - return(b); - } +/* ****************************************************** */ - if((category >= NDPI_PROTOCOL_CATEGORY_CUSTOM_1) && (category <= NDPI_PROTOCOL_CATEGORY_CUSTOM_5)) { - switch(category) { - case NDPI_PROTOCOL_CATEGORY_CUSTOM_1: - return(ndpi_str->custom_category_labels[0]); - case NDPI_PROTOCOL_CATEGORY_CUSTOM_2: - return(ndpi_str->custom_category_labels[1]); - case NDPI_PROTOCOL_CATEGORY_CUSTOM_3: - return(ndpi_str->custom_category_labels[2]); - case NDPI_PROTOCOL_CATEGORY_CUSTOM_4: - return(ndpi_str->custom_category_labels[3]); - case NDPI_PROTOCOL_CATEGORY_CUSTOM_5: - return(ndpi_str->custom_category_labels[4]); - case NDPI_PROTOCOL_NUM_CATEGORIES: - return("Code should not use this internal constant"); - default: - return("Unspecified"); - } - } else - return(categories[category]); +char *ndpi_get_proto_breed_name(struct ndpi_detection_module_struct *ndpi_str, + ndpi_protocol_breed_t breed_id) { + switch(breed_id) { + case NDPI_PROTOCOL_SAFE: + return("Safe"); + break; + case NDPI_PROTOCOL_ACCEPTABLE: + return("Acceptable"); + break; + case NDPI_PROTOCOL_FUN: + return("Fun"); + break; + case NDPI_PROTOCOL_UNSAFE: + return("Unsafe"); + break; + case NDPI_PROTOCOL_POTENTIALLY_DANGEROUS: + return("Potentially Dangerous"); + break; + case NDPI_PROTOCOL_TRACKER_ADS: + return("Tracker/Ads"); + break; + case NDPI_PROTOCOL_DANGEROUS: + return("Dangerous"); + break; + case NDPI_PROTOCOL_UNRATED: + return("Unrated"); + break; + default: + return("???"); + break; } +} + +/* ****************************************************** */ - /* ****************************************************** */ +int ndpi_get_protocol_id(struct ndpi_detection_module_struct *ndpi_str, char *proto) { + int i; - ndpi_protocol_category_t ndpi_get_proto_category(struct ndpi_detection_module_struct *ndpi_str, - ndpi_protocol proto) { - if(proto.category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) - return(proto.category); + for(i = 0; i < (int) ndpi_str->ndpi_num_supported_protocols; i++) + if(strcasecmp(proto, ndpi_str->proto_defaults[i].protoName) == 0) + return(i); - /* simple rule: sub protocol first, master after */ - else if((proto.master_protocol == NDPI_PROTOCOL_UNKNOWN) || - (ndpi_str->proto_defaults[proto.app_protocol].protoCategory != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED)) { - if(proto.app_protocol < (NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) - return(ndpi_str->proto_defaults[proto.app_protocol].protoCategory); - } else if(proto.master_protocol < (NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) - return(ndpi_str->proto_defaults[proto.master_protocol].protoCategory); + return(-1); +} - return(NDPI_PROTOCOL_CATEGORY_UNSPECIFIED); - } +/* ****************************************************** */ - /* ****************************************************** */ +int ndpi_get_category_id(struct ndpi_detection_module_struct *ndpi_str, char *cat) { + int i; - char *ndpi_get_proto_name(struct ndpi_detection_module_struct *ndpi_str, - u_int16_t proto_id) { - if((proto_id >= ndpi_str->ndpi_num_supported_protocols) || - (proto_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) || - (ndpi_str->proto_defaults[proto_id].protoName == NULL)) - proto_id = NDPI_PROTOCOL_UNKNOWN; + for(i = 0; i < NDPI_PROTOCOL_NUM_CATEGORIES; i++) { + const char *name = ndpi_category_get_name(ndpi_str, i); - return(ndpi_str->proto_defaults[proto_id].protoName); + if(strcasecmp(cat, name) == 0) + return(i); } - /* ****************************************************** */ + return(-1); +} + +/* ****************************************************** */ - ndpi_protocol_breed_t ndpi_get_proto_breed(struct ndpi_detection_module_struct *ndpi_str, - u_int16_t proto_id) { - if((proto_id >= ndpi_str->ndpi_num_supported_protocols) || - (proto_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) || - (ndpi_str->proto_defaults[proto_id].protoName == NULL)) - proto_id = NDPI_PROTOCOL_UNKNOWN; +void ndpi_dump_protocols(struct ndpi_detection_module_struct *ndpi_str) { + int i; - return(ndpi_str->proto_defaults[proto_id].protoBreed); - } + for(i = 0; i < (int) ndpi_str->ndpi_num_supported_protocols; i++) + printf("%3d %-22s %-8s %-12s %s\n", i, ndpi_str->proto_defaults[i].protoName, + ndpi_get_l4_proto_name(ndpi_get_l4_proto_info(ndpi_str, i)), + ndpi_get_proto_breed_name(ndpi_str, ndpi_str->proto_defaults[i].protoBreed), + ndpi_category_get_name(ndpi_str, ndpi_str->proto_defaults[i].protoCategory)); +} - /* ****************************************************** */ +/* ****************************************************** */ - char *ndpi_get_proto_breed_name(struct ndpi_detection_module_struct *ndpi_str, - ndpi_protocol_breed_t breed_id) { - switch(breed_id) { - case NDPI_PROTOCOL_SAFE: - return("Safe"); - break; - case NDPI_PROTOCOL_ACCEPTABLE: - return("Acceptable"); - break; - case NDPI_PROTOCOL_FUN: - return("Fun"); - break; - case NDPI_PROTOCOL_UNSAFE: - return("Unsafe"); - break; - case NDPI_PROTOCOL_POTENTIALLY_DANGEROUS: - return("Potentially Dangerous"); - break; - case NDPI_PROTOCOL_TRACKER_ADS: - return("Tracker/Ads"); +void ndpi_dump_risks_score() { + u_int i; + + printf("%3s %-48s %-8s %s\n", + "Id", "Risk", "Severity", "Score"); + + for(i = 1; i < NDPI_MAX_RISK; i++) { + ndpi_risk_enum r = (ndpi_risk_enum)i; + ndpi_risk_severity s = ndpi_risk2severity(r); + u_int16_t score; + + switch(s) { + case NDPI_RISK_LOW: + score = NDPI_SCORE_RISK_LOW; break; - case NDPI_PROTOCOL_DANGEROUS: - return("Dangerous"); + + case NDPI_RISK_MEDIUM: + score = NDPI_SCORE_RISK_MEDIUM; break; - case NDPI_PROTOCOL_UNRATED: - return("Unrated"); + + case NDPI_RISK_HIGH: + score = NDPI_SCORE_RISK_HIGH; break; - default: - return("???"); + + case NDPI_RISK_SEVERE: + score = NDPI_SCORE_RISK_SEVERE; break; } + + printf("%3d %-48s %-8s %u\n", + i, ndpi_risk2str(r), + ndpi_severity2str(s), + score); } +} - /* ****************************************************** */ +/* ****************************************************** */ - int ndpi_get_protocol_id(struct ndpi_detection_module_struct *ndpi_str, char *proto) { - int i; +/* + * Find the first occurrence of find in s, where the search is limited to the + * first slen characters of s. + */ +char *ndpi_strnstr(const char *s, const char *find, size_t slen) { + char c; + size_t len; - for(i = 0; i < (int) ndpi_str->ndpi_num_supported_protocols; i++) - if(strcasecmp(proto, ndpi_str->proto_defaults[i].protoName) == 0) - return(i); + if((c = *find++) != '\0') { + len = strnlen(find, slen); + do { + char sc; - return(-1); + do { + if(slen-- < 1 || (sc = *s++) == '\0') + return(NULL); + } while(sc != c); + if(len > slen) + return(NULL); + } while(strncmp(s, find, len) != 0); + s--; } - /* ****************************************************** */ + return((char *) s); +} - int ndpi_get_category_id(struct ndpi_detection_module_struct *ndpi_str, char *cat) { - int i; +/* ****************************************************** */ - for(i = 0; i < NDPI_PROTOCOL_NUM_CATEGORIES; i++) { - const char *name = ndpi_category_get_name(ndpi_str, i); +/* + * Same as ndpi_strnstr but case-insensitive + */ +const char * ndpi_strncasestr(const char *str1, const char *str2, size_t len) { + size_t str1_len = strnlen(str1, len); + size_t str2_len = strlen(str2); + size_t i; - if(strcasecmp(cat, name) == 0) - return(i); - } + for(i = 0; i < (str1_len - str2_len + 1); i++){ + if(str1[0] == '\0') + return NULL; + else if(strncasecmp(str1, str2, str2_len) == 0) + return(str1); - return(-1); + str1++; } - /* ****************************************************** */ + return NULL; +} - void ndpi_dump_protocols(struct ndpi_detection_module_struct *ndpi_str) { - int i; +/* ****************************************************** */ - for(i = 0; i < (int) ndpi_str->ndpi_num_supported_protocols; i++) - printf("%3d %-22s %-8s %-12s %s\n", i, ndpi_str->proto_defaults[i].protoName, - ndpi_get_l4_proto_name(ndpi_get_l4_proto_info(ndpi_str, i)), - ndpi_get_proto_breed_name(ndpi_str, ndpi_str->proto_defaults[i].protoBreed), - ndpi_category_get_name(ndpi_str, ndpi_str->proto_defaults[i].protoCategory)); - } +int ndpi_match_prefix(const u_int8_t *payload, + size_t payload_len, const char *str, size_t str_len) { + int rc = str_len <= payload_len ? memcmp(payload, str, str_len) == 0 : 0; - /* ****************************************************** */ + return(rc); +} - /* - * Find the first occurrence of find in s, where the search is limited to the - * first slen characters of s. - */ - char *ndpi_strnstr(const char *s, const char *find, size_t slen) { - char c; - size_t len; +/* ****************************************************** */ - if((c = *find++) != '\0') { - len = strnlen(find, slen); - do { - char sc; +int ndpi_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_str, char *string_to_match, + u_int string_to_match_len, ndpi_protocol_match_result *ret_match, + u_int8_t is_host_match) { + AC_TEXT_t ac_input_text; + ndpi_automa *automa = is_host_match ? &ndpi_str->host_automa : &ndpi_str->content_automa; + AC_REP_t match = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED}; + int rc; - do { - if(slen-- < 1 || (sc = *s++) == '\0') - return(NULL); - } while(sc != c); - if(len > slen) - return(NULL); - } while(strncmp(s, find, len) != 0); - s--; - } + if((automa->ac_automa == NULL) || (string_to_match_len == 0)) + return(NDPI_PROTOCOL_UNKNOWN); - return((char *) s); + if(!automa->ac_automa_finalized) { + printf("[%s:%d] [NDPI] Internal error: please call ndpi_finalize_initialization()\n", __FILE__, __LINE__); + return(0); /* No matches */ } - /* ****************************************************** */ + ac_input_text.astring = string_to_match, ac_input_text.length = string_to_match_len; + rc = ac_automata_search(((AC_AUTOMATA_t *) automa->ac_automa), &ac_input_text, &match); /* - * Same as ndpi_strnstr but case-insensitive - */ - const char * ndpi_strncasestr(const char *str1, const char *str2, size_t len) { - size_t str1_len = strnlen(str1, len); - size_t str2_len = strlen(str2); - size_t i; - - for(i = 0; i < (str1_len - str2_len + 1); i++){ - if(str1[0] == '\0') - return NULL; - else if(strncasecmp(str1, str2, str2_len) == 0) - return(str1); - - str1++; - } - - return NULL; - } - - /* ****************************************************** */ - - int ndpi_match_prefix(const u_int8_t *payload, - size_t payload_len, const char *str, size_t str_len) { - int rc = str_len <= payload_len ? memcmp(payload, str, str_len) == 0 : 0; - - return(rc); - } - - /* ****************************************************** */ - - int ndpi_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_str, char *string_to_match, - u_int string_to_match_len, ndpi_protocol_match_result *ret_match, - u_int8_t is_host_match) { - AC_TEXT_t ac_input_text; - ndpi_automa *automa = is_host_match ? &ndpi_str->host_automa : &ndpi_str->content_automa; - AC_REP_t match = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED}; - int rc; + As ac_automata_search can detect partial matches and continue the search process + in case rc == 0 (i.e. no match), we need to check if there is a partial match + and in this case return it + */ + if((rc == 0) && (match.number != 0)) + rc = 1; - if((automa->ac_automa == NULL) || (string_to_match_len == 0)) - return(NDPI_PROTOCOL_UNKNOWN); + /* We need to take into account also rc == 0 that is used for partial matches */ + ret_match->protocol_id = match.number, ret_match->protocol_category = match.category, + ret_match->protocol_breed = match.breed; - if(!automa->ac_automa_finalized) { - printf("[%s:%d] [NDPI] Internal error: please call ndpi_finalize_initialization()\n", __FILE__, __LINE__); - return(0); /* No matches */ - } + return(rc ? match.number : 0); +} - ac_input_text.astring = string_to_match, ac_input_text.length = string_to_match_len; - rc = ac_automata_search(((AC_AUTOMATA_t *) automa->ac_automa), &ac_input_text, &match); +/* **************************************** */ - /* - As ac_automata_search can detect partial matches and continue the search process - in case rc == 0 (i.e. no match), we need to check if there is a partial match - and in this case return it - */ - if((rc == 0) && (match.number != 0)) - rc = 1; +static u_int8_t ndpi_is_more_generic_protocol(u_int16_t previous_proto, u_int16_t new_proto) { + /* Sometimes certificates are more generic than previously identified protocols */ - /* We need to take into account also rc == 0 that is used for partial matches */ - ret_match->protocol_id = match.number, ret_match->protocol_category = match.category, - ret_match->protocol_breed = match.breed; + if((previous_proto == NDPI_PROTOCOL_UNKNOWN) || (previous_proto == new_proto)) + return(0); - return(rc ? match.number : 0); + switch(previous_proto) { + case NDPI_PROTOCOL_WHATSAPP_CALL: + case NDPI_PROTOCOL_WHATSAPP_FILES: + if(new_proto == NDPI_PROTOCOL_WHATSAPP) + return(1); } - /* **************************************** */ - - static u_int8_t ndpi_is_more_generic_protocol(u_int16_t previous_proto, u_int16_t new_proto) { - /* Sometimes certificates are more generic than previously identified protocols */ - - if((previous_proto == NDPI_PROTOCOL_UNKNOWN) || (previous_proto == new_proto)) - return(0); - - switch(previous_proto) { - case NDPI_PROTOCOL_WHATSAPP_CALL: - case NDPI_PROTOCOL_WHATSAPP_FILES: - if(new_proto == NDPI_PROTOCOL_WHATSAPP) - return(1); - } - - return(0); - } + return(0); +} - /* ****************************************************** */ +/* ****************************************************** */ - static u_int16_t ndpi_automa_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_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; - struct ndpi_packet_struct *packet = &flow->packet; +static u_int16_t ndpi_automa_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_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; + struct ndpi_packet_struct *packet = &flow->packet; - matching_protocol_id = - ndpi_match_string_subprotocol(ndpi_str, string_to_match, string_to_match_len, ret_match, is_host_match); + matching_protocol_id = + ndpi_match_string_subprotocol(ndpi_str, string_to_match, string_to_match_len, ret_match, is_host_match); #ifdef DEBUG - { - char m[256]; - int len = ndpi_min(sizeof(m), string_to_match_len); + { + char m[256]; + int len = ndpi_min(sizeof(m), string_to_match_len); - strncpy(m, string_to_match, len); - m[len] = '\0'; + strncpy(m, string_to_match, len); + m[len] = '\0'; - NDPI_LOG_DBG2(ndpi_str, "[NDPI] ndpi_match_host_subprotocol(%s): %s\n", m, - ndpi_str->proto_defaults[matching_protocol_id].protoName); - } + NDPI_LOG_DBG2(ndpi_str, "[NDPI] ndpi_match_host_subprotocol(%s): %s\n", m, + ndpi_str->proto_defaults[matching_protocol_id].protoName); + } #endif - if((matching_protocol_id != NDPI_PROTOCOL_UNKNOWN) && - (!ndpi_is_more_generic_protocol(packet->detected_protocol_stack[0], matching_protocol_id))) { - /* Move the protocol on slot 0 down one position */ - packet->detected_protocol_stack[1] = master_protocol_id, - packet->detected_protocol_stack[0] = matching_protocol_id; + if((matching_protocol_id != NDPI_PROTOCOL_UNKNOWN) && + (!ndpi_is_more_generic_protocol(packet->detected_protocol_stack[0], matching_protocol_id))) { + /* Move the protocol on slot 0 down one position */ + packet->detected_protocol_stack[1] = master_protocol_id, + 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[0] = packet->detected_protocol_stack[0], + flow->detected_protocol_stack[1] = packet->detected_protocol_stack[1]; - if(flow->category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) - flow->category = ret_match->protocol_category; + if(flow->category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) + flow->category = ret_match->protocol_category; - return(packet->detected_protocol_stack[0]); - } + return(packet->detected_protocol_stack[0]); + } #ifdef DEBUG - string_to_match[string_to_match_len] = '\0'; - NDPI_LOG_DBG2(ndpi_str, "[NTOP] Unable to find a match for '%s'\n", string_to_match); + string_to_match[string_to_match_len] = '\0'; + NDPI_LOG_DBG2(ndpi_str, "[NTOP] Unable to find a match for '%s'\n", string_to_match); #endif - ret_match->protocol_id = NDPI_PROTOCOL_UNKNOWN, ret_match->protocol_category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, - ret_match->protocol_breed = NDPI_PROTOCOL_UNRATED; + ret_match->protocol_id = NDPI_PROTOCOL_UNKNOWN, ret_match->protocol_category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, + ret_match->protocol_breed = NDPI_PROTOCOL_UNRATED; - return(NDPI_PROTOCOL_UNKNOWN); - } + return(NDPI_PROTOCOL_UNKNOWN); +} - /* ****************************************************** */ +/* ****************************************************** */ - void ndpi_check_subprotocol_risk(struct ndpi_flow_struct *flow, u_int16_t subprotocol_id) { - switch(subprotocol_id) { - case NDPI_PROTOCOL_ANYDESK: - ndpi_set_risk(flow, NDPI_DESKTOP_OR_FILE_SHARING_SESSION); /* Remote assistance */ - break; - } +void ndpi_check_subprotocol_risk(struct ndpi_flow_struct *flow, u_int16_t subprotocol_id) { + switch(subprotocol_id) { + case NDPI_PROTOCOL_ANYDESK: + ndpi_set_risk(flow, NDPI_DESKTOP_OR_FILE_SHARING_SESSION); /* Remote assistance */ + break; } +} - /* ****************************************************** */ +/* ****************************************************** */ - u_int16_t ndpi_match_host_subprotocol(struct ndpi_detection_module_struct *ndpi_str, - 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) { - u_int16_t rc, buf_len, i; - ndpi_protocol_category_t id; - char buf[96]; +u_int16_t ndpi_match_host_subprotocol(struct ndpi_detection_module_struct *ndpi_str, + 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) { + u_int16_t rc, buf_len, i; + ndpi_protocol_category_t id; + char buf[96]; - buf_len = ndpi_min(string_to_match_len, sizeof(buf)-2); - for(i=0; i<buf_len; i++) buf[i] = tolower(string_to_match[i]); - buf[i++] = '$'; /* Add trailer $ */ - buf[i] = '\0'; + buf_len = ndpi_min(string_to_match_len, sizeof(buf)-2); + for(i=0; i<buf_len; i++) buf[i] = tolower(string_to_match[i]); + buf[i++] = '$'; /* Add trailer $ */ + buf[i] = '\0'; - rc = ndpi_automa_match_string_subprotocol(ndpi_str, flow, buf, i, - master_protocol_id, ret_match, 1); - id = ret_match->protocol_category; + rc = ndpi_automa_match_string_subprotocol(ndpi_str, flow, buf, i, + master_protocol_id, ret_match, 1); + id = ret_match->protocol_category; - if(ndpi_get_custom_category_match(ndpi_str, buf, i, &id) != -1) { - /* if(id != -1) */ { - flow->category = ret_match->protocol_category = id; - rc = master_protocol_id; - } + if(ndpi_get_custom_category_match(ndpi_str, buf, i, &id) != -1) { + /* if(id != -1) */ { + flow->category = ret_match->protocol_category = id; + rc = master_protocol_id; } + } - if(ndpi_str->risky_domain_automa.ac_automa != NULL) { - u_int16_t rc1 = ndpi_match_string(ndpi_str->risky_domain_automa.ac_automa, buf); + if(ndpi_str->risky_domain_automa.ac_automa != NULL) { + u_int16_t rc1 = ndpi_match_string(ndpi_str->risky_domain_automa.ac_automa, buf); - if(rc1 > 0) - ndpi_set_risk(flow, NDPI_RISKY_DOMAIN); - } - - return(rc); + if(rc1 > 0) + ndpi_set_risk(flow, NDPI_RISKY_DOMAIN); } - /* **************************************** */ + return(rc); +} - int ndpi_match_hostname_protocol(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, - u_int16_t master_protocol, char *name, u_int name_len) { - ndpi_protocol_match_result ret_match; - u_int16_t subproto, what_len; - char *what; +/* **************************************** */ - if((name_len > 2) && (name[0] == '*') && (name[1] == '.')) - what = &name[1], what_len = name_len - 1; - else - what = name, what_len = name_len; +int ndpi_match_hostname_protocol(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + u_int16_t master_protocol, char *name, u_int name_len) { + ndpi_protocol_match_result ret_match; + u_int16_t subproto, what_len; + char *what; - subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, what, what_len, - &ret_match, master_protocol); + if((name_len > 2) && (name[0] == '*') && (name[1] == '.')) + what = &name[1], what_len = name_len - 1; + else + what = name, what_len = name_len; - if(subproto != NDPI_PROTOCOL_UNKNOWN) { - ndpi_set_detected_protocol(ndpi_struct, flow, subproto, master_protocol); - ndpi_int_change_category(ndpi_struct, flow, ret_match.protocol_category); - return(1); - } else - return(0); - } + subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, what, what_len, + &ret_match, master_protocol); - /* ****************************************************** */ + if(subproto != NDPI_PROTOCOL_UNKNOWN) { + ndpi_set_detected_protocol(ndpi_struct, flow, subproto, master_protocol); + ndpi_int_change_category(ndpi_struct, flow, ret_match.protocol_category); + return(1); + } else + return(0); +} - u_int16_t ndpi_match_content_subprotocol(struct ndpi_detection_module_struct *ndpi_str, - 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_str, flow, string_to_match, string_to_match_len, - master_protocol_id, ret_match, 0)); - } +/* ****************************************************** */ - /* ****************************************************** */ +u_int16_t ndpi_match_content_subprotocol(struct ndpi_detection_module_struct *ndpi_str, + 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_str, flow, string_to_match, string_to_match_len, + master_protocol_id, ret_match, 0)); +} - int ndpi_match_bigram(struct ndpi_detection_module_struct *ndpi_str, - ndpi_automa *automa, char *bigram_to_match) { - AC_TEXT_t ac_input_text; - AC_REP_t match = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED}; - int rc; +/* ****************************************************** */ - if((automa->ac_automa == NULL) || (bigram_to_match == NULL)) - return(-1); +int ndpi_match_bigram(struct ndpi_detection_module_struct *ndpi_str, + ndpi_automa *automa, char *bigram_to_match) { + AC_TEXT_t ac_input_text; + AC_REP_t match = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED}; + int rc; + + if((automa->ac_automa == NULL) || (bigram_to_match == NULL)) + return(-1); - if(!automa->ac_automa_finalized) { + if(!automa->ac_automa_finalized) { #if 1 - ndpi_finalize_initialization(ndpi_str); + ndpi_finalize_initialization(ndpi_str); #else - printf("[%s:%d] [NDPI] Internal error: please call ndpi_finalize_initialization()\n", __FILE__, __LINE__); - return(0); /* No matches */ + printf("[%s:%d] [NDPI] Internal error: please call ndpi_finalize_initialization()\n", __FILE__, __LINE__); + return(0); /* No matches */ #endif - } + } - ac_input_text.astring = bigram_to_match, ac_input_text.length = 2; - rc = ac_automata_search(((AC_AUTOMATA_t *) automa->ac_automa), &ac_input_text, &match); + ac_input_text.astring = bigram_to_match, ac_input_text.length = 2; + rc = ac_automata_search(((AC_AUTOMATA_t *) automa->ac_automa), &ac_input_text, &match); - /* - As ac_automata_search can detect partial matches and continue the search process - in case rc == 0 (i.e. no match), we need to check if there is a partial match - and in this case return it - */ - if((rc == 0) && (match.number != 0)) - rc = 1; + /* + As ac_automata_search can detect partial matches and continue the search process + in case rc == 0 (i.e. no match), we need to check if there is a partial match + and in this case return it + */ + if((rc == 0) && (match.number != 0)) + rc = 1; - return(rc ? match.number : 0); - } + return(rc ? match.number : 0); +} - /* ****************************************************** */ +/* ****************************************************** */ - int ndpi_match_trigram(struct ndpi_detection_module_struct *ndpi_str, - ndpi_automa *automa, char *trigram_to_match) { - AC_TEXT_t ac_input_text; - AC_REP_t match = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED}; - int rc; +int ndpi_match_trigram(struct ndpi_detection_module_struct *ndpi_str, + ndpi_automa *automa, char *trigram_to_match) { + AC_TEXT_t ac_input_text; + AC_REP_t match = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED}; + int rc; - if((automa->ac_automa == NULL) || (trigram_to_match == NULL)) - return(-1); + if((automa->ac_automa == NULL) || (trigram_to_match == NULL)) + return(-1); - if(!automa->ac_automa_finalized) { + if(!automa->ac_automa_finalized) { #if 1 - ndpi_finalize_initialization(ndpi_str); + ndpi_finalize_initialization(ndpi_str); #else - printf("[%s:%d] [NDPI] Internal error: please call ndpi_finalize_initialization()\n", __FILE__, __LINE__); - return(0); /* No matches */ + printf("[%s:%d] [NDPI] Internal error: please call ndpi_finalize_initialization()\n", __FILE__, __LINE__); + return(0); /* No matches */ #endif - } + } - ac_input_text.astring = trigram_to_match, ac_input_text.length = 3; - rc = ac_automata_search(((AC_AUTOMATA_t *) automa->ac_automa), &ac_input_text, &match); + ac_input_text.astring = trigram_to_match, ac_input_text.length = 3; + rc = ac_automata_search(((AC_AUTOMATA_t *) automa->ac_automa), &ac_input_text, &match); - /* - As ac_automata_search can detect partial matches and continue the search process - in case rc == 0 (i.e. no match), we need to check if there is a partial match - and in this case return it - */ - if((rc == 0) && (match.number != 0)) - rc = 1; - - if(ndpi_verbose_dga_detection && rc && match.number) { - printf("[%s:%d] [NDPI] Trigram %c%c%c\n", - __FILE__, __LINE__, - trigram_to_match[0], - trigram_to_match[1], - trigram_to_match[2]); - } + /* + As ac_automata_search can detect partial matches and continue the search process + in case rc == 0 (i.e. no match), we need to check if there is a partial match + and in this case return it + */ + if((rc == 0) && (match.number != 0)) + rc = 1; - return(rc ? match.number : 0); + if(ndpi_verbose_dga_detection && rc && match.number) { + printf("[%s:%d] [NDPI] Trigram %c%c%c\n", + __FILE__, __LINE__, + trigram_to_match[0], + trigram_to_match[1], + trigram_to_match[2]); } - /* ****************************************************** */ + return(rc ? match.number : 0); +} - void ndpi_free_flow(struct ndpi_flow_struct *flow) { - if(flow) { - ndpi_free_flow_data(flow); - ndpi_free(flow); - } +/* ****************************************************** */ + +void ndpi_free_flow(struct ndpi_flow_struct *flow) { + if(flow) { + ndpi_free_flow_data(flow); + ndpi_free(flow); } +} - /* ****************************************************** */ +/* ****************************************************** */ - char *ndpi_revision() { - return(NDPI_GIT_RELEASE); - } +char *ndpi_revision() { + return(NDPI_GIT_RELEASE); +} - /* ****************************************************** */ +/* ****************************************************** */ #ifdef WIN32 - /* https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows */ - int gettimeofday(struct timeval *tp, struct timezone *tzp) { - // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's - // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) - // until 00:00:00 January 1, 1970 - static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); +/* https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows */ +int gettimeofday(struct timeval *tp, struct timezone *tzp) { + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) + // until 00:00:00 January 1, 1970 + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); - SYSTEMTIME system_time; - FILETIME file_time; - uint64_t time; + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; - GetSystemTime(&system_time); - SystemTimeToFileTime(&system_time, &file_time); - time = ((uint64_t) file_time.dwLowDateTime); - time += ((uint64_t) file_time.dwHighDateTime) << 32; + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t) file_time.dwLowDateTime); + time += ((uint64_t) file_time.dwHighDateTime) << 32; - tp->tv_sec = (long) ((time - EPOCH) / 10000000L); - tp->tv_usec = (long) (system_time.wMilliseconds * 1000); - return(0); - } + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + return(0); +} #endif - int NDPI_BITMASK_COMPARE(NDPI_PROTOCOL_BITMASK a, NDPI_PROTOCOL_BITMASK b) { - int i; - - for(i = 0; i < NDPI_NUM_FDS_BITS; i++) { - if(a.fds_bits[i] & b.fds_bits[i]) - return(1); - } +int NDPI_BITMASK_COMPARE(NDPI_PROTOCOL_BITMASK a, NDPI_PROTOCOL_BITMASK b) { + int i; - return(0); + for(i = 0; i < NDPI_NUM_FDS_BITS; i++) { + if(a.fds_bits[i] & b.fds_bits[i]) + return(1); } + return(0); +} + #ifdef CODE_UNUSED - int NDPI_BITMASK_IS_EMPTY(NDPI_PROTOCOL_BITMASK a) { - int i; +int NDPI_BITMASK_IS_EMPTY(NDPI_PROTOCOL_BITMASK a) { + int i; - for(i = 0; i < NDPI_NUM_FDS_BITS; i++) - if(a.fds_bits[i] != 0) - return(0); + for(i = 0; i < NDPI_NUM_FDS_BITS; i++) + if(a.fds_bits[i] != 0) + return(0); - return(1); - } + return(1); +} - void NDPI_DUMP_BITMASK(NDPI_PROTOCOL_BITMASK a) { - int i; +void NDPI_DUMP_BITMASK(NDPI_PROTOCOL_BITMASK a) { + int i; - for(i = 0; i < NDPI_NUM_FDS_BITS; i++) - printf("[%d=%u]", i, a.fds_bits[i]); + for(i = 0; i < NDPI_NUM_FDS_BITS; i++) + printf("[%d=%u]", i, a.fds_bits[i]); - printf("\n"); - } + printf("\n"); +} #endif - u_int16_t ndpi_get_api_version() { - return(NDPI_API_VERSION); - } +u_int16_t ndpi_get_api_version() { + return(NDPI_API_VERSION); +} - const char *ndpi_get_gcrypt_version(void) { +const char *ndpi_get_gcrypt_version(void) { #ifdef HAVE_LIBGCRYPT - return gcry_check_version(NULL); + return gcry_check_version(NULL); #endif - return NULL; - } + return NULL; +} - ndpi_proto_defaults_t *ndpi_get_proto_defaults(struct ndpi_detection_module_struct *ndpi_str) { - return(ndpi_str->proto_defaults); - } +ndpi_proto_defaults_t *ndpi_get_proto_defaults(struct ndpi_detection_module_struct *ndpi_str) { + return(ndpi_str->proto_defaults); +} - u_int ndpi_get_ndpi_num_supported_protocols(struct ndpi_detection_module_struct *ndpi_str) { - return(ndpi_str->ndpi_num_supported_protocols); - } +u_int ndpi_get_ndpi_num_supported_protocols(struct ndpi_detection_module_struct *ndpi_str) { + return(ndpi_str->ndpi_num_supported_protocols); +} - u_int ndpi_get_ndpi_num_custom_protocols(struct ndpi_detection_module_struct *ndpi_str) { - return(ndpi_str->ndpi_num_custom_protocols); - } +u_int ndpi_get_ndpi_num_custom_protocols(struct ndpi_detection_module_struct *ndpi_str) { + return(ndpi_str->ndpi_num_custom_protocols); +} - u_int ndpi_get_ndpi_detection_module_size() { - return(sizeof(struct ndpi_detection_module_struct)); - } +u_int ndpi_get_ndpi_detection_module_size() { + return(sizeof(struct ndpi_detection_module_struct)); +} - void ndpi_set_debug_bitmask(struct ndpi_detection_module_struct *ndpi_str, NDPI_PROTOCOL_BITMASK debug_bitmask) { +void ndpi_set_debug_bitmask(struct ndpi_detection_module_struct *ndpi_str, NDPI_PROTOCOL_BITMASK debug_bitmask) { #ifdef NDPI_ENABLE_DEBUG_MESSAGES - ndpi_str->debug_bitmask = debug_bitmask; + ndpi_str->debug_bitmask = debug_bitmask; #endif - } +} - void ndpi_set_log_level(struct ndpi_detection_module_struct *ndpi_str, u_int l){ - ndpi_str->ndpi_log_level = l; - } +void ndpi_set_log_level(struct ndpi_detection_module_struct *ndpi_str, u_int l){ + ndpi_str->ndpi_log_level = l; +} - /* ******************************************************************** */ +/* ******************************************************************** */ - /* LRU cache */ - struct ndpi_lru_cache *ndpi_lru_cache_init(u_int32_t num_entries) { - struct ndpi_lru_cache *c = (struct ndpi_lru_cache *) ndpi_malloc(sizeof(struct ndpi_lru_cache)); +/* LRU cache */ +struct ndpi_lru_cache *ndpi_lru_cache_init(u_int32_t num_entries) { + struct ndpi_lru_cache *c = (struct ndpi_lru_cache *) ndpi_malloc(sizeof(struct ndpi_lru_cache)); - if(!c) - return(NULL); + if(!c) + return(NULL); - c->entries = (struct ndpi_lru_cache_entry *) ndpi_calloc(num_entries, sizeof(struct ndpi_lru_cache_entry)); + c->entries = (struct ndpi_lru_cache_entry *) ndpi_calloc(num_entries, sizeof(struct ndpi_lru_cache_entry)); - if(!c->entries) { - ndpi_free(c); - return(NULL); - } else - c->num_entries = num_entries; + if(!c->entries) { + ndpi_free(c); + return(NULL); + } else + c->num_entries = num_entries; - return(c); - } + return(c); +} - void ndpi_lru_free_cache(struct ndpi_lru_cache *c) { - ndpi_free(c->entries); - ndpi_free(c); - } +void ndpi_lru_free_cache(struct ndpi_lru_cache *c) { + ndpi_free(c->entries); + ndpi_free(c); +} - u_int8_t ndpi_lru_find_cache(struct ndpi_lru_cache *c, u_int32_t key, - u_int16_t *value, u_int8_t clean_key_when_found) { - u_int32_t slot = key % c->num_entries; +u_int8_t ndpi_lru_find_cache(struct ndpi_lru_cache *c, u_int32_t key, + u_int16_t *value, u_int8_t clean_key_when_found) { + u_int32_t slot = key % c->num_entries; - if(c->entries[slot].is_full) { - *value = c->entries[slot].value; - if(clean_key_when_found) - c->entries[slot].is_full = 0; - return(1); - } else - return(0); - } + if(c->entries[slot].is_full) { + *value = c->entries[slot].value; + if(clean_key_when_found) + c->entries[slot].is_full = 0; + return(1); + } else + return(0); +} - void ndpi_lru_add_to_cache(struct ndpi_lru_cache *c, u_int32_t key, u_int16_t value) { - u_int32_t slot = key % c->num_entries; +void ndpi_lru_add_to_cache(struct ndpi_lru_cache *c, u_int32_t key, u_int16_t value) { + u_int32_t slot = key % c->num_entries; - c->entries[slot].is_full = 1, c->entries[slot].key = key, c->entries[slot].value = value; - } + c->entries[slot].is_full = 1, c->entries[slot].key = key, c->entries[slot].value = value; +} - /* ******************************************************************** */ +/* ******************************************************************** */ - /* - This function tells if it's possible to further dissect a given flow - 0 - All possible dissection has been completed - 1 - Additional dissection is possible - */ - u_int8_t ndpi_extra_dissection_possible(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow) { - u_int16_t proto = - flow->detected_protocol_stack[1] ? flow->detected_protocol_stack[1] : flow->detected_protocol_stack[0]; +/* + This function tells if it's possible to further dissect a given flow + 0 - All possible dissection has been completed + 1 - Additional dissection is possible +*/ +u_int8_t ndpi_extra_dissection_possible(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow) { + u_int16_t proto = + flow->detected_protocol_stack[1] ? flow->detected_protocol_stack[1] : flow->detected_protocol_stack[0]; #if 0 - printf("[DEBUG] %s(%u.%u): %u\n", __FUNCTION__, - flow->detected_protocol_stack[0], - flow->detected_protocol_stack[1], - proto); + printf("[DEBUG] %s(%u.%u): %u\n", __FUNCTION__, + flow->detected_protocol_stack[0], + flow->detected_protocol_stack[1], + proto); #endif - switch(proto) { - case NDPI_PROTOCOL_TLS: - case NDPI_PROTOCOL_DTLS: - if(flow->l4.tcp.tls.certificate_processed) return(0); - - if(flow->l4.tcp.tls.num_tls_blocks <= ndpi_str->num_tls_blocks_to_follow) { - // printf("*** %u/%u\n", flow->l4.tcp.tls.num_tls_blocks, ndpi_str->num_tls_blocks_to_follow); - return(1); - } - break; + switch(proto) { + case NDPI_PROTOCOL_TLS: + case NDPI_PROTOCOL_DTLS: + if(flow->l4.tcp.tls.certificate_processed) return(0); - case NDPI_PROTOCOL_HTTP: - if((flow->host_server_name[0] == '\0') || (flow->http.response_status_code == 0)) - return(1); - break; + if(flow->l4.tcp.tls.num_tls_blocks <= ndpi_str->num_tls_blocks_to_follow) { + // printf("*** %u/%u\n", flow->l4.tcp.tls.num_tls_blocks, ndpi_str->num_tls_blocks_to_follow); + return(1); + } + break; - case NDPI_PROTOCOL_DNS: - case NDPI_PROTOCOL_MDNS: - if(flow->protos.dns.num_answers == 0) - return(1); - break; + case NDPI_PROTOCOL_HTTP: + if((flow->host_server_name[0] == '\0') || (flow->http.response_status_code == 0)) + return(1); + break; - case NDPI_PROTOCOL_FTP_CONTROL: - case NDPI_PROTOCOL_MAIL_POP: - case NDPI_PROTOCOL_MAIL_IMAP: - case NDPI_PROTOCOL_MAIL_SMTP: - if(flow->protos.ftp_imap_pop_smtp.password[0] == '\0') - return(1); - break; + case NDPI_PROTOCOL_DNS: + case NDPI_PROTOCOL_MDNS: + if(flow->protos.dns.num_answers == 0) + return(1); + break; - case NDPI_PROTOCOL_SSH: - if((flow->protos.ssh.hassh_client[0] == '\0') || (flow->protos.ssh.hassh_server[0] == '\0')) - return(1); - break; + case NDPI_PROTOCOL_FTP_CONTROL: + case NDPI_PROTOCOL_MAIL_POP: + case NDPI_PROTOCOL_MAIL_IMAP: + case NDPI_PROTOCOL_MAIL_SMTP: + if(flow->protos.ftp_imap_pop_smtp.password[0] == '\0') + return(1); + break; - case NDPI_PROTOCOL_TELNET: - if(!flow->protos.telnet.password_detected) - return(1); - break; + case NDPI_PROTOCOL_SSH: + if((flow->protos.ssh.hassh_client[0] == '\0') || (flow->protos.ssh.hassh_server[0] == '\0')) + return(1); + break; - case NDPI_PROTOCOL_SKYPE: - if(flow->extra_packets_func) - return(1); - break; + case NDPI_PROTOCOL_TELNET: + if(!flow->protos.telnet.password_detected) + return(1); + break; - case NDPI_PROTOCOL_QUIC: - if(flow->extra_packets_func) - return(1); - break; - } + case NDPI_PROTOCOL_SKYPE: + if(flow->extra_packets_func) + return(1); + break; - return(0); + case NDPI_PROTOCOL_QUIC: + if(flow->extra_packets_func) + return(1); + break; } - /* ******************************************************************** */ + return(0); +} - const char *ndpi_get_l4_proto_name(ndpi_l4_proto_info proto) { - switch(proto) { - case ndpi_l4_proto_unknown: - return(""); - break; +/* ******************************************************************** */ - case ndpi_l4_proto_tcp_only: - return("TCP"); - break; +const char *ndpi_get_l4_proto_name(ndpi_l4_proto_info proto) { + switch(proto) { + case ndpi_l4_proto_unknown: + return(""); + break; - case ndpi_l4_proto_udp_only: - return("UDP"); - break; + case ndpi_l4_proto_tcp_only: + return("TCP"); + break; - case ndpi_l4_proto_tcp_and_udp: - return("TCP/UDP"); - break; - } + case ndpi_l4_proto_udp_only: + return("UDP"); + break; - return(""); + case ndpi_l4_proto_tcp_and_udp: + return("TCP/UDP"); + break; } - /* ******************************************************************** */ + return(""); +} - ndpi_l4_proto_info ndpi_get_l4_proto_info(struct ndpi_detection_module_struct *ndpi_struct, - u_int16_t ndpi_proto_id) { - if(ndpi_proto_id < ndpi_struct->ndpi_num_supported_protocols) { - u_int16_t idx = ndpi_struct->proto_defaults[ndpi_proto_id].protoIdx; - NDPI_SELECTION_BITMASK_PROTOCOL_SIZE bm = ndpi_struct->callback_buffer[idx].ndpi_selection_bitmask; +/* ******************************************************************** */ - if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP) - return(ndpi_l4_proto_tcp_only); - else if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_UDP) - return(ndpi_l4_proto_udp_only); - else if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP) - return(ndpi_l4_proto_tcp_and_udp); - } +ndpi_l4_proto_info ndpi_get_l4_proto_info(struct ndpi_detection_module_struct *ndpi_struct, + u_int16_t ndpi_proto_id) { + if(ndpi_proto_id < ndpi_struct->ndpi_num_supported_protocols) { + u_int16_t idx = ndpi_struct->proto_defaults[ndpi_proto_id].protoIdx; + NDPI_SELECTION_BITMASK_PROTOCOL_SIZE bm = ndpi_struct->callback_buffer[idx].ndpi_selection_bitmask; - return(ndpi_l4_proto_unknown); /* default */ + if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP) + return(ndpi_l4_proto_tcp_only); + else if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_UDP) + return(ndpi_l4_proto_udp_only); + else if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP) + return(ndpi_l4_proto_tcp_and_udp); } - /* ******************************************************************** */ + return(ndpi_l4_proto_unknown); /* default */ +} + +/* ******************************************************************** */ - ndpi_ptree_t *ndpi_ptree_create(void) { - ndpi_ptree_t *tree = (ndpi_ptree_t *) ndpi_malloc(sizeof(ndpi_ptree_t)); +ndpi_ptree_t *ndpi_ptree_create(void) { + ndpi_ptree_t *tree = (ndpi_ptree_t *) ndpi_malloc(sizeof(ndpi_ptree_t)); - if(tree) { - tree->v4 = ndpi_patricia_new(32); - tree->v6 = ndpi_patricia_new(128); + if(tree) { + tree->v4 = ndpi_patricia_new(32); + tree->v6 = ndpi_patricia_new(128); - if((!tree->v4) || (!tree->v6)) { - ndpi_ptree_destroy(tree); - return(NULL); - } + if((!tree->v4) || (!tree->v6)) { + ndpi_ptree_destroy(tree); + return(NULL); } - - return(tree); } - /* ******************************************************************** */ + return(tree); +} - void ndpi_ptree_destroy(ndpi_ptree_t *tree) { - if(tree) { - if(tree->v4) - ndpi_patricia_destroy(tree->v4, free_ptree_data); - if(tree->v6) - ndpi_patricia_destroy(tree->v6, free_ptree_data); +/* ******************************************************************** */ - ndpi_free(tree); - } - } +void ndpi_ptree_destroy(ndpi_ptree_t *tree) { + if(tree) { + if(tree->v4) + ndpi_patricia_destroy(tree->v4, free_ptree_data); + if(tree->v6) + ndpi_patricia_destroy(tree->v6, free_ptree_data); - /* ******************************************************************** */ + ndpi_free(tree); + } +} - int ndpi_ptree_insert(ndpi_ptree_t *tree, const ndpi_ip_addr_t *addr, - u_int8_t bits, u_int64_t user_data) { - u_int8_t is_v6 = ndpi_is_ipv6(addr); - ndpi_patricia_tree_t *ptree = is_v6 ? tree->v6 : tree->v4; - ndpi_prefix_t prefix; - ndpi_patricia_node_t *node; +/* ******************************************************************** */ - if(bits > ptree->maxbits) - return(-1); +int ndpi_ptree_insert(ndpi_ptree_t *tree, const ndpi_ip_addr_t *addr, + u_int8_t bits, u_int64_t user_data) { + u_int8_t is_v6 = ndpi_is_ipv6(addr); + ndpi_patricia_tree_t *ptree = is_v6 ? tree->v6 : tree->v4; + ndpi_prefix_t prefix; + ndpi_patricia_node_t *node; - if(is_v6) - ndpi_fill_prefix_v6(&prefix, (const struct in6_addr *) &addr->ipv6, bits, ptree->maxbits); - else - ndpi_fill_prefix_v4(&prefix, (const struct in_addr *) &addr->ipv4, bits, ptree->maxbits); + if(bits > ptree->maxbits) + return(-1); - /* Verify that the node does not already exist */ - node = ndpi_patricia_search_best(ptree, &prefix); + if(is_v6) + ndpi_fill_prefix_v6(&prefix, (const struct in6_addr *) &addr->ipv6, bits, ptree->maxbits); + else + ndpi_fill_prefix_v4(&prefix, (const struct in_addr *) &addr->ipv4, bits, ptree->maxbits); - if(node && (node->prefix->bitlen == bits)) - return(-2); + /* Verify that the node does not already exist */ + node = ndpi_patricia_search_best(ptree, &prefix); - node = ndpi_patricia_lookup(ptree, &prefix); + if(node && (node->prefix->bitlen == bits)) + return(-2); - if(node != NULL) { - node->value.u.uv64 = user_data; + node = ndpi_patricia_lookup(ptree, &prefix); - return(0); - } + if(node != NULL) { + node->value.u.uv64 = user_data; - return(-3); + return(0); } - /* ******************************************************************** */ + return(-3); +} - int ndpi_ptree_match_addr(ndpi_ptree_t *tree, - const ndpi_ip_addr_t *addr, u_int64_t *user_data) { - u_int8_t is_v6 = ndpi_is_ipv6(addr); - ndpi_patricia_tree_t *ptree = is_v6 ? tree->v6 : tree->v4; - ndpi_prefix_t prefix; - ndpi_patricia_node_t *node; - int bits = ptree->maxbits; +/* ******************************************************************** */ - if(is_v6) - ndpi_fill_prefix_v6(&prefix, (const struct in6_addr *) &addr->ipv6, bits, ptree->maxbits); - else - ndpi_fill_prefix_v4(&prefix, (const struct in_addr *) &addr->ipv4, bits, ptree->maxbits); +int ndpi_ptree_match_addr(ndpi_ptree_t *tree, + const ndpi_ip_addr_t *addr, u_int64_t *user_data) { + u_int8_t is_v6 = ndpi_is_ipv6(addr); + ndpi_patricia_tree_t *ptree = is_v6 ? tree->v6 : tree->v4; + ndpi_prefix_t prefix; + ndpi_patricia_node_t *node; + int bits = ptree->maxbits; - node = ndpi_patricia_search_best(ptree, &prefix); + if(is_v6) + ndpi_fill_prefix_v6(&prefix, (const struct in6_addr *) &addr->ipv6, bits, ptree->maxbits); + else + ndpi_fill_prefix_v4(&prefix, (const struct in_addr *) &addr->ipv4, bits, ptree->maxbits); - if(node) { - *user_data = node->value.u.uv64; + node = ndpi_patricia_search_best(ptree, &prefix); - return(0); - } + if(node) { + *user_data = node->value.u.uv64; - return(-1); + return(0); } - /* ******************************************************************** */ + return(-1); +} + +/* ******************************************************************** */ - /* Based on djb2 hash - http://www.cse.yorku.ca/~oz/hash.html */ - u_int32_t ndpi_quick_hash(unsigned char *str, u_int str_len) { - u_int32_t hash = 5381, i; +/* Based on djb2 hash - http://www.cse.yorku.ca/~oz/hash.html */ +u_int32_t ndpi_quick_hash(unsigned char *str, u_int str_len) { + u_int32_t hash = 5381, i; - for(i=0; i<str_len; i++) - hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + str[i] */ + for(i=0; i<str_len; i++) + hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + str[i] */ - return hash; - } + return hash; +} - /* ******************************************************************** */ +/* ******************************************************************** */ - void ndpi_md5(const u_char *data, size_t data_len, u_char hash[16]) { - ndpi_MD5_CTX ctx; +void ndpi_md5(const u_char *data, size_t data_len, u_char hash[16]) { + ndpi_MD5_CTX ctx; - ndpi_MD5Init(&ctx); - ndpi_MD5Update(&ctx, data, data_len); - ndpi_MD5Final(hash, &ctx); - } + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, data, data_len); + ndpi_MD5Final(hash, &ctx); +} - /* ******************************************************************** */ +/* ******************************************************************** */ - static int enough(int a, int b) { - u_int8_t percentage = 20; +static int enough(int a, int b) { + u_int8_t percentage = 20; - if(b <= 1) return(0); - if(a == 0) return(1); + if(b <= 1) return(0); + if(a == 0) return(1); - if(b > (((a+1)*percentage)/100)) return(1); + if(b > (((a+1)*percentage)/100)) return(1); - return(0); - } + return(0); +} - /* ******************************************************************** */ +/* ******************************************************************** */ - static u_int8_t endsWith(char *str, char *ends, u_int8_t ends_len) { - u_int str_len = str ? strlen(str) : 0; - u_int8_t rc; +static u_int8_t endsWith(char *str, char *ends, u_int8_t ends_len) { + u_int str_len = str ? strlen(str) : 0; + u_int8_t rc; - if(str_len < ends_len) return(0); + if(str_len < ends_len) return(0); - rc = (strncmp(&str[str_len-ends_len], ends, ends_len) != 0) ? 0 : 1; + rc = (strncmp(&str[str_len-ends_len], ends, ends_len) != 0) ? 0 : 1; #ifdef DGA_DEBUG - printf("[DGA] %s / %s [rc: %u]\n", str, ends, rc); + printf("[DGA] %s / %s [rc: %u]\n", str, ends, rc); #endif - return(rc); - } + return(rc); +} - /* ******************************************************************** */ +/* ******************************************************************** */ - static int ndpi_is_trigram_char(char c) { - if(isdigit(c) || (c == '.') || (c == '-')) - return(0); - else - return(1); - } +static int ndpi_is_trigram_char(char c) { + if(isdigit(c) || (c == '.') || (c == '-')) + return(0); + else + return(1); +} - /* ******************************************************************** */ +/* ******************************************************************** */ - static int ndpi_is_vowel(char c) { - switch(c) { - case 'a': - case 'e': - case 'i': - case 'o': - case 'u': - case 'y': // Not a real vowel... - case 'x': // Not a real vowel... - return(1); - break; +static int ndpi_is_vowel(char c) { + switch(c) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + case 'y': // Not a real vowel... + case 'x': // Not a real vowel... + return(1); + break; - default: - return(0); - } + default: + return(0); } +} - /* ******************************************************************** */ +/* ******************************************************************** */ - int ndpi_check_dga_name(struct ndpi_detection_module_struct *ndpi_str, - struct ndpi_flow_struct *flow, - char *name, u_int8_t is_hostname) { - if(ndpi_dga_function != NULL) { - /* A custom DGA function is defined */ - int rc = ndpi_dga_function(name, is_hostname); +int ndpi_check_dga_name(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + char *name, u_int8_t is_hostname) { + if(ndpi_dga_function != NULL) { + /* A custom DGA function is defined */ + int rc = ndpi_dga_function(name, is_hostname); - if(rc) { - if(flow) - ndpi_set_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN); - } + if(rc) { + if(flow) + ndpi_set_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN); + } - return(rc); - } else { - int len, rc = 0, trigram_char_skip = 0; - u_int8_t max_num_char_repetitions = 0, last_char = 0, num_char_repetitions = 0, num_dots = 0, num_trigram_dots = 0; - u_int8_t max_domain_element_len = 0, curr_domain_element_len = 0, first_element_is_numeric = 1; - - if((!name) - || (strchr(name, '_') != NULL) - || (endsWith(name, "in-addr.arpa", 12)) - || (endsWith(name, "ip6.arpa", 8)) - /* Ignore TLD .local .lan and .home */ - || (endsWith(name, ".local", 6)) - || (endsWith(name, ".lan", 4)) - || (endsWith(name, ".home", 5)) - ) - return(0); + return(rc); + } else { + int len, rc = 0, trigram_char_skip = 0; + u_int8_t max_num_char_repetitions = 0, last_char = 0, num_char_repetitions = 0, num_dots = 0, num_trigram_dots = 0; + u_int8_t max_domain_element_len = 0, curr_domain_element_len = 0, first_element_is_numeric = 1; + + if((!name) + || (strchr(name, '_') != NULL) + || (endsWith(name, "in-addr.arpa", 12)) + || (endsWith(name, "ip6.arpa", 8)) + /* Ignore TLD .local .lan and .home */ + || (endsWith(name, ".local", 6)) + || (endsWith(name, ".lan", 4)) + || (endsWith(name, ".home", 5)) + ) + return(0); - if(flow && (flow->packet.detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN)) - return(0); /* Ignore DGA check for protocols already fully detected */ + if(flow && (flow->packet.detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN)) + return(0); /* Ignore DGA check for protocols already fully detected */ - if(strncmp(name, "www.", 4) == 0) - name = &name[4]; + if(strncmp(name, "www.", 4) == 0) + name = &name[4]; - if(ndpi_verbose_dga_detection) - printf("[DGA check] %s\n", name); + if(ndpi_verbose_dga_detection) + printf("[DGA check] %s\n", name); - len = strlen(name); + len = strlen(name); - if(len >= 5) { - int i, j, num_found = 0, num_impossible = 0, num_bigram_checks = 0, - num_trigram_found = 0, num_trigram_checked = 0, num_dash = 0, - num_digits = 0, num_vowels = 0, num_trigram_vowels = 0, num_words = 0, skip_next_bigram = 0; - char tmp[128], *word, *tok_tmp; - u_int max_tmp_len = sizeof(tmp)-1; + if(len >= 5) { + int i, j, num_found = 0, num_impossible = 0, num_bigram_checks = 0, + num_trigram_found = 0, num_trigram_checked = 0, num_dash = 0, + num_digits = 0, num_vowels = 0, num_trigram_vowels = 0, num_words = 0, skip_next_bigram = 0; + char tmp[128], *word, *tok_tmp; + u_int max_tmp_len = sizeof(tmp)-1; - len = snprintf(tmp, max_tmp_len, "%s", name); - if(len < 0) { + len = snprintf(tmp, max_tmp_len, "%s", name); + if(len < 0) { - if(ndpi_verbose_dga_detection) - printf("[DGA] Too short"); + if(ndpi_verbose_dga_detection) + printf("[DGA] Too short"); - return(0); - } else - tmp[len < max_tmp_len ? len : max_tmp_len] = '\0'; + return(0); + } else + tmp[len < max_tmp_len ? len : max_tmp_len] = '\0'; - for(i=0, j=0; (i<len) && (j<max_tmp_len); i++) { - tmp[j] = tolower(name[i]); + for(i=0, j=0; (i<len) && (j<max_tmp_len); i++) { + tmp[j] = tolower(name[i]); - if(tmp[j] == '.') { - num_dots++; - } else if(num_dots == 0) { - if(!isdigit(tmp[j])) - first_element_is_numeric = 0; - } + if(tmp[j] == '.') { + num_dots++; + } else if(num_dots == 0) { + if(!isdigit(tmp[j])) + first_element_is_numeric = 0; + } - if(ndpi_is_vowel(tmp[j])) - num_vowels++; + if(ndpi_is_vowel(tmp[j])) + num_vowels++; - if(last_char == tmp[j]) { - if(++num_char_repetitions > max_num_char_repetitions) - max_num_char_repetitions = num_char_repetitions; - } else - num_char_repetitions = 1, last_char = tmp[j]; + if(last_char == tmp[j]) { + if(++num_char_repetitions > max_num_char_repetitions) + max_num_char_repetitions = num_char_repetitions; + } else + num_char_repetitions = 1, last_char = tmp[j]; - if(isdigit(tmp[j])) { - num_digits++; + if(isdigit(tmp[j])) { + num_digits++; - if(((j+2)<len) && isdigit(tmp[j+1]) && (tmp[j+2] == '.')) { - /* Check if there are too many digits */ - if(num_digits < 4) - return(0); /* Double digits */ - } + if(((j+2)<len) && isdigit(tmp[j+1]) && (tmp[j+2] == '.')) { + /* Check if there are too many digits */ + if(num_digits < 4) + return(0); /* Double digits */ } + } - switch(tmp[j]) { - case '.': - case '-': - case '_': - case '/': - case ')': - case '(': - case ';': - case ':': - case '[': - case ']': - case ' ': - /* - Domain/word separator chars - - NOTE: - this function is used also to detect other type of issues - such as invalid/suspiciuous user agent - */ - if(curr_domain_element_len > max_domain_element_len) - max_domain_element_len = curr_domain_element_len; + switch(tmp[j]) { + case '.': + case '-': + case '_': + case '/': + case ')': + case '(': + case ';': + case ':': + case '[': + case ']': + case ' ': + /* + Domain/word separator chars - curr_domain_element_len = 0; - break; + NOTE: + this function is used also to detect other type of issues + such as invalid/suspiciuous user agent + */ + if(curr_domain_element_len > max_domain_element_len) + max_domain_element_len = curr_domain_element_len; - default: - curr_domain_element_len++; - break; - } + curr_domain_element_len = 0; + break; - j++; + default: + curr_domain_element_len++; + break; } - if(num_dots == 0) /* Doesn't look like a domain name */ - return(0); + j++; + } - if(curr_domain_element_len > max_domain_element_len) - max_domain_element_len = curr_domain_element_len; + if(num_dots == 0) /* Doesn't look like a domain name */ + return(0); - if(ndpi_verbose_dga_detection) - printf("[DGA] [max_num_char_repetitions: %u][max_domain_element_len: %u]\n", - max_num_char_repetitions, max_domain_element_len); - - if( - (is_hostname - && (num_dots > 5) - && (!first_element_is_numeric) - ) - || (max_num_char_repetitions > 5 /* num or consecutive repeated chars */) - /* - In case of a name with too many consecutive chars an alert is triggered - This is the case for instance of the wildcard DNS query used by NetBIOS - (ckaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) and that can be exploited - for reflection attacks - - https://www.akamai.com/uk/en/multimedia/documents/state-of-the-internet/ddos-reflection-netbios-name-server-rpc-portmap-sentinel-udp-threat-advisory.pdf - - http://ubiqx.org/cifs/NetBIOS.html - */ - || ((max_domain_element_len >= 19 /* word too long. Example bbcbedxhgjmdobdprmen.com */) && ((num_char_repetitions > 1) || (num_digits > 1))) - ) { - if(flow) ndpi_set_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN); + if(curr_domain_element_len > max_domain_element_len) + max_domain_element_len = curr_domain_element_len; - if(ndpi_verbose_dga_detection) - printf("[DGA] Found!"); + if(ndpi_verbose_dga_detection) + printf("[DGA] [max_num_char_repetitions: %u][max_domain_element_len: %u]\n", + max_num_char_repetitions, max_domain_element_len); + + if( + (is_hostname + && (num_dots > 5) + && (!first_element_is_numeric) + ) + || (max_num_char_repetitions > 5 /* num or consecutive repeated chars */) + /* + In case of a name with too many consecutive chars an alert is triggered + This is the case for instance of the wildcard DNS query used by NetBIOS + (ckaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) and that can be exploited + for reflection attacks + - https://www.akamai.com/uk/en/multimedia/documents/state-of-the-internet/ddos-reflection-netbios-name-server-rpc-portmap-sentinel-udp-threat-advisory.pdf + - http://ubiqx.org/cifs/NetBIOS.html + */ + || ((max_domain_element_len >= 19 /* word too long. Example bbcbedxhgjmdobdprmen.com */) && ((num_char_repetitions > 1) || (num_digits > 1))) + ) { + if(flow) ndpi_set_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN); - return(1); - } + if(ndpi_verbose_dga_detection) + printf("[DGA] Found!"); + + return(1); + } - tmp[j] = '\0'; - len = j; + tmp[j] = '\0'; + len = j; - for(word = strtok_r(tmp, ".", &tok_tmp); ; word = strtok_r(NULL, ".", &tok_tmp)) { - if(!word) break; + for(word = strtok_r(tmp, ".", &tok_tmp); ; word = strtok_r(NULL, ".", &tok_tmp)) { + if(!word) break; - num_words++; + num_words++; - if(strlen(word) < 3) continue; + if(strlen(word) < 3) continue; - if(ndpi_verbose_dga_detection) - printf("-> word(%s) [%s][len: %u]\n", word, name, (unsigned int)strlen(word)); + if(ndpi_verbose_dga_detection) + printf("-> word(%s) [%s][len: %u]\n", word, name, (unsigned int)strlen(word)); - trigram_char_skip = 0; + trigram_char_skip = 0; - for(i = 0; word[i+1] != '\0'; i++) { - switch(word[i]) { - case '-': - num_dash++; - /* - Let's check for double+consecutive -- - that are usually ok - r2---sn-uxaxpu5ap5-2n5e.gvt1.com - */ - if(word[i+1] == '-') - return(0); /* Double dash */ - - case '_': - case ':': - continue; - break; - - case '.': - continue; - break; - } - num_bigram_checks++; + for(i = 0; word[i+1] != '\0'; i++) { + switch(word[i]) { + case '-': + num_dash++; + /* + Let's check for double+consecutive -- + that are usually ok + r2---sn-uxaxpu5ap5-2n5e.gvt1.com + */ + if(word[i+1] == '-') + return(0); /* Double dash */ - if(ndpi_verbose_dga_detection) - printf("-> Checking %c%c\n", word[i], word[i+1]); + case '_': + case ':': + continue; + break; + + case '.': + continue; + break; + } + num_bigram_checks++; - if(ndpi_match_bigram(ndpi_str, - &ndpi_str->impossible_bigrams_automa, - &word[i])) { - if(ndpi_verbose_dga_detection) - printf("IMPOSSIBLE %s\n", &word[i]); + if(ndpi_verbose_dga_detection) + printf("-> Checking %c%c\n", word[i], word[i+1]); - num_impossible++; - } else { - if(!skip_next_bigram) { - if(ndpi_match_bigram(ndpi_str, &ndpi_str->bigrams_automa, &word[i])) { - num_found++, skip_next_bigram = 1; - } - } else - skip_next_bigram = 0; - } + if(ndpi_match_bigram(ndpi_str, + &ndpi_str->impossible_bigrams_automa, + &word[i])) { + if(ndpi_verbose_dga_detection) + printf("IMPOSSIBLE %s\n", &word[i]); + + num_impossible++; + } else { + if(!skip_next_bigram) { + if(ndpi_match_bigram(ndpi_str, &ndpi_str->bigrams_automa, &word[i])) { + num_found++, skip_next_bigram = 1; + } + } else + skip_next_bigram = 0; + } - if((num_trigram_dots < 2) && (word[i+2] != '\0')) { - if(ndpi_verbose_dga_detection) - printf("***> %s [trigram_char_skip: %u]\n", &word[i], trigram_char_skip); + if((num_trigram_dots < 2) && (word[i+2] != '\0')) { + if(ndpi_verbose_dga_detection) + printf("***> %s [trigram_char_skip: %u]\n", &word[i], trigram_char_skip); - if(ndpi_is_trigram_char(word[i]) && ndpi_is_trigram_char(word[i+1]) && ndpi_is_trigram_char(word[i+2])) { - if(trigram_char_skip) { - trigram_char_skip--; - } else { - num_trigram_checked++; + if(ndpi_is_trigram_char(word[i]) && ndpi_is_trigram_char(word[i+1]) && ndpi_is_trigram_char(word[i+2])) { + if(trigram_char_skip) { + trigram_char_skip--; + } else { + num_trigram_checked++; - if(ndpi_match_trigram(ndpi_str, &ndpi_str->trigrams_automa, &word[i])) - num_trigram_found++, trigram_char_skip = 2 /* 1 char overlap */; - else if(ndpi_verbose_dga_detection) - printf("[NDPI] NO Trigram %c%c%c\n", word[i], word[i+1], word[i+2]); + if(ndpi_match_trigram(ndpi_str, &ndpi_str->trigrams_automa, &word[i])) + num_trigram_found++, trigram_char_skip = 2 /* 1 char overlap */; + else if(ndpi_verbose_dga_detection) + printf("[NDPI] NO Trigram %c%c%c\n", word[i], word[i+1], word[i+2]); - /* Count vowels */ - num_trigram_vowels += ndpi_is_vowel(word[i]) + ndpi_is_vowel(word[i+1]) + ndpi_is_vowel(word[i+2]); - } - } else { - if(word[i] == '.') - num_trigram_dots++; - - trigram_char_skip = 0; + /* Count vowels */ + num_trigram_vowels += ndpi_is_vowel(word[i]) + ndpi_is_vowel(word[i+1]) + ndpi_is_vowel(word[i+2]); } + } else { + if(word[i] == '.') + num_trigram_dots++; + + trigram_char_skip = 0; } - } /* for */ + } } /* for */ + } /* for */ - if(ndpi_verbose_dga_detection) - printf("[%s][num_found: %u][num_impossible: %u][num_digits: %u][num_bigram_checks: %u][num_vowels: %u/%u][num_trigram_vowels: %u][num_trigram_found: %u/%u][vowels: %u][rc: %u]\n", - name, num_found, num_impossible, num_digits, num_bigram_checks, num_vowels, len, num_trigram_vowels, - num_trigram_checked, num_trigram_found, num_vowels, rc); - - if((len > 16) && (num_dots < 3) && ((num_vowels*4) < (len-num_dots))) { - if((num_trigram_checked > 2) && (num_trigram_vowels >= (num_trigram_found-1))) - ; /* skip me */ - else - rc = 1; - } - - if(num_bigram_checks - && (num_dots > 0) - && ((num_found == 0) || ((num_digits > 5) && (num_words <= 3)) - || enough(num_found, num_impossible) - || ((num_trigram_checked > 2) - && ((num_trigram_found < (num_trigram_checked/2)) - || ((num_trigram_vowels < (num_trigram_found-1)) && (num_dash == 0) && (num_dots > 1))) - ) - ) - ) + if(ndpi_verbose_dga_detection) + printf("[%s][num_found: %u][num_impossible: %u][num_digits: %u][num_bigram_checks: %u][num_vowels: %u/%u][num_trigram_vowels: %u][num_trigram_found: %u/%u][vowels: %u][rc: %u]\n", + name, num_found, num_impossible, num_digits, num_bigram_checks, num_vowels, len, num_trigram_vowels, + num_trigram_checked, num_trigram_found, num_vowels, rc); + + if((len > 16) && (num_dots < 3) && ((num_vowels*4) < (len-num_dots))) { + if((num_trigram_checked > 2) && (num_trigram_vowels >= (num_trigram_found-1))) + ; /* skip me */ + else rc = 1; + } + + if(num_bigram_checks + && (num_dots > 0) + && ((num_found == 0) || ((num_digits > 5) && (num_words <= 3)) + || enough(num_found, num_impossible) + || ((num_trigram_checked > 2) + && ((num_trigram_found < (num_trigram_checked/2)) + || ((num_trigram_vowels < (num_trigram_found-1)) && (num_dash == 0) && (num_dots > 1))) + ) + ) + ) + rc = 1; - if((num_trigram_checked > 2) && (num_vowels == 0)) - rc = 1; + if((num_trigram_checked > 2) && (num_vowels == 0)) + rc = 1; - if(num_dash > 2) - rc = 0; + if(num_dash > 2) + rc = 0; - if(ndpi_verbose_dga_detection) { - if(rc) - printf("DGA %s [num_found: %u][num_impossible: %u]\n", - name, num_found, num_impossible); - } + if(ndpi_verbose_dga_detection) { + if(rc) + printf("DGA %s [num_found: %u][num_impossible: %u]\n", + name, num_found, num_impossible); } + } - if(ndpi_verbose_dga_detection) - printf("[DGA] Result: %u\n", rc); + if(ndpi_verbose_dga_detection) + printf("[DGA] Result: %u\n", rc); - if(rc && flow) - ndpi_set_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN); + if(rc && flow) + ndpi_set_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN); - return(rc); - } + return(rc); } +} - /* ******************************************************************** */ +/* ******************************************************************** */ diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index 12140cdc9..0f784bb7e 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -1714,7 +1714,7 @@ const char* ndpi_risk2str(ndpi_risk_enum risk) { return("Possibly Malicious JA3 Fingerprint"); case NDPI_MALICIOUS_SHA1_CERTIFICATE: - return("Possibly Malicious SSL Certificate SHA1 Fingerprint"); + return("Possibly Malicious SSL Cert. SHA1 Fingerprint"); case NDPI_DESKTOP_OR_FILE_SHARING_SESSION: return("Desktop/File Sharing Session"); @@ -1781,6 +1781,28 @@ ndpi_risk_severity ndpi_risk2severity(ndpi_risk_enum risk) { /* ******************************************************************** */ +const char* ndpi_severity2str(ndpi_risk_severity s) { + switch(s) { + case NDPI_RISK_LOW: + return("Low"); + break; + + case NDPI_RISK_MEDIUM: + return("Medium"); + break; + + case NDPI_RISK_HIGH: + return("High"); + break; + + case NDPI_RISK_SEVERE: + return("Severe"); + break; + } +} + +/* ******************************************************************** */ + u_int16_t ndpi_risk2score(ndpi_risk risk) { u_int16_t score = 0; u_int32_t i; diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 0b900be64..6f30400f7 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -43,6 +43,8 @@ extern int is_version_with_var_int_transport_params(uint32_t version); // #define DEBUG_TLS_BLOCKS 1 // #define DEBUG_CERTIFICATE_HASH +// #define DEBUG_HEURISTIC + // #define DEBUG_JA3C 1 /* #define DEBUG_FINGERPRINT 1 */ @@ -1513,6 +1515,12 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_chrome_tls = 1; else if(safari_ciphers == 12) flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_safari_tls = 1; + +#ifdef DEBUG_HEURISTIC + printf("[is_chrome_tls: %u][is_safari_tls: %u]\n", + flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_chrome_tls, + flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_safari_tls); +#endif } else { invalid_ja3 = 1; #ifdef DEBUG_TLS @@ -1725,11 +1733,12 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, } for(i=0; i<tot_signature_algorithms_len; i+=2) { - u_int16_t cipher_id = (u_int16_t)ntohs(*((u_int16_t*)&packet->payload[s_offset+i])); - - // printf("=>> %04X\n", cipher_id); + u_int16_t signature_algo = (u_int16_t)ntohs(*((u_int16_t*)&packet->payload[s_offset+i])); - switch(cipher_id) { +#ifdef DEBUG_HEURISTIC + printf("[TLS Signature Algorithm] 0x%04X\n", signature_algo); +#endif + switch(signature_algo) { case ECDSA_SECP521R1_SHA512: flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_firefox_tls = 1; break; @@ -1757,6 +1766,13 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if(chrome_signature_algorithms != 8) flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_chrome_tls = 0; +#ifdef DEBUG_HEURISTIC + printf("[is_firefox_tls: %u][is_chrome_tls: %u][is_safari_tls: %u]\n", + flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_firefox_tls, + flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_chrome_tls, + flow->protos.tls_quic_stun.tls_quic.browser_euristics.is_safari_tls); +#endif + ja3.client.signature_algorithms[i*2] = '\0'; #ifdef DEBUG_TLS |