diff options
author | Campus <campus@ntop.org> | 2017-07-27 13:12:12 +0200 |
---|---|---|
committer | Campus <campus@ntop.org> | 2017-07-27 13:12:12 +0200 |
commit | abf5bea425d5f8ce18c26e18046a0ef42d15a0a7 (patch) | |
tree | 82fc1b058d6b39f722507d23cdd6ba85e5d97ec2 /src | |
parent | e6b594a626e5cfb5cd0410336f8c1e12966a27cd (diff) | |
parent | 6ca6d968214d8c23ee9a31b0b5497a3ea24795e8 (diff) |
Merge branch 'MicahLyle-ssl-certificate-fix' into dev
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_api.h | 121 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 6 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 54 | ||||
-rw-r--r-- | src/lib/protocols/ssl.c | 92 |
4 files changed, 194 insertions, 79 deletions
diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h index b2c6b6952..03a73d66b 100644 --- a/src/include/ndpi_api.h +++ b/src/include/ndpi_api.h @@ -42,20 +42,20 @@ extern "C" { #define SAVE_DETECTION_BITMASK_AS_UNKNOWN 1 #define NO_SAVE_DETECTION_BITMASK_AS_UNKNOWN 0 - + /** * Check if a string is encoded with punycode * ( https://tools.ietf.org/html/rfc3492 ) * * @par buff = pointer to the string to ckeck * @par len = len of the string - * @return 1 if the string is punycoded; + * @return 1 if the string is punycoded; * else 0 * */ int check_punycode_string(char * buff , int len); - + /** * Get the size of the flow struct * @@ -64,16 +64,16 @@ extern "C" { */ u_int32_t ndpi_detection_get_sizeof_ndpi_flow_struct(void); - + /** - * Get the size of the id struct + * Get the size of the id struct * * @return the size of the id struct - * + * */ u_int32_t ndpi_detection_get_sizeof_ndpi_id_struct(void); - + /** * nDPI personal allocation and free functions **/ @@ -98,7 +98,7 @@ extern "C" { */ char* ndpi_strnstr(const char *s, const char *find, size_t slen); - + /** * Returns the nDPI protocol id for IP-based protocol detection * @@ -106,7 +106,7 @@ extern "C" { * @par pin = IP host address (MUST BE in network byte order): * See man(7) ip for details * @return the nDPI protocol ID - * + * */ u_int16_t ndpi_network_ptree_match(struct ndpi_detection_module_struct *ndpi_struct, struct in_addr *pin); @@ -117,9 +117,9 @@ extern "C" { * @par ndpi_mod = the struct created for the protocol detection * @par match = the struct passed to match the protocol * - */ + */ void ndpi_init_protocol_match(struct ndpi_detection_module_struct *ndpi_mod, ndpi_protocol_match *match); - + /** * Returns a new initialized detection module * @@ -127,7 +127,7 @@ extern "C" { * */ struct ndpi_detection_module_struct *ndpi_init_detection_module(void); - + /** * Frees the memory allocated in the specified flow * @@ -136,7 +136,7 @@ extern "C" { */ void ndpi_free_flow(struct ndpi_flow_struct *flow); - + /** * Enables cache support. * In nDPI is used for some protocol (i.e. Skype) @@ -148,7 +148,7 @@ extern "C" { */ void ndpi_enable_cache(struct ndpi_detection_module_struct *ndpi_mod, char* host, u_int port); - + /** * Destroys the detection module * @@ -180,7 +180,7 @@ extern "C" { const NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_bitmask, u_int8_t b_save_bitmask_unknow, u_int8_t b_add_detection_bitmask); - + /** * Sets the protocol bitmask2 @@ -192,7 +192,7 @@ extern "C" { void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *ndpi_struct, const NDPI_PROTOCOL_BITMASK * detection_bitmask); - + /** * Function to be called before we give up with detection for a given flow. * This function reduces the NDPI_UNKNOWN_PROTOCOL detection @@ -200,12 +200,35 @@ extern "C" { * @par ndpi_struct = the detection module * @par flow = the flow given for the detection module * @return the detected protocol even if the flow is not completed; - * + * */ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); - + /** + * Processes an extra packet in order to get more information for a given protocol + * (like SSL getting both client and server certificate even if we already know after + * seeing the client certificate what the protocol is) + * + * @par ndpi_struct = the detection module + * @par flow = pointer to the connection state machine + * @par packet = unsigned char pointer to the Layer 3 (IP header) + * @par packetlen = the length of the packet + * @par current_tick = the current timestamp for the packet + * @par src = pointer to the source subscriber state machine + * @par dst = pointer to the destination subscriber state machine + * @return void + * + */ + void ndpi_process_extra_packet(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + const unsigned char *packet, + const unsigned short packetlen, + const u_int64_t current_tick, + struct ndpi_id_struct *src, + struct ndpi_id_struct *dst); + + /** * Processes one packet and returns the ID of the detected protocol. * This is the MAIN PACKET PROCESSING FUNCTION. @@ -228,7 +251,7 @@ extern "C" { struct ndpi_id_struct *src, struct ndpi_id_struct *dst); - + /** * Get the main protocol of the passed flows for the detected module * @@ -241,13 +264,13 @@ extern "C" { u_int16_t ndpi_get_flow_masterprotocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); - + /** * Query the pointer to the layer 4 packet * * @par l3 = pointer to the layer 3 data * @par l3_len = length of the layer 3 data - * @par l4_return = address to the pointer of the layer 4 data if return value == 0, else undefined + * @par l4_return = address to the pointer of the layer 4 data if return value == 0, else undefined * @par l4_len_return = length of the layer 4 data if return value == 0, else undefined * @par l4_protocol_return = protocol of the layer 4 data if return value == 0, undefined otherwise * @par flags = limit operation on ipv4 or ipv6 packets. Possible values: NDPI_DETECTION_ONLY_IPV4 - NDPI_DETECTION_ONLY_IPV6 - 0 (any) @@ -261,13 +284,13 @@ extern "C" { /** * Search and return the protocol based on matched ports - * + * * @par ndpi_struct = the detection module * @par shost = source address in host byte order * @par sport = source port number * @par dhost = destination address in host byte order * @par dport = destination port number - * @return the struct ndpi_protocol that match the port base protocol + * @return the struct ndpi_protocol that match the port base protocol * */ ndpi_protocol ndpi_find_port_based_protocol(struct ndpi_detection_module_struct *ndpi_struct/* , u_int8_t proto */, @@ -276,17 +299,17 @@ extern "C" { u_int32_t dhost, u_int16_t dport); - + /** * Search and return the protocol guessed that is undetected - * + * * @par ndpi_struct = the detection module * @par proto = the l4 protocol number * @par shost = source address in host byte order * @par sport = source port number * @par dhost = destination address in host byte order * @par dport = destination port number - * @return the struct ndpi_protocol that match the port base protocol + * @return the struct ndpi_protocol that match the port base protocol * */ ndpi_protocol ndpi_guess_undetected_protocol(struct ndpi_detection_module_struct *ndpi_struct, @@ -299,7 +322,7 @@ extern "C" { /** * Check if the string passed match with a protocol - * + * * @par ndpi_struct = the detection module * @par string_to_match = the string to match * @par string_to_match_len = the length of the string @@ -315,7 +338,7 @@ extern "C" { /** * Check if the host passed match with a protocol - * + * * @par ndpi_struct = the detection module * @par flow = the flow where match the host * @par string_to_match = the string to match @@ -333,7 +356,7 @@ extern "C" { /** * Check if the string content passed match with a protocol - * + * * @par ndpi_struct = the detection module * @par flow = the flow where match the host * @par string_to_match = the string to match @@ -348,7 +371,7 @@ extern "C" { u_int string_to_match_len, u_int16_t master_protocol_id); - + /** * Check if the string -bigram_to_match- match with a bigram of -automa- * @@ -358,11 +381,11 @@ extern "C" { * @return 0 * */ - int ndpi_match_bigram(struct ndpi_detection_module_struct *ndpi_struct, + int ndpi_match_bigram(struct ndpi_detection_module_struct *ndpi_struct, ndpi_automa *automa, char *bigram_to_match); - + /** * Write the protocol name in the buffer -buf- as master_protocol.protocol * @@ -392,7 +415,7 @@ extern "C" { * @return the protocol category */ ndpi_protocol_category_t ndpi_get_proto_category(struct ndpi_detection_module_struct *ndpi_mod, ndpi_protocol proto); - + /** * Get the protocol name associated to the ID * @@ -414,13 +437,13 @@ extern "C" { */ ndpi_protocol_breed_t ndpi_get_proto_breed(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t proto); - + /** * Return the string name of the protocol breed * * @par ndpi_struct = the detection module * @par breed_id = the breed ID associated to the protocol - * @return the string name of the breed ID + * @return the string name of the breed ID * */ char* ndpi_get_proto_breed_name(struct ndpi_detection_module_struct *ndpi_struct, ndpi_protocol_breed_t breed_id); @@ -431,7 +454,7 @@ extern "C" { * * @par ndpi_mod = the detection module * @par proto = the ID of the protocol - * @return the string name of the breed ID + * @return the string name of the breed ID * */ int ndpi_get_protocol_id(struct ndpi_detection_module_struct *ndpi_mod, char *proto); @@ -443,7 +466,7 @@ extern "C" { * @par ndpi_mod = the detection module */ void ndpi_dump_protocols(struct ndpi_detection_module_struct *mod); - + /** * Read a file and load the protocols @@ -467,12 +490,12 @@ extern "C" { * Get the total number of the supported protocols * * @par ndpi_mod = the detection module - * @return the number of protocols + * @return the number of protocols * */ u_int ndpi_get_num_supported_protocols(struct ndpi_detection_module_struct *ndpi_mod); - + /** * Get the nDPI version release * @@ -503,7 +526,7 @@ extern "C" { */ ndpi_http_method ndpi_get_http_method(struct ndpi_detection_module_struct *ndpi_mod, struct ndpi_flow_struct *flow); - + /** * Get the HTTP url * @@ -526,7 +549,7 @@ extern "C" { char* ndpi_get_http_content_type(struct ndpi_detection_module_struct *ndpi_mod, struct ndpi_flow_struct *flow); #endif - + #ifdef NDPI_PROTOCOL_TOR /** * Check if the flow could be detected as TOR protocol @@ -536,7 +559,7 @@ extern "C" { * @par certificate = the ssl certificate * @return 1 if the flow is TOR; * 0 else - * + * */ int ndpi_is_ssl_tor(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, char *certificate); @@ -547,7 +570,7 @@ extern "C" { * Init Aho-Corasick automata * * @return The requested automata, or NULL if an error occurred - * + * */ void* ndpi_init_automa(void); @@ -556,7 +579,7 @@ extern "C" { * Free Aho-Corasick automata allocated with ndpi_init_automa(); * * @par The automata initialized with ndpi_init_automa(); - * + * */ void ndpi_free_automa(void *_automa); @@ -568,7 +591,7 @@ extern "C" { * @par The (sub)string to search * @par The number associated with this string * @return 0 in case of no error, or -1 if an error occurred. - * + * */ int ndpi_add_string_value_to_automa(void *_automa, char *str, unsigned long num); @@ -579,7 +602,7 @@ extern "C" { * @par The automata initialized with ndpi_init_automa(); * @par The (sub)string to search * @return 0 in case of no error, or -1 if an error occurred. - * + * */ int ndpi_add_string_to_automa(void *_automa, char *str); @@ -588,7 +611,7 @@ extern "C" { * Finalize the automa (necessary before start searching) * * @par The automata initialized with ndpi_init_automa(); - * + * */ void ndpi_finalize_automa(void *_automa); @@ -599,7 +622,7 @@ extern "C" { * @par The automata initialized with ndpi_init_automa(); * @par The (sub)string to search * @return 0 in case of match, or -1 if no match, or -2 if an error occurred. - * + * */ int ndpi_match_string(void *_automa, char *string_to_match); @@ -611,7 +634,7 @@ extern "C" { * @par The (sub)string to search * @par The id associated with the matched string or 0 id not found. * @return 0 in case of match, or -1 if no match, or -2 if an error occurred. - * + * */ int ndpi_match_string_id(void *_automa, char *string_to_match, unsigned long *id); diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 93b1b8651..d3c34452f 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -912,7 +912,7 @@ struct ndpi_flow_struct { /* init parameter, internal used to set up timestamp,... */ u_int16_t guessed_protocol_id, guessed_host_protocol_id; - u_int8_t protocol_id_already_guessed:1, host_already_guessed:1, init_finished:1, setup_packet_direction:1, packet_direction:1; + u_int8_t protocol_id_already_guessed:1, host_already_guessed:1, init_finished:1, setup_packet_direction:1, packet_direction:1, check_extra_packets:1; /* if ndpi_struct->direction_detect_disable == 1 @@ -920,6 +920,10 @@ struct ndpi_flow_struct { */ u_int32_t next_tcp_seq_nr[2]; + u_int8_t max_extra_packets_to_check; + u_int8_t num_extra_packets_checked; + int (*extra_packets_func) (struct ndpi_detection_module_struct *, struct ndpi_flow_struct *flow); + /* the tcp / udp / other l4 value union used to reduce the number of bytes for tcp or udp protocol states diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 8ed89e3ae..537893567 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -1616,7 +1616,7 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp no_master, "Nintendo", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); - + /* calling function for host and content matched protocols */ init_string_based_protocols(ndpi_mod); @@ -1635,7 +1635,7 @@ static int ac_match_handler(AC_MATCH_t *m, void *param) { /* Return 1 for stopping to the first match. We might consider searching for the more - specific match, paying more cpu cycles. + specific match, paying more cpu cycles. */ *matching_protocol_id = m->patterns[0].rep.number; @@ -3426,6 +3426,50 @@ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_st /* ********************************************************************************* */ +void ndpi_process_extra_packet(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + const unsigned char *packet, + const unsigned short packetlen, + const u_int64_t current_tick_l, + struct ndpi_id_struct *src, + struct ndpi_id_struct *dst) +{ + if(flow == NULL) + return; + + if(flow->server_id == NULL) flow->server_id = dst; /* Default */ + + /* need at least 20 bytes for ip header */ + if(packetlen < 20) { + return; + } + + flow->packet.tick_timestamp_l = current_tick_l; + flow->packet.tick_timestamp = (u_int32_t)current_tick_l/1000; + + /* parse packet */ + flow->packet.iph = (struct ndpi_iphdr *)packet; + /* we are interested in ipv4 packet */ + + /* set up the packet headers for the extra packet function to use if it wants */ + if(ndpi_init_packet_header(ndpi_struct, flow, packetlen) != 0) + return; + + /* detect traffic for tcp or udp only */ + flow->src = src, flow->dst = dst; + ndpi_connection_tracking(ndpi_struct, 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_struct, flow)) == 0) + flow->check_extra_packets = 0; + } + + flow->num_extra_packets_checked++; +} + +/* ********************************************************************************* */ + ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, const unsigned char *packet, @@ -4622,7 +4666,7 @@ 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; } @@ -4635,7 +4679,7 @@ int ndpi_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_stru AC_TEXT_t ac_input_text; ndpi_automa *automa = is_host_match ? &ndpi_struct->host_automa : &ndpi_struct->content_automa; int rc; - + if((automa->ac_automa == NULL) || (string_to_match_len == 0)) return(NDPI_PROTOCOL_UNKNOWN); if(!automa->ac_automa_finalized) { @@ -4645,7 +4689,7 @@ int ndpi_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_stru ac_input_text.astring = string_to_match, ac_input_text.length = string_to_match_len; ac_automata_search(((AC_AUTOMATA_t*)automa->ac_automa), &ac_input_text, (void*)&matching_protocol_id); - + ac_automata_reset(((AC_AUTOMATA_t*)automa->ac_automa)); return(matching_protocol_id); diff --git a/src/lib/protocols/ssl.c b/src/lib/protocols/ssl.c index 5860abed7..5afca5389 100644 --- a/src/lib/protocols/ssl.c +++ b/src/lib/protocols/ssl.c @@ -47,7 +47,7 @@ static u_int32_t ndpi_ssl_refine_master_protocol(struct ndpi_detection_module_st if(packet->tcp != NULL) { switch(protocol) { - + case NDPI_PROTOCOL_SSL: case NDPI_PROTOCOL_SSL_NO_CERT: { @@ -57,7 +57,7 @@ static u_int32_t ndpi_ssl_refine_master_protocol(struct ndpi_detection_module_st */ u_int16_t sport = ntohs(packet->tcp->source); u_int16_t dport = ntohs(packet->tcp->dest); - + if((sport == 465) || (dport == 465)) protocol = NDPI_PROTOCOL_MAIL_SMTPS; else if((sport == 993) || (dport == 993) @@ -70,7 +70,7 @@ static u_int32_t ndpi_ssl_refine_master_protocol(struct ndpi_detection_module_st break; } } - + return protocol; } @@ -98,14 +98,14 @@ static void ndpi_int_ssl_add_connection(struct ndpi_detection_module_struct *ndp ((ch) >= '{' && (ch) <= '~')) static void stripCertificateTrailer(char *buffer, int buffer_len) { - + int i, is_puny; - + // printf("->%s<-\n", buffer); - + for(i = 0; i < buffer_len; i++) { // printf("%c [%d]\n", buffer[i], buffer[i]); - + if((buffer[i] != '.') && (buffer[i] != '-') && (buffer[i] != '_') @@ -120,12 +120,12 @@ static void stripCertificateTrailer(char *buffer, int buffer_len) { /* check for punycode encoding */ is_puny = check_punycode_string(buffer, buffer_len); - + // not a punycode string - need more checks if(is_puny == 0) { - + if(i > 0) i--; - + while(i > 0) { if(!ndpi_isalpha(buffer[i])) { buffer[i] = '\0'; @@ -134,8 +134,8 @@ static void stripCertificateTrailer(char *buffer, int buffer_len) { } else break; } - - for(i = buffer_len; i > 0; i--) { + + for(i = buffer_len; i > 0; i--) { if(buffer[i] == '.') break; else if(ndpi_isdigit(buffer[i])) buffer[i] = '\0', buffer_len = i; @@ -306,6 +306,46 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, return(0); /* Not found */ } +int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { + struct ndpi_packet_struct *packet = &flow->packet; + + /* consider only specific SSL packets (handshake) */ + if((packet->payload_packet_len > 9) && (packet->payload[0] == 0x16)) { + char certificate[64]; + int rc; + certificate[0] = '\0'; + rc = getSSLcertificate(ndpi_struct, flow, certificate, sizeof(certificate)); + packet->ssl_certificate_num_checks++; + if (rc > 0) { + packet->ssl_certificate_detected++; + if (flow->protos.ssl.server_certificate[0] != '\0') + /* 0 means we're done processing extra packets (since we found what we wanted) */ + return 0; + } + /* Client hello, Server Hello, and certificate packets probably all checked in this case */ + if ((packet->ssl_certificate_num_checks >= 3) + && (flow->l4.tcp.seen_syn) + && (flow->l4.tcp.seen_syn_ack) + && (flow->l4.tcp.seen_ack) /* We have seen the 3-way handshake */) + { + /* We're done processing extra packets since we've probably checked all possible cert packets */ + return 0; + } + } + /* 1 means keep looking for more packets */ + return 1; +} + +void sslInitExtraPacketProcessing(int caseNum, struct ndpi_flow_struct *flow) { + flow->check_extra_packets = 1; + /* 0 is the case for waiting for the server certificate */ + if (caseNum == 0) { + /* At most 7 packets should almost always be enough to find the server certificate if it's there */ + flow->max_extra_packets_to_check = 7; + flow->extra_packets_func = sslTryAndRetrieveServerCertificate; + } +} + int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; @@ -325,18 +365,22 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s #ifdef CERTIFICATE_DEBUG printf("***** [SSL] %s\n", certificate); #endif - u_int32_t subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, certificate, + u_int32_t subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, certificate, strlen(certificate), NDPI_PROTOCOL_SSL); - if(subproto != NDPI_PROTOCOL_UNKNOWN) { - ndpi_set_detected_protocol(ndpi_struct, flow, subproto, - ndpi_ssl_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSL)); - return(rc); /* Fix courtesy of Gianluca Costa <g.costa@xplico.org> */ - } - + /* If we've detected the subprotocol from client certificate but haven't had a chance + * to see the server certificate yet, set up extra packet processing to wait + * a few more packets. */ + if((flow->protos.ssl.client_certificate[0] != '\0') && (flow->protos.ssl.server_certificate[0] == '\0')) { + sslInitExtraPacketProcessing(0, flow); + } + ndpi_set_detected_protocol(ndpi_struct, flow, subproto, + ndpi_ssl_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSL)); + return(rc); /* Fix courtesy of Gianluca Costa <g.costa@xplico.org> */ + } #ifdef NDPI_PROTOCOL_TOR - if(ndpi_is_ssl_tor(ndpi_struct, flow, certificate) != 0) - return(rc); + if(ndpi_is_ssl_tor(ndpi_struct, flow, certificate) != 0) + return(rc); #endif } @@ -346,11 +390,11 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s && flow->l4.tcp.seen_ack /* We have seen the 3-way handshake */) || (flow->protos.ssl.server_certificate[0] != '\0') /* || (flow->protos.ssl.client_certificate[0] != '\0') */ - ) + ) { ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL); - } + } } - + } return(0); } |