aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/ndpi_util.c40
-rw-r--r--example/ndpi_util.h5
-rw-r--r--src/include/ndpi_api.h121
-rw-r--r--src/include/ndpi_typedefs.h6
-rw-r--r--src/lib/ndpi_main.c54
-rw-r--r--src/lib/protocols/ssl.c63
6 files changed, 207 insertions, 82 deletions
diff --git a/example/ndpi_util.c b/example/ndpi_util.c
index 75bab6319..b0955d8d4 100644
--- a/example/ndpi_util.c
+++ b/example/ndpi_util.c
@@ -158,10 +158,10 @@ int ndpi_workflow_node_cmp(const void *a, const void *b) {
if(fa->hashval < fb->hashval) return(-1); else if(fa->hashval > fb->hashval) return(1);
/* Flows have the same hash */
-
+
if(fa->vlan_id < fb->vlan_id ) return(-1); else { if(fa->vlan_id > fb->vlan_id ) return(1); }
if(fa->protocol < fb->protocol ) return(-1); else { if(fa->protocol > fb->protocol ) return(1); }
-
+
if(
(
(fa->src_ip == fb->src_ip )
@@ -178,12 +178,12 @@ int ndpi_workflow_node_cmp(const void *a, const void *b) {
)
)
return(0);
-
+
if(fa->src_ip < fb->src_ip ) return(-1); else { if(fa->src_ip > fb->src_ip ) return(1); }
if(fa->src_port < fb->src_port) return(-1); else { if(fa->src_port > fb->src_port) return(1); }
if(fa->dst_ip < fb->dst_ip ) return(-1); else { if(fa->dst_ip > fb->dst_ip ) return(1); }
if(fa->dst_port < fb->dst_port) return(-1); else { if(fa->dst_port > fb->dst_port) return(1); }
-
+
return(0); /* notreached */
}
@@ -453,7 +453,7 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
}
}
- if(flow->detection_completed) {
+ if(flow->detection_completed && !flow->check_extra_packets) {
if(flow->detected_protocol.app_protocol == NDPI_PROTOCOL_UNKNOWN) {
if (workflow->__flow_giveup_callback != NULL)
workflow->__flow_giveup_callback(workflow, flow, workflow->__flow_giveup_udata);
@@ -516,7 +516,7 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
flow->src2dst_packets++, flow->src2dst_bytes += rawsize;
else
flow->dst2src_packets++, flow->dst2src_bytes += rawsize;
-
+
flow->last_seen = time;
} else { // flow is NULL
workflow->stats.total_discarded_bytes++;
@@ -524,7 +524,28 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
}
/* Protocol already detected */
- if(flow->detection_completed) return(flow->detected_protocol);
+ if(flow->detection_completed) {
+ if(flow->check_extra_packets && ndpi_flow != NULL && ndpi_flow->check_extra_packets) {
+ if(ndpi_flow->num_extra_packets_checked == 0 && ndpi_flow->max_extra_packets_to_check == 0) {
+ /* Protocols can set this, but we set it here in case they didn't */
+ ndpi_flow->max_extra_packets_to_check = MAX_EXTRA_PACKETS_TO_CHECK;
+ }
+ if(ndpi_flow->num_extra_packets_checked < ndpi_flow->max_extra_packets_to_check) {
+ ndpi_process_extra_packet(workflow->ndpi_struct, ndpi_flow,
+ iph ? (uint8_t *)iph : (uint8_t *)iph6,
+ ipsize, time, src, dst);
+ if (ndpi_flow->check_extra_packets == 0) {
+ flow->check_extra_packets = 0;
+ ndpi_free_flow_info_half(flow);
+ }
+ }
+ } else if (ndpi_flow != NULL) {
+ /* If this wasn't NULL we should do the half free */
+ /* TODO: When half_free is deprecated, get rid of this */
+ ndpi_free_flow_info_half(flow);
+ }
+ return(flow->detected_protocol);
+ }
flow->detected_protocol = ndpi_detection_process_packet(workflow->ndpi_struct, ndpi_flow,
iph ? (uint8_t *)iph : (uint8_t *)iph6,
@@ -535,12 +556,15 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
|| ((proto == IPPROTO_TCP) && ((flow->src2dst_packets + flow->dst2src_packets) > 10))) {
/* New protocol detected or give up */
flow->detection_completed = 1;
+ /* Check if we should keep checking extra packets */
+ if (ndpi_flow->check_extra_packets)
+ flow->check_extra_packets = 1;
if(flow->detected_protocol.app_protocol == NDPI_PROTOCOL_UNKNOWN)
flow->detected_protocol = ndpi_detection_giveup(workflow->ndpi_struct,
flow->ndpi_flow);
process_ndpi_collected_info(workflow, flow);
- }
+ }
return(flow->detected_protocol);
}
diff --git a/example/ndpi_util.h b/example/ndpi_util.h
index f6d315748..45101cf10 100644
--- a/example/ndpi_util.h
+++ b/example/ndpi_util.h
@@ -36,6 +36,7 @@
#define MAX_IDLE_TIME 30000
#define IDLE_SCAN_BUDGET 1024
#define NUM_ROOTS 512
+#define MAX_EXTRA_PACKETS_TO_CHECK 7
#define MAX_NDPI_FLOWS 200000000
#define TICK_RESOLUTION 1000
#define MAX_NUM_IP_ADDRESS 5 /* len of ip address array */
@@ -56,7 +57,7 @@ typedef struct ndpi_flow_info {
u_int32_t dst_ip;
u_int16_t src_port;
u_int16_t dst_port;
- u_int8_t detection_completed, protocol, bidirectional;
+ u_int8_t detection_completed, protocol, bidirectional, check_extra_packets;
u_int16_t vlan_id;
struct ndpi_flow_struct *ndpi_flow;
char src_name[48], dst_name[48];
@@ -64,7 +65,7 @@ typedef struct ndpi_flow_info {
u_int64_t last_seen;
u_int64_t src2dst_bytes, dst2src_bytes;
u_int32_t src2dst_packets, dst2src_packets;
-
+
// result only, not used for flow identification
ndpi_protocol detected_protocol;
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 c10101d42..dd7bb89d9 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 a2f957ce9..de8c0cb7b 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -1631,7 +1631,7 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp
no_master, "FIX", NDPI_PROTOCOL_CATEGORY_RPC,
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);
@@ -1650,7 +1650,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;
@@ -3439,6 +3439,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,
@@ -4635,7 +4679,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;
}
@@ -4648,7 +4692,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) {
@@ -4658,7 +4702,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 d6e1ffd7e..5afca5389 100644
--- a/src/lib/protocols/ssl.c
+++ b/src/lib/protocols/ssl.c
@@ -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,14 +365,15 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s
#ifdef CERTIFICATE_DEBUG
printf("***** [SSL] %s\n", certificate);
#endif
- /* If we've detected the subprotocol from client certificate but haven't had a chance
- * to see the server certificate yet, wait a few more packets */
- if((flow->protos.ssl.client_certificate[0] != '\0') && (flow->protos.ssl.server_certificate[0] == '\0')) {
- return (rc);
- }
u_int32_t subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, certificate,
strlen(certificate), NDPI_PROTOCOL_SSL);
if(subproto != NDPI_PROTOCOL_UNKNOWN) {
+ /* If we've detected the subprotocol from client certificate but haven't had a chance
+ * to see the server certificate yet, set up extra packet processing to wait
+ * a few more packets. */
+ if((flow->protos.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> */
@@ -350,18 +391,6 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s
|| (flow->protos.ssl.server_certificate[0] != '\0')
/* || (flow->protos.ssl.client_certificate[0] != '\0') */
) {
- if (flow->protos.ssl.client_certificate[0] != '\0') {
- u_int32_t subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, flow->protos.ssl.client_certificate,
- strlen(flow->protos.ssl.client_certificate), NDPI_PROTOCOL_SSL);
- if (subproto != NDPI_PROTOCOL_UNKNOWN) {
- /* We would've only made it here if at some point we went into the if clause above where we wait a
- * few packets if we have a subprotocol client cert match but hadn't seen a server cert at that point. */
- ndpi_set_detected_protocol(ndpi_struct, flow, subproto,
- ndpi_ssl_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSL));
- return(2); /* Returning 2 is because we had a client certificate match
- * (since we use what would've been the return code from getSSLCertificate) */
- }
- }
ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL);
}
}