aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2020-01-05 18:25:44 +0100
committerLuca Deri <deri@ntop.org>2020-01-05 18:25:44 +0100
commitef16591f3f9d2673dfacf1c715c2e10dcd1da248 (patch)
treebabb2c57fec88d3942a2f13a911f569af33f9ac3 /src/lib/protocols
parent29dd45838da84bfa43da615d7624373392861751 (diff)
parent798bb6e2e113f10d9b710179553e4cef23222a61 (diff)
Merge branch 'dev' of https://github.com/ntop/nDPI into dev
Diffstat (limited to 'src/lib/protocols')
-rw-r--r--src/lib/protocols/bittorrent.c4
-rw-r--r--src/lib/protocols/dhcp.c52
-rw-r--r--src/lib/protocols/http.c29
-rw-r--r--src/lib/protocols/kerberos.c11
-rw-r--r--src/lib/protocols/mdns_proto.c8
-rw-r--r--src/lib/protocols/netbios.c11
-rw-r--r--src/lib/protocols/oscar.c151
-rw-r--r--src/lib/protocols/quic.c30
-rw-r--r--src/lib/protocols/ssh.c47
-rw-r--r--src/lib/protocols/tls.c1981
-rw-r--r--src/lib/protocols/ubntac2.c8
-rw-r--r--src/lib/protocols/whoisdas.c12
12 files changed, 954 insertions, 1390 deletions
diff --git a/src/lib/protocols/bittorrent.c b/src/lib/protocols/bittorrent.c
index 5ed0d311a..a1ade79b2 100644
--- a/src/lib/protocols/bittorrent.c
+++ b/src/lib/protocols/bittorrent.c
@@ -72,9 +72,7 @@ static void ndpi_add_connection_as_bittorrent(struct ndpi_detection_module_struc
} else
bt_hash = (const char*)&flow->packet.payload[28];
- if(!ndpi_struct->disable_metadata_export) {
- if(bt_hash) memcpy(flow->protos.bittorrent.hash, bt_hash, 20);
- }
+ if(bt_hash) memcpy(flow->protos.bittorrent.hash, bt_hash, 20);
}
ndpi_int_change_protocol(ndpi_struct, flow, NDPI_PROTOCOL_BITTORRENT, NDPI_PROTOCOL_UNKNOWN);
diff --git a/src/lib/protocols/dhcp.c b/src/lib/protocols/dhcp.c
index 8631989e9..f40a8138c 100644
--- a/src/lib/protocols/dhcp.c
+++ b/src/lib/protocols/dhcp.c
@@ -100,42 +100,36 @@ void ndpi_search_dhcp_udp(struct ndpi_detection_module_struct *ndpi_struct, stru
if(msg_type <= 8) foundValidMsgType = 1;
} else if(id == 55 /* Parameter Request List / Fingerprint */) {
- if(!ndpi_struct->disable_metadata_export) {
- u_int idx, offset = 0;
+ u_int idx, offset = 0;
+
+ for(idx = 0; idx < len && offset < sizeof(flow->protos.dhcp.fingerprint) - 2; idx++) {
+ int rc = snprintf((char*)&flow->protos.dhcp.fingerprint[offset],
+ sizeof(flow->protos.dhcp.fingerprint) - offset,
+ "%s%u", (idx > 0) ? "," : "",
+ (unsigned int)dhcp->options[i+2+idx] & 0xFF);
- for(idx = 0; idx < len && offset < sizeof(flow->protos.dhcp.fingerprint) - 2; idx++) {
- int rc = snprintf((char*)&flow->protos.dhcp.fingerprint[offset],
- sizeof(flow->protos.dhcp.fingerprint) - offset,
- "%s%u", (idx > 0) ? "," : "",
- (unsigned int)dhcp->options[i+2+idx] & 0xFF);
-
- if(rc < 0) break; else offset += rc;
- }
-
- flow->protos.dhcp.fingerprint[sizeof(flow->protos.dhcp.fingerprint) - 1] = '\0';
+ if(rc < 0) break; else offset += rc;
}
+
+ flow->protos.dhcp.fingerprint[sizeof(flow->protos.dhcp.fingerprint) - 1] = '\0';
} else if(id == 60 /* Class Identifier */) {
- if(!ndpi_struct->disable_metadata_export) {
- char *name = (char*)&dhcp->options[i+2];
- int j = 0;
-
- j = ndpi_min(len, sizeof(flow->protos.dhcp.class_ident)-1);
- strncpy((char*)flow->protos.dhcp.class_ident, name, j);
- flow->protos.dhcp.class_ident[j] = '\0';
- }
+ char *name = (char*)&dhcp->options[i+2];
+ int j = 0;
+
+ j = ndpi_min(len, sizeof(flow->protos.dhcp.class_ident)-1);
+ strncpy((char*)flow->protos.dhcp.class_ident, name, j);
+ flow->protos.dhcp.class_ident[j] = '\0';
} else if(id == 12 /* Host Name */) {
- if(!ndpi_struct->disable_metadata_export) {
- char *name = (char*)&dhcp->options[i+2];
- int j = 0;
-
+ char *name = (char*)&dhcp->options[i+2];
+ int j = 0;
+
#ifdef DHCP_DEBUG
- NDPI_LOG_DBG2(ndpi_struct, "[DHCP] '%.*s'\n",name,len);
+ NDPI_LOG_DBG2(ndpi_struct, "[DHCP] '%.*s'\n",name,len);
// while(j < len) { printf( "%c", name[j]); j++; }; printf("\n");
#endif
- j = ndpi_min(len, sizeof(flow->host_server_name)-1);
- strncpy((char*)flow->host_server_name, name, j);
- flow->host_server_name[j] = '\0';
- }
+ j = ndpi_min(len, sizeof(flow->host_server_name)-1);
+ strncpy((char*)flow->host_server_name, name, j);
+ flow->host_server_name[j] = '\0';
}
i += len + 2;
diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c
index fbe510459..14be88246 100644
--- a/src/lib/protocols/http.c
+++ b/src/lib/protocols/http.c
@@ -149,9 +149,8 @@ static void setHttpUserAgent(struct ndpi_detection_module_struct *ndpi_struct,
* https://github.com/ua-parser/uap-core/blob/master/regexes.yaml */
//printf("==> %s\n", ua);
- if(!ndpi_struct->disable_metadata_export) {
- snprintf((char*)flow->protos.http.detected_os, sizeof(flow->protos.http.detected_os), "%s", ua);
- }
+ snprintf((char*)flow->protos.http.detected_os,
+ sizeof(flow->protos.http.detected_os), "%s", ua);
}
/* ************************************************************* */
@@ -160,14 +159,12 @@ static void ndpi_http_parse_subprotocol(struct ndpi_detection_module_struct *ndp
struct ndpi_flow_struct *flow) {
if((flow->l4.tcp.http_stage == 0) || (flow->http.url && flow->http_detected)) {
char *double_col = strchr((char*)flow->host_server_name, ':');
- ndpi_protocol_match_result ret_match;
if(double_col) double_col[0] = '\0';
- ndpi_match_host_subprotocol(ndpi_struct, flow, (char *)flow->host_server_name,
- strlen((const char *)flow->host_server_name),
- &ret_match,
- NDPI_PROTOCOL_HTTP);
+ ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HTTP,
+ (char *)flow->host_server_name,
+ strlen((const char *)flow->host_server_name));
}
}
@@ -333,21 +330,17 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
packet->host_line.len, packet->host_line.ptr);
/* Copy result for nDPI apps */
- if(!ndpi_struct->disable_metadata_export) {
- len = ndpi_min(packet->host_line.len, sizeof(flow->host_server_name)-1);
- strncpy((char*)flow->host_server_name, (char*)packet->host_line.ptr, len);
- flow->host_server_name[len] = '\0';
- flow->extra_packets_func = NULL; /* We're good now */
- }
+ len = ndpi_min(packet->host_line.len, sizeof(flow->host_server_name)-1);
+ strncpy((char*)flow->host_server_name, (char*)packet->host_line.ptr, len);
+ flow->host_server_name[len] = '\0';
+ flow->extra_packets_func = NULL; /* We're good now */
flow->server_id = flow->dst;
if(packet->forwarded_line.ptr) {
len = ndpi_min(packet->forwarded_line.len, sizeof(flow->protos.http.nat_ip)-1);
- if(!ndpi_struct->disable_metadata_export) {
- strncpy((char*)flow->protos.http.nat_ip, (char*)packet->forwarded_line.ptr, len);
- flow->protos.http.nat_ip[len] = '\0';
- }
+ strncpy((char*)flow->protos.http.nat_ip, (char*)packet->forwarded_line.ptr, len);
+ flow->protos.http.nat_ip[len] = '\0';
}
ndpi_http_parse_subprotocol(ndpi_struct, flow);
diff --git a/src/lib/protocols/kerberos.c b/src/lib/protocols/kerberos.c
index 06d258006..43f1127d1 100644
--- a/src/lib/protocols/kerberos.c
+++ b/src/lib/protocols/kerberos.c
@@ -28,7 +28,7 @@
#include "ndpi_api.h"
-//#define KERBEROS_DEBUG 1
+/* #define KERBEROS_DEBUG 1 */
#define KERBEROS_PORT 88
@@ -190,7 +190,7 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t name_offset;
name_offset = body_offset + 13;
- for(i=0; i<10; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */
+ for(i=0; i<20; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */
#ifdef KERBEROS_DEBUG
printf("name_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", name_offset, packet->payload[name_offset], packet->payload[name_offset+1]);
@@ -222,8 +222,7 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
for(i=0; i<cname_len; i++) cname_str[i] = tolower(cname_str[i]);
#ifdef KERBEROS_DEBUG
- printf("[AS-REQ][s/dport: %u/%u][Kerberos Cname][len: %u][%s]\n",
- sport, dport, cname_len, cname_str);
+ printf("[AS-REQ][s/dport: %u/%u][Kerberos Cname][len: %u][%s]\n", sport, dport, cname_len, cname_str);
#endif
if(((strcmp(cname_str, "host") == 0) || (strcmp(cname_str, "ldap") == 0)) && (packet->payload[name_offset+1+cname_len] == 0x1b)) {
@@ -242,7 +241,7 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
} else
snprintf(flow->protos.kerberos.username, sizeof(flow->protos.kerberos.username), "%s", cname_str);
- for(i=0; i<10; i++) if(packet->payload[realm_offset] != 0x1b) name_offset++; /* ASN.1 */
+ for(i=0; i<14; i++) if(packet->payload[realm_offset] != 0x1b) realm_offset++; /* ASN.1 */
#ifdef KERBEROS_DEBUG
printf("realm_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", realm_offset, packet->payload[realm_offset], packet->payload[realm_offset+1]);
#endif
@@ -279,7 +278,7 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
u_int name_offset, padding_offset = body_offset + 4;
name_offset = padding_offset;
- for(i=0; i<10; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */
+ for(i=0; i<14; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */
#ifdef KERBEROS_DEBUG
printf("name_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", name_offset, packet->payload[name_offset], packet->payload[name_offset+1]);
diff --git a/src/lib/protocols/mdns_proto.c b/src/lib/protocols/mdns_proto.c
index 506491be1..2b75f19ec 100644
--- a/src/lib/protocols/mdns_proto.c
+++ b/src/lib/protocols/mdns_proto.c
@@ -82,11 +82,9 @@ static int ndpi_int_check_mdns_payload(struct ndpi_detection_module_struct
/* printf("==> [%d] %s\n", j, answer); */
- if(!ndpi_struct->disable_metadata_export) {
- len = ndpi_min(sizeof(flow->protos.mdns.answer)-1, j);
- strncpy(flow->protos.mdns.answer, (const char *)answer, len);
- flow->protos.mdns.answer[len] = '\0';
- }
+ len = ndpi_min(sizeof(flow->protos.mdns.answer)-1, j);
+ strncpy(flow->protos.mdns.answer, (const char *)answer, len);
+ flow->protos.mdns.answer[len] = '\0';
NDPI_LOG_INFO(ndpi_struct, "found MDNS with answer query\n");
return 1;
diff --git a/src/lib/protocols/netbios.c b/src/lib/protocols/netbios.c
index e21a5639b..19cffeb82 100644
--- a/src/lib/protocols/netbios.c
+++ b/src/lib/protocols/netbios.c
@@ -73,13 +73,10 @@ int ndpi_netbios_name_interpret(char *in, char *out, u_int out_len) {
static void ndpi_int_netbios_add_connection(struct ndpi_detection_module_struct
*ndpi_struct, struct ndpi_flow_struct *flow) {
char name[64];
-
- if(!ndpi_struct->disable_metadata_export) {
- u_int off = flow->packet.payload[12] == 0x20 ? 12 : 14;
-
- if(ndpi_netbios_name_interpret((char*)&flow->packet.payload[off], name, sizeof(name)) > 0)
- snprintf((char*)flow->host_server_name, sizeof(flow->host_server_name)-1, "%s", name);
- }
+ u_int off = flow->packet.payload[12] == 0x20 ? 12 : 14;
+
+ if(ndpi_netbios_name_interpret((char*)&flow->packet.payload[off], name, sizeof(name)) > 0)
+ snprintf((char*)flow->host_server_name, sizeof(flow->host_server_name)-1, "%s", name);
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_NETBIOS, NDPI_PROTOCOL_UNKNOWN);
}
diff --git a/src/lib/protocols/oscar.c b/src/lib/protocols/oscar.c
index 91420a5b5..a24b9441e 100644
--- a/src/lib/protocols/oscar.c
+++ b/src/lib/protocols/oscar.c
@@ -83,10 +83,10 @@ static void ndpi_int_oscar_add_connection(struct ndpi_detection_module_struct *n
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR, NDPI_PROTOCOL_UNKNOWN);
- if (src != NULL) {
+ if(src != NULL) {
src->oscar_last_safe_access_time = packet->tick_timestamp;
}
- if (dst != NULL) {
+ if(dst != NULL) {
dst->oscar_last_safe_access_time = packet->tick_timestamp;
}
}
@@ -107,10 +107,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
u_int16_t family;
u_int16_t type;
u_int16_t flag;
- u_int32_t req_ID;
-
struct ndpi_packet_struct * packet = &flow->packet;
-
struct ndpi_id_struct * src = flow->src;
struct ndpi_id_struct * dst = flow->dst;
@@ -124,7 +121,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
* [ 4 byte of data ]
*
* */
- if (packet->payload_packet_len >= 6 && packet->payload[0] == 0x2a)
+ if(packet->payload_packet_len >= 6 && packet->payload[0] == 0x2a)
{
/* FLAP__FRAME_TYPE (Channel)*/
@@ -140,7 +137,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
+ TLVs | [Class: FLAP__SIGNON_TAGS] TLVs +
+--------------------------------------------------+
*/
- if (channel == SIGNON &&
+ if(channel == SIGNON &&
get_u_int16_t(packet->payload, 4) == htons(packet->payload_packet_len - 6) &&
get_u_int32_t(packet->payload, 6) == htonl(FLAPVERSION))
{
@@ -153,28 +150,28 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
return;
}
/* /\* SCREEN_NAME *\/ */
- /* if (get_u_int16_t(packet->payload, 10) == htons(SCREEN_NAME)) /\* packet->payload[10] == 0x00 && packet->payload[11] == 0x01 *\/ */
+ /* if(get_u_int16_t(packet->payload, 10) == htons(SCREEN_NAME)) /\* packet->payload[10] == 0x00 && packet->payload[11] == 0x01 *\/ */
/* { */
/* NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Screen Name \n"); */
/* ndpi_int_oscar_add_connection(ndpi_struct, flow); */
/* return; */
/* } */
/* /\* PASSWD *\/ */
- /* if (get_u_int16_t(packet->payload, 10) == htons(PASSWD)) /\* packet->payload[10] == 0x00 && packet->payload[11] == 0x02 *\/ */
+ /* if(get_u_int16_t(packet->payload, 10) == htons(PASSWD)) /\* packet->payload[10] == 0x00 && packet->payload[11] == 0x02 *\/ */
/* { */
/* NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Password (roasted) \n"); */
/* ndpi_int_oscar_add_connection(ndpi_struct, flow); */
/* return; */
/* } */
/* CLIENT_NAME */
- if (get_u_int16_t(packet->payload, 10) == htons(CLIENT_NAME)) /* packet->payload[10] == 0x00 && packet->payload[11] == 0x03 */
+ if(get_u_int16_t(packet->payload, 10) == htons(CLIENT_NAME)) /* packet->payload[10] == 0x00 && packet->payload[11] == 0x03 */
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Client Name \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
}
/* LOGIN_COOKIE */
- if (get_u_int16_t(packet->payload, 10) == htons(LOGIN_COOKIE) &&
+ if(get_u_int16_t(packet->payload, 10) == htons(LOGIN_COOKIE) &&
get_u_int16_t(packet->payload, 12) == htons(0x0100))
{
if(get_u_int16_t(packet->payload, packet->payload_packet_len - 5) == htons(MULTICONN_FLAGS)) /* MULTICONN_FLAGS */
@@ -191,35 +188,35 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* MAJOR_VERSION */
- if (get_u_int16_t(packet->payload, 10) == htons(MAJOR_VERSION))
+ if(get_u_int16_t(packet->payload, 10) == htons(MAJOR_VERSION))
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Major_Version \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
}
/* MINOR_VERSION */
- if (get_u_int16_t(packet->payload, 10) == htons(MINOR_VERSION))
+ if(get_u_int16_t(packet->payload, 10) == htons(MINOR_VERSION))
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Minor_Version \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
}
/* POINT_VERSION */
- if (get_u_int16_t(packet->payload, 10) == htons(POINT_VERSION))
+ if(get_u_int16_t(packet->payload, 10) == htons(POINT_VERSION))
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Point_Version \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
}
/* BUILD_NUM */
- if (get_u_int16_t(packet->payload, 10) == htons(BUILD_NUM))
+ if(get_u_int16_t(packet->payload, 10) == htons(BUILD_NUM))
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Build_Num \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
}
/* CLIENT_RECONNECT */
- if (get_u_int16_t(packet->payload, 10) == htons(CLIENT_RECONNECT))
+ if(get_u_int16_t(packet->payload, 10) == htons(CLIENT_RECONNECT))
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Client_Reconnect \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
@@ -244,24 +241,24 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
+ requestId | 4 byte +
+----------------------------------------------+
*/
- if (channel == DATA)
+ if(channel == DATA)
{
- if (packet->payload_packet_len >= 8)
+ if(packet->payload_packet_len >= 8)
family = get_u_int16_t(packet->payload, 6);
else
family = 0;
- if (packet->payload_packet_len >= 10)
+ if(packet->payload_packet_len >= 10)
type = get_u_int16_t(packet->payload, 8);
else
type = 0;
- if (family == 0 || type == 0)
+ if(family == 0 || type == 0)
{
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
}
/* Family 0x0001 */
- if (family == htons(GE_SE_CTL))
+ if(family == htons(GE_SE_CTL))
{
switch (type) {
@@ -297,7 +294,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0002 */
- if (family == htons(LOC_SRV))
+ if(family == htons(LOC_SRV))
{
switch (type) {
@@ -320,7 +317,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0003 */
- if (family == htons(BUDDY_LIST))
+ if(family == htons(BUDDY_LIST))
{
switch (type) {
@@ -340,7 +337,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0004 */
- if (family == htons(IM))
+ if(family == htons(IM))
{
switch (type) {
@@ -361,7 +358,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0006 */
- if (family == htons(IS))
+ if(family == htons(IS))
{
switch (type) {
@@ -372,7 +369,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0007 */
- if (family == htons(ACC_ADM))
+ if(family == htons(ACC_ADM))
{
switch (type) {
@@ -389,7 +386,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0008 */
- if (family == htons(POPUP))
+ if(family == htons(POPUP))
{
switch (type) {
@@ -399,7 +396,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0009 */
- if (family == htons(PMS))
+ if(family == htons(PMS))
{
switch (type) {
@@ -418,7 +415,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x000b */
- if (family == htons(USS))
+ if(family == htons(USS))
{
switch (type) {
@@ -430,7 +427,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x000d */
- if (family == htons(CHAT_ROOM_SETUP))
+ if(family == htons(CHAT_ROOM_SETUP))
{
switch (type) {
@@ -447,7 +444,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x000e */
- if (family == htons(CHAT_ROOM_ACT))
+ if(family == htons(CHAT_ROOM_ACT))
{
switch (type) {
@@ -464,7 +461,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x000f */
- if (family == htons(USER_SRCH))
+ if(family == htons(USER_SRCH))
{
switch (type) {
@@ -477,7 +474,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0010 */
- if (family == htons(BUDDY_ICON_SERVER))
+ if(family == htons(BUDDY_ICON_SERVER))
{
switch (type) {
@@ -492,7 +489,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0013 */
- if (family == htons(SERVER_STORED_INFO))
+ if(family == htons(SERVER_STORED_INFO))
{
switch (type) {
@@ -521,7 +518,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0015 */
- if (family == htons(ICQ))
+ if(family == htons(ICQ))
{
switch (type) {
@@ -532,7 +529,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0017 */
- if (family == htons(INIT_AUTH))
+ if(family == htons(INIT_AUTH))
{
switch (type) {
@@ -549,12 +546,12 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
/* Family 0x0018 */
- if (family == htons(EMAIL))
+ if(family == htons(EMAIL))
{
/* TODO */
}
/* Family 0x0085 */
- if (family == htons(IS_EXT))
+ if(family == htons(IS_EXT))
{
switch (type) {
@@ -571,15 +568,15 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
/* flag */
- if (packet->payload_packet_len >= 12)
+ if(packet->payload_packet_len >= 12)
{
flag = get_u_int16_t(packet->payload, 10);
- if (flag == htons(0x0000)|| flag == htons(0x8000) || flag == htons(0x0001))
+ if(flag == htons(0x0000)|| flag == htons(0x8000) || flag == htons(0x0001))
{
- if (packet->payload_packet_len >= 16)
+ if(packet->payload_packet_len >= 16)
{
/* request ID */
- req_ID = get_u_int32_t(packet->payload, 12);
+ // u_int32_t req_ID = get_u_int32_t(packet->payload, 12);
/* if((req_ID <= ((u_int32_t)-1))) */
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR\n");
@@ -594,7 +591,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
ERROR -> FLAP__ERROR_CHANNEL_0x03
A FLAP error - rare
*/
- if (channel == O_ERROR)
+ if(channel == O_ERROR)
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Error frame \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
@@ -604,7 +601,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
Close down the FLAP connection gracefully.
SIGNOFF: FLAP__SIGNOFF_CHANNEL_0x04
*/
- if (channel == SIGNOFF)
+ if(channel == SIGNOFF)
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Signoff frame \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
@@ -614,7 +611,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
Send a heartbeat to server to help keep connection open.
KEEP_ALIVE: FLAP__KEEP_ALIVE_CHANNEL_0x05
*/
- if (channel == KEEP_ALIVE)
+ if(channel == KEEP_ALIVE)
{
NDPI_LOG_INFO(ndpi_struct, "found OSCAR - Keep Alive frame \n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
@@ -624,11 +621,11 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
/* detect http connections */
- if (packet->payload_packet_len >= 18) {
- if ((packet->payload[0] == 'P') && (memcmp(packet->payload, "POST /photo/upload", 18) == 0)) {
+ if(packet->payload_packet_len >= 18) {
+ if((packet->payload[0] == 'P') && (memcmp(packet->payload, "POST /photo/upload", 18) == 0)) {
NDPI_PARSE_PACKET_LINE_INFO(ndpi_struct, flow, packet);
- if (packet->host_line.len >= 18 && packet->host_line.ptr != NULL) {
- if (memcmp(packet->host_line.ptr, "lifestream.aol.com", 18) == 0) {
+ if(packet->host_line.len >= 18 && packet->host_line.ptr != NULL) {
+ if(memcmp(packet->host_line.ptr, "lifestream.aol.com", 18) == 0) {
NDPI_LOG_INFO(ndpi_struct,
"found OSCAR over HTTP, POST method\n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
@@ -637,9 +634,9 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
}
- if (packet->payload_packet_len > 40) {
- if ((packet->payload[0] == 'G') && (memcmp(packet->payload, "GET /", 5) == 0)) {
- if ((memcmp(&packet->payload[5], "aim/fetchEvents?aimsid=", 23) == 0) ||
+ if(packet->payload_packet_len > 40) {
+ if((packet->payload[0] == 'G') && (memcmp(packet->payload, "GET /", 5) == 0)) {
+ if((memcmp(&packet->payload[5], "aim/fetchEvents?aimsid=", 23) == 0) ||
(memcmp(&packet->payload[5], "aim/startSession?", 17) == 0) ||
(memcmp(&packet->payload[5], "aim/gromit/aim_express", 22) == 0) ||
(memcmp(&packet->payload[5], "b/ss/aolwpaim", 13) == 0) ||
@@ -649,9 +646,9 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
return;
}
- if ((memcmp(&packet->payload[5], "aim", 3) == 0) || (memcmp(&packet->payload[5], "im", 2) == 0)) {
+ if((memcmp(&packet->payload[5], "aim", 3) == 0) || (memcmp(&packet->payload[5], "im", 2) == 0)) {
NDPI_PARSE_PACKET_LINE_INFO(ndpi_struct, flow, packet);
- if (packet->user_agent_line.len > 15 && packet->user_agent_line.ptr != NULL &&
+ if(packet->user_agent_line.len > 15 && packet->user_agent_line.ptr != NULL &&
((memcmp(packet->user_agent_line.ptr, "mobileAIM/", 10) == 0) ||
(memcmp(packet->user_agent_line.ptr, "ICQ/", 4) == 0) ||
(memcmp(packet->user_agent_line.ptr, "mobileICQ/", 10) == 0) ||
@@ -663,14 +660,14 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
NDPI_PARSE_PACKET_LINE_INFO(ndpi_struct, flow, packet);
- if (packet->referer_line.ptr != NULL && packet->referer_line.len >= 22) {
+ if(packet->referer_line.ptr != NULL && packet->referer_line.len >= 22) {
- if (memcmp(&packet->referer_line.ptr[packet->referer_line.len - NDPI_STATICSTRING_LEN("WidgetMain.swf")],
+ if(memcmp(&packet->referer_line.ptr[packet->referer_line.len - NDPI_STATICSTRING_LEN("WidgetMain.swf")],
"WidgetMain.swf", NDPI_STATICSTRING_LEN("WidgetMain.swf")) == 0) {
u_int16_t i;
for (i = 0; i < (packet->referer_line.len - 22); i++) {
- if (packet->referer_line.ptr[i] == 'a') {
- if (memcmp(&packet->referer_line.ptr[i + 1], "im/gromit/aim_express", 21) == 0) {
+ if(packet->referer_line.ptr[i] == 'a') {
+ if(memcmp(&packet->referer_line.ptr[i + 1], "im/gromit/aim_express", 21) == 0) {
NDPI_LOG_INFO(ndpi_struct,
"found OSCAR over HTTP : aim/gromit/aim_express\n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
@@ -681,13 +678,13 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
}
- if (memcmp(packet->payload, "CONNECT ", 8) == 0) {
- if (memcmp(packet->payload, "CONNECT login.icq.com:443 HTTP/1.", 33) == 0) {
+ if(memcmp(packet->payload, "CONNECT ", 8) == 0) {
+ if(memcmp(packet->payload, "CONNECT login.icq.com:443 HTTP/1.", 33) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found OSCAR ICQ-HTTP\n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
}
- if (memcmp(packet->payload, "CONNECT login.oscar.aol.com:5190 HTTP/1.", 40) == 0) {
+ if(memcmp(packet->payload, "CONNECT login.oscar.aol.com:5190 HTTP/1.", 40) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found OSCAR AIM-HTTP\n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
@@ -696,32 +693,32 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
}
- if (packet->payload_packet_len > 43
+ if(packet->payload_packet_len > 43
&& memcmp(packet->payload, "GET http://http.proxy.icq.com/hello HTTP/1.", 43) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found OSCAR ICQ-HTTP PROXY\n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
}
- if (packet->payload_packet_len > 46
+ if(packet->payload_packet_len > 46
&& memcmp(packet->payload, "GET http://aimhttp.oscar.aol.com/hello HTTP/1.", 46) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found OSCAR AIM-HTTP PROXY\n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
return;
}
- if (packet->payload_packet_len > 5 && get_u_int32_t(packet->payload, 0) == htonl(0x05010003)) {
+ if(packet->payload_packet_len > 5 && get_u_int32_t(packet->payload, 0) == htonl(0x05010003)) {
NDPI_LOG_DBG2(ndpi_struct, "Maybe OSCAR Picturetransfer\n");
return;
}
- if (packet->payload_packet_len == 10 && get_u_int32_t(packet->payload, 0) == htonl(0x05000001) &&
+ if(packet->payload_packet_len == 10 && get_u_int32_t(packet->payload, 0) == htonl(0x05000001) &&
get_u_int32_t(packet->payload, 4) == 0) {
NDPI_LOG_DBG2(ndpi_struct, "Maybe OSCAR Picturetransfer\n");
return;
}
- if (packet->payload_packet_len >= 70 &&
+ if(packet->payload_packet_len >= 70 &&
memcmp(&packet->payload[packet->payload_packet_len - 26],
"\x67\x00\x65\x00\x74\x00\x43\x00\x61\x00\x74\x00\x61\x00\x6c\x00\x6f\x00\x67", 19) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found OSCAR PICTURE TRANSFER\n");
@@ -729,9 +726,9 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
return;
}
- if (NDPI_SRC_OR_DST_HAS_PROTOCOL(src, dst, NDPI_PROTOCOL_OSCAR) != 0) {
+ if(NDPI_SRC_OR_DST_HAS_PROTOCOL(src, dst, NDPI_PROTOCOL_OSCAR) != 0) {
- if (flow->packet_counter == 1
+ if(flow->packet_counter == 1
&&
((packet->payload_packet_len == 9
&& memcmp(packet->payload, "\x00\x09\x00\x00\x83\x01\xc0\x00\x00", 9) == 0)
@@ -742,13 +739,13 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
}
#if 0
- if (flow->oscar_video_voice && ntohs(get_u_int16_t(packet->payload, 0)) == packet->payload_packet_len
+ if(flow->oscar_video_voice && ntohs(get_u_int16_t(packet->payload, 0)) == packet->payload_packet_len
&& packet->payload[2] == 0x00 && packet->payload[3] == 0x00) {
}
#endif
- if (packet->payload_packet_len >= 70 && ntohs(get_u_int16_t(packet->payload, 4)) == packet->payload_packet_len) {
- if (memcmp(packet->payload, "OFT", 3) == 0 &&
+ if(packet->payload_packet_len >= 70 && ntohs(get_u_int16_t(packet->payload, 4)) == packet->payload_packet_len) {
+ if(memcmp(packet->payload, "OFT", 3) == 0 &&
((packet->payload[3] == '3' && ((memcmp(&packet->payload[4], "\x01\x00\x01\x01", 4) == 0)
|| (memcmp(&packet->payload[6], "\x01\x01\x00", 3) == 0)))
|| (packet->payload[3] == '2' && ((memcmp(&packet->payload[6], "\x01\x01", 2)
@@ -760,7 +757,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
return;
}
- if (memcmp(packet->payload, "ODC2", 4) == 0 && memcmp(&packet->payload[6], "\x00\x01\x00\x06", 4) == 0) {
+ if(memcmp(packet->payload, "ODC2", 4) == 0 && memcmp(&packet->payload[6], "\x00\x01\x00\x06", 4) == 0) {
//PICTURE TRANSFER PATTERN EXMAPLE::
//4f 44 43 32 00 4c 00 01 00 06 00 00 00 00 00 00 ODC2.L..........
NDPI_LOG_INFO(ndpi_struct, "found OSCAR PICTURE TRANSFER\n");
@@ -768,7 +765,7 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
return;
}
}
- if (packet->payload_packet_len > 40 && (memcmp(&packet->payload[2], "\x04\x4a\x00", 3) == 0)
+ if(packet->payload_packet_len > 40 && (memcmp(&packet->payload[2], "\x04\x4a\x00", 3) == 0)
&& (memcmp(&packet->payload[6], "\x00\x00", 2) == 0)
&& packet->payload[packet->payload_packet_len - 15] == 'F'
&& packet->payload[packet->payload_packet_len - 12] == 'L'
@@ -776,21 +773,21 @@ static void ndpi_search_oscar_tcp_connect(struct ndpi_detection_module_struct
&& (memcmp(&packet->payload[packet->payload_packet_len - 2], "\x00\x00", 2) == 0)) {
NDPI_LOG_INFO(ndpi_struct, "found OSCAR PICTURE TRANSFER\n");
ndpi_int_oscar_add_connection(ndpi_struct, flow);
- if (ntohs(packet->tcp->dest) == 443 || ntohs(packet->tcp->source) == 443) {
+ if(ntohs(packet->tcp->dest) == 443 || ntohs(packet->tcp->source) == 443) {
flow->oscar_ssl_voice_stage = 1;
}
return;
}
}
- if (flow->packet_counter < 3 && packet->payload_packet_len > 11 && (memcmp(packet->payload, "\x00\x37\x04\x4a", 4)
+ if(flow->packet_counter < 3 && packet->payload_packet_len > 11 && (memcmp(packet->payload, "\x00\x37\x04\x4a", 4)
|| memcmp(packet->payload, "\x00\x0a\x04\x4a",
4))) {
return;
}
- if (packet->detected_protocol_stack[0] != NDPI_PROTOCOL_OSCAR) {
+ if(packet->detected_protocol_stack[0] != NDPI_PROTOCOL_OSCAR) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
}
@@ -800,7 +797,7 @@ void ndpi_search_oscar(struct ndpi_detection_module_struct *ndpi_struct, struct
{
struct ndpi_packet_struct *packet = &flow->packet;
NDPI_LOG_DBG(ndpi_struct, "search OSCAR\n");
- if (packet->tcp != NULL) {
+ if(packet->tcp != NULL) {
ndpi_search_oscar_tcp_connect(ndpi_struct, flow);
}
}
diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c
index 0d83e4739..5c565e5a1 100644
--- a/src/lib/protocols/quic.c
+++ b/src/lib/protocols/quic.c
@@ -129,23 +129,21 @@ void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
sni_offset++;
if((sni_offset+len) < udp_len) {
- if(!ndpi_struct->disable_metadata_export) {
- int max_len = sizeof(flow->host_server_name)-1, j = 0;
- ndpi_protocol_match_result ret_match;
-
- if(len > max_len) len = max_len;
-
- while((len > 0) && (sni_offset < udp_len)) {
- flow->host_server_name[j++] = packet->payload[sni_offset];
- sni_offset++, len--;
- }
-
- ndpi_match_host_subprotocol(ndpi_struct, flow,
- (char *)flow->host_server_name,
- strlen((const char*)flow->host_server_name),
- &ret_match,
- NDPI_PROTOCOL_QUIC);
+ int max_len = sizeof(flow->host_server_name)-1, j = 0;
+ ndpi_protocol_match_result ret_match;
+
+ if(len > max_len) len = max_len;
+
+ while((len > 0) && (sni_offset < udp_len)) {
+ flow->host_server_name[j++] = packet->payload[sni_offset];
+ sni_offset++, len--;
}
+
+ ndpi_match_host_subprotocol(ndpi_struct, flow,
+ (char *)flow->host_server_name,
+ strlen((const char*)flow->host_server_name),
+ &ret_match,
+ NDPI_PROTOCOL_QUIC);
}
break;
diff --git a/src/lib/protocols/ssh.c b/src/lib/protocols/ssh.c
index 2f7fe97ae..44eaf333e 100644
--- a/src/lib/protocols/ssh.c
+++ b/src/lib/protocols/ssh.c
@@ -251,18 +251,16 @@ static void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct
if(flow->l4.tcp.ssh_stage == 0) {
if(packet->payload_packet_len > 7 && packet->payload_packet_len < 100
&& memcmp(packet->payload, "SSH-", 4) == 0) {
- if(!ndpi_struct->disable_metadata_export) {
- int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len);
-
- strncpy(flow->protos.ssh.client_signature, (const char *)packet->payload, len);
- flow->protos.ssh.client_signature[len] = '\0';
- ndpi_ssh_zap_cr(flow->protos.ssh.client_signature, len);
-
+ int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len);
+
+ strncpy(flow->protos.ssh.client_signature, (const char *)packet->payload, len);
+ flow->protos.ssh.client_signature[len] = '\0';
+ ndpi_ssh_zap_cr(flow->protos.ssh.client_signature, len);
+
#ifdef SSH_DEBUG
- printf("[SSH] [client_signature: %s]\n", flow->protos.ssh.client_signature);
-#endif
- }
-
+ printf("[SSH] [client_signature: %s]\n", flow->protos.ssh.client_signature);
+#endif
+
NDPI_LOG_DBG2(ndpi_struct, "ssh stage 0 passed\n");
flow->l4.tcp.ssh_stage = 1 + packet->packet_direction;
ndpi_int_ssh_add_connection(ndpi_struct, flow);
@@ -271,24 +269,19 @@ static void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct
} else if(flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) {
if(packet->payload_packet_len > 7 && packet->payload_packet_len < 500
&& memcmp(packet->payload, "SSH-", 4) == 0) {
- if(!ndpi_struct->disable_metadata_export) {
- int len = ndpi_min(sizeof(flow->protos.ssh.server_signature)-1, packet->payload_packet_len);
-
- strncpy(flow->protos.ssh.server_signature, (const char *)packet->payload, len);
- flow->protos.ssh.server_signature[len] = '\0';
- ndpi_ssh_zap_cr(flow->protos.ssh.server_signature, len);
-
+ int len = ndpi_min(sizeof(flow->protos.ssh.server_signature)-1, packet->payload_packet_len);
+
+ strncpy(flow->protos.ssh.server_signature, (const char *)packet->payload, len);
+ flow->protos.ssh.server_signature[len] = '\0';
+ ndpi_ssh_zap_cr(flow->protos.ssh.server_signature, len);
+
#ifdef SSH_DEBUG
- printf("[SSH] [server_signature: %s]\n", flow->protos.ssh.server_signature);
+ printf("[SSH] [server_signature: %s]\n", flow->protos.ssh.server_signature);
#endif
-
- NDPI_LOG_DBG2(ndpi_struct, "ssh stage 1 passed\n");
- flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH;
- } else {
- NDPI_LOG_INFO(ndpi_struct, "found ssh\n");
- ndpi_int_ssh_add_connection(ndpi_struct, flow);
- }
-
+
+ NDPI_LOG_DBG2(ndpi_struct, "ssh stage 1 passed\n");
+ flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH;
+
#ifdef SSH_DEBUG
printf("[SSH] [completed stage: %u]\n", flow->l4.tcp.ssh_stage);
#endif
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index 185056fba..737585db4 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -31,9 +31,17 @@
extern char *strptime(const char *s, const char *format, struct tm *tm);
+extern int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow);
+
+#if 0
+#define DEBUG_TLS_MEMORY 1
+#define DEBUG_TLS 1
+#endif
-/* #define DEBUG_TLS 1 */
+// #define DEBUG_CERTIFICATE_HASH
+
/* #define DEBUG_FINGERPRINT 1 */
/*
@@ -60,8 +68,8 @@ extern u_int8_t is_skype_flow(struct ndpi_detection_module_struct *ndpi_struct,
/* stun.c */
extern u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow, u_int8_t rev);
-extern int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow);
+static void ndpi_int_tls_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow, u_int32_t protocol);
/* **************************************** */
@@ -93,30 +101,61 @@ static u_int32_t ndpi_tls_refine_master_protocol(struct ndpi_detection_module_st
}
}
- return protocol;
+ return(protocol);
}
/* **************************************** */
-static void sslInitExtraPacketProcessing(struct ndpi_flow_struct *flow) {
- flow->check_extra_packets = 1;
+void ndpi_search_tls_tcp_memory(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
+ struct ndpi_packet_struct *packet = &flow->packet;
- /* 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;
-}
+ /* TCP */
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] Handling TCP/TLS flow [payload_len: %u][buffer_len: %u][direction: %u]\n",
+ packet->payload_packet_len,
+ flow->l4.tcp.tls.message.buffer_len,
+ packet->packet_direction);
+#endif
-/* **************************************** */
+ if(flow->l4.tcp.tls.message.buffer == NULL) {
+ /* Allocate buffer */
+ flow->l4.tcp.tls.message.buffer_len = 2048, flow->l4.tcp.tls.message.buffer_used = 0;
+ flow->l4.tcp.tls.message.buffer = (u_int8_t*)ndpi_malloc(flow->l4.tcp.tls.message.buffer_len);
-static void ndpi_int_tls_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow, u_int32_t protocol) {
- if(protocol != NDPI_PROTOCOL_TLS)
- ;
- else
- protocol = ndpi_tls_refine_master_protocol(ndpi_struct, flow, protocol);
+ if(flow->l4.tcp.tls.message.buffer == NULL)
+ return;
- ndpi_set_detected_protocol(ndpi_struct, flow, protocol, NDPI_PROTOCOL_TLS);
- sslInitExtraPacketProcessing(flow);
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] Allocating %u buffer\n", flow->l4.tcp.tls.message.buffer_len);
+#endif
+ }
+
+ u_int avail_bytes = flow->l4.tcp.tls.message.buffer_len - flow->l4.tcp.tls.message.buffer_used;
+ if(avail_bytes < packet->payload_packet_len) {
+ u_int new_len = flow->l4.tcp.tls.message.buffer_len + packet->payload_packet_len;
+ void *newbuf = ndpi_realloc(flow->l4.tcp.tls.message.buffer,
+ flow->l4.tcp.tls.message.buffer_len, new_len);
+ if(!newbuf) return;
+
+ flow->l4.tcp.tls.message.buffer = (u_int8_t*)newbuf, flow->l4.tcp.tls.message.buffer_len = new_len;
+ avail_bytes = flow->l4.tcp.tls.message.buffer_len - flow->l4.tcp.tls.message.buffer_used;
+
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] Enlarging %u -> %u buffer\n", flow->l4.tcp.tls.message.buffer_len, new_len);
+#endif
+ }
+
+ if(avail_bytes >= packet->payload_packet_len) {
+ memcpy(&flow->l4.tcp.tls.message.buffer[flow->l4.tcp.tls.message.buffer_used],
+ packet->payload, packet->payload_packet_len);
+
+ flow->l4.tcp.tls.message.buffer_used += packet->payload_packet_len;
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] Copied data to buffer [%u/%u bytes]\n",
+ flow->l4.tcp.tls.message.buffer_used, flow->l4.tcp.tls.message.buffer_len);
+#endif
+ }
}
/* **************************************** */
@@ -134,9 +173,12 @@ static void ndpi_int_tls_add_connection(struct ndpi_detection_module_struct *ndp
/* **************************************** */
-static void stripCertificateTrailer(char *buffer, int buffer_len) {
- int i, is_puny;
-
+static void cleanupServerName(char *buffer, int buffer_len) {
+ u_int i;
+
+#if 0
+ int is_puny;
+
// printf("->%s<-\n", buffer);
for(i = 0; i < buffer_len; i++) {
@@ -159,7 +201,6 @@ static void stripCertificateTrailer(char *buffer, int buffer_len) {
// not a punycode string - need more checks
if(is_puny == 0) {
-
if(i > 0) i--;
while(i > 0) {
@@ -177,7 +218,8 @@ static void stripCertificateTrailer(char *buffer, int buffer_len) {
buffer[i] = '\0', buffer_len = i;
}
}
-
+#endif
+
/* Now all lowecase */
for(i=0; i<buffer_len; i++)
buffer[i] = tolower(buffer[i]);
@@ -185,1412 +227,971 @@ static void stripCertificateTrailer(char *buffer, int buffer_len) {
/* **************************************** */
-/* https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967 */
-
-#define JA3_STR_LEN 1024
-#define MAX_NUM_JA3 128
+/* See https://blog.catchpoint.com/2017/05/12/dissecting-tls-using-wireshark/ */
+static void processCertificateElements(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ u_int16_t offset, u_int16_t certificate_len) {
+ struct ndpi_packet_struct *packet = &flow->packet;
+ u_int num_found = 0, i, j;
+ char buffer[64] = { '\0' };
+
+#ifdef DEBUG_TLS
+ printf("[TLS] %s() [offset: %u][certificate_len: %u]\n", __FUNCTION__, offset, certificate_len);
+#endif
-struct ja3_info {
- u_int16_t tls_handshake_version;
- u_int16_t num_cipher, cipher[MAX_NUM_JA3];
- u_int16_t num_tls_extension, tls_extension[MAX_NUM_JA3];
- u_int16_t num_elliptic_curve, elliptic_curve[MAX_NUM_JA3];
- u_int8_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA3];
-};
+ /* Check after handshake protocol header (5 bytes) and message header (4 bytes) */
+ for(i = offset; i < certificate_len; i++) {
+ /* Organization OID: 2.5.4.10 */
+ if((packet->payload[i] == 0x55) && (packet->payload[i+1] == 0x04) && (packet->payload[i+2] == 0x0a)) {
+ u_int8_t server_len = packet->payload[i+4];
-/* **************************************** */
+ num_found++;
+ /* what we want is subject certificate, so we bypass the issuer certificate */
+ if(num_found != 2) continue;
-int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow,
- char *buffer, int buffer_len) {
- struct ndpi_packet_struct *packet = &flow->packet;
- struct ja3_info ja3;
- u_int8_t invalid_ja3 = 0;
- u_int16_t pkt_tls_version = (packet->payload[1] << 8) + packet->payload[2], ja3_str_len;
- char ja3_str[JA3_STR_LEN];
- ndpi_MD5_CTX ctx;
- u_char md5_hash[16];
- int i;
+ // packet is truncated... further inspection is not needed
+ if(i+4+server_len >= packet->payload_packet_len) {
+ break;
+ }
- if(packet->udp) {
- /* Check if this is DTLS or return */
- if((packet->payload[1] != 0xfe)
- || ((packet->payload[2] != 0xff) && (packet->payload[2] != 0xfd))) {
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return(0);
- }
- }
+ char *server_org = (char*)&packet->payload[i+5];
- flow->protos.stun_ssl.ssl.ssl_version = pkt_tls_version;
+ u_int len = (u_int)ndpi_min(server_len, sizeof(buffer)-1);
+ strncpy(buffer, server_org, len);
+ buffer[len] = '\0';
- memset(&ja3, 0, sizeof(ja3));
+ // check if organization string are all printable
+ u_int8_t is_printable = 1;
+ for(j = 0; j < len; j++) {
+ if(!ndpi_isprint(buffer[j])) {
+ is_printable = 0;
+ break;
+ }
+ }
+ if(is_printable == 1) {
+ snprintf(flow->protos.stun_ssl.ssl.server_organization,
+ sizeof(flow->protos.stun_ssl.ssl.server_organization), "%s", buffer);
#ifdef DEBUG_TLS
- {
- u_int16_t tls_len = (packet->payload[3] << 8) + packet->payload[4];
-
- printf("SSL Record [version: 0x%04X][len: %u]\n", pkt_tls_version, tls_len);
- }
+ printf("Certificate organization: %s\n", flow->protos.stun_ssl.ssl.server_organization);
#endif
+ }
+ } else if((packet->payload[i] == 0x30) && (packet->payload[i+1] == 0x1e) && (packet->payload[i+2] == 0x17)) {
+ /* Certificate Validity */
+ u_int8_t len = packet->payload[i+3];
+ u_int offset = i+4;
- /*
- Nothing matched so far: let's decode the certificate with some heuristics
- Patches courtesy of Denys Fedoryshchenko <nuclearcat@nuclearcat.com>
- */
- if(packet->payload[0] == 0x16 /* Handshake */) {
- u_int16_t total_len;
- u_int8_t handshake_protocol, header_len;
-
- if(packet->tcp) {
- header_len = 5; /* SSL Header */
- handshake_protocol = packet->payload[5]; /* handshake protocol a bit misleading, it is message type according TLS specs */
- total_len = (packet->payload[3] << 8) + packet->payload[4];
- } else {
- header_len = 13; /* DTLS header */
- handshake_protocol = packet->payload[13];
- total_len = ntohs(*((u_int16_t*)&packet->payload[11]));
- }
-
- total_len += header_len;
+ if((offset+len) < packet->payload_packet_len) {
+ char utcDate[32];
- memset(buffer, 0, buffer_len);
+#ifdef DEBUG_TLS
+ printf("[CERTIFICATE] notBefore [len: %u][", len);
+ for(j=0; j<len; j++) printf("%c", packet->payload[i+4+j]);
+ printf("]\n");
+#endif
- /* Truncate total len, search at least in incomplete packet */
- if(total_len > packet->payload_packet_len)
- total_len = packet->payload_packet_len;
+ if(len < (sizeof(utcDate)-1)) {
+ struct tm utc;
+ utc.tm_isdst = -1; /* Not set by strptime */
- /* At least "magic" 3 bytes, null for string end, otherwise no need to waste cpu cycles */
- if(total_len > 4) {
- u_int16_t base_offset = packet->tcp ? 43 : 59;
+ strncpy(utcDate, (const char*)&packet->payload[i+4], len);
+ utcDate[len] = '\0';
+ /* 141021000000Z */
+ if(strptime(utcDate, "%y%m%d%H%M%SZ", &utc) != NULL) {
+ flow->protos.stun_ssl.ssl.notBefore = timegm(&utc);
#ifdef DEBUG_TLS
- printf("SSL [len: %u][handshake_protocol: %02X]\n", packet->payload_packet_len, handshake_protocol);
+ printf("[CERTIFICATE] notBefore %u [%s]\n",
+ flow->protos.stun_ssl.ssl.notBefore, utcDate);
#endif
+ }
+ }
- if((handshake_protocol == 0x02)
- || (handshake_protocol == 0x0b) /* Server Hello and Certificate message types are interesting for us */) {
- u_int num_found = 0;
- u_int16_t tls_version;
- int i, rc;
-
- if(packet->tcp)
- tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+4]));
- else
- tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+12]));
+ offset += len;
- ja3.tls_handshake_version = tls_version;
+ if((offset+1) < packet->payload_packet_len) {
+ len = packet->payload[offset+1];
- if(handshake_protocol == 0x02) {
- u_int16_t offset = base_offset, extension_len, j;
- u_int8_t session_id_len = packet->payload[offset];
+ offset += 2;
+ if((offset+len) < packet->payload_packet_len) {
#ifdef DEBUG_TLS
- printf("SSL Server Hello [version: 0x%04X]\n", tls_version);
+ printf("[CERTIFICATE] notAfter [len: %u][", len);
+ for(j=0; j<len; j++) printf("%c", packet->payload[offset+j]);
+ printf("]\n");
#endif
- /*
- The server hello decides about the SSL version of this flow
- https://networkengineering.stackexchange.com/questions/55752/why-does-wireshark-show-version-tls-1-2-here-instead-of-tls-1-3
- */
- flow->protos.stun_ssl.ssl.ssl_version = tls_version;
-
- if(packet->udp)
- offset += 1;
- else {
- if(tls_version < 0x7F15 /* TLS 1.3 lacks of session id */)
- offset += session_id_len+1;
- }
+ if(len < (sizeof(utcDate)-1)) {
+ struct tm utc;
+ utc.tm_isdst = -1; /* Not set by strptime */
- ja3.num_cipher = 1, ja3.cipher[0] = ntohs(*((u_int16_t*)&packet->payload[offset]));
- flow->protos.stun_ssl.ssl.server_unsafe_cipher = ndpi_is_safe_ssl_cipher(ja3.cipher[0]);
- flow->protos.stun_ssl.ssl.server_cipher = ja3.cipher[0];
+ strncpy(utcDate, (const char*)&packet->payload[offset], len);
+ utcDate[len] = '\0';
+ /* 141021000000Z */
+ if(strptime(utcDate, "%y%m%d%H%M%SZ", &utc) != NULL) {
+ flow->protos.stun_ssl.ssl.notAfter = timegm(&utc);
#ifdef DEBUG_TLS
- printf("TLS [server][session_id_len: %u][cipher: %04X]\n", session_id_len, ja3.cipher[0]);
+ printf("[CERTIFICATE] notAfter %u [%s]\n",
+ flow->protos.stun_ssl.ssl.notAfter, utcDate);
#endif
-
- offset += 2 + 1;
-
- if((offset + 1) < packet->payload_packet_len) /* +1 because we are goint to read 2 bytes */
- extension_len = ntohs(*((u_int16_t*)&packet->payload[offset]));
- else
- extension_len = 0;
+ }
+ }
+ }
+ }
+ }
+ } else if((packet->payload[i] == 0x55) && (packet->payload[i+1] == 0x1d) && (packet->payload[i+2] == 0x11)) {
+ /* Organization OID: 2.5.29.17 (subjectAltName) */
+ u_int16_t servernames_len = 0;
+ char servernames[2048];
#ifdef DEBUG_TLS
- printf("TLS [server][extension_len: %u]\n", extension_len);
+ printf("******* [TLS] Found subjectAltName\n");
#endif
- offset += 2;
- for(i=0; i<extension_len; ) {
- u_int16_t extension_id, extension_len;
+ i += 3 /* skip the initial patten 55 1D 11 */;
+ i++; /* skip the first type, 0x04 == BIT STRING, and jump to it's length */
+ i += packet->payload[i] & 0x80 ? packet->payload[i] & 0x7F : 0; /* skip BIT STRING length */
+ i += 2; /* skip the second type, 0x30 == SEQUENCE, and jump to it's length */
+ i += packet->payload[i] & 0x80 ? packet->payload[i] & 0x7F : 0; /* skip SEQUENCE length */
+ i++;
+
+ while(i < packet->payload_packet_len) {
+ if(packet->payload[i] == 0x82) {
+ if((i < (packet->payload_packet_len - 1))
+ && ((i + packet->payload[i + 1] + 2) < packet->payload_packet_len)) {
+ u_int8_t len = packet->payload[i + 1];
+ char dNSName[256];
+ int rc;
+
+ i += 2;
+
+ strncpy(dNSName, (const char*)&packet->payload[i], len);
+ dNSName[len] = '\0';
- if(offset >= (packet->payload_packet_len+4)) break;
+ cleanupServerName(dNSName, len);
- extension_id = ntohs(*((u_int16_t*)&packet->payload[offset]));
- extension_len = ntohs(*((u_int16_t*)&packet->payload[offset+2]));
+ rc = snprintf(&servernames[servernames_len], sizeof(servernames)-servernames_len, "%s%s",
+ (servernames_len == 0) ? "" : ",", dNSName);
- if(ja3.num_tls_extension < MAX_NUM_JA3)
- ja3.tls_extension[ja3.num_tls_extension++] = extension_id;
+ if(rc > 0)
+ servernames_len += rc;
-#ifdef DEBUG_TLS
- printf("TLS [server][extension_id: %u/0x%04X][len: %u]\n",
- extension_id, extension_id, extension_len);
+#if DEBUG_TLS
+ printf("[TLS] dNSName %s [%s]\n", dNSName, servernames);
#endif
- if(extension_id == 43 /* supported versions */) {
- if(extension_len >= 2) {
- u_int16_t tls_version = ntohs(*((u_int16_t*)&packet->payload[offset+4]));
-
-#ifdef DEBUG_TLS
- printf("TLS [server] [TLS version: 0x%04X]\n", tls_version);
-#endif
-
- flow->protos.stun_ssl.ssl.ssl_version = tls_version;
+ if(flow->protos.stun_ssl.ssl.server_names == NULL)
+ flow->protos.stun_ssl.ssl.server_names = ndpi_strdup(dNSName),
+ flow->protos.stun_ssl.ssl.server_names_len = strlen(dNSName);
+ else {
+ u_int16_t dNSName_len = strlen(dNSName);
+ u_int16_t newstr_len = flow->protos.stun_ssl.ssl.server_names_len + dNSName_len + 1;
+ char *newstr = (char*)ndpi_realloc(flow->protos.stun_ssl.ssl.server_names,
+ flow->protos.stun_ssl.ssl.server_names_len+1, newstr_len+1);
+
+ if(newstr) {
+ flow->protos.stun_ssl.ssl.server_names = newstr;
+ flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len] = ',';
+ strncpy(&flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len+1],
+ dNSName, dNSName_len+1);
+ flow->protos.stun_ssl.ssl.server_names[newstr_len] = '\0';
+ flow->protos.stun_ssl.ssl.server_names_len = newstr_len;
}
}
+
+ if(!flow->l4.tcp.tls.subprotocol_detected)
+ if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS, dNSName, len))
+ flow->l4.tcp.tls.subprotocol_detected = 1;
- i += 4 + extension_len, offset += 4 + extension_len;
+ i += len;
+ } else {
+#if DEBUG_TLS
+ printf("[TLS] Leftover %u bytes", packet->payload_packet_len - i);
+#endif
+ break;
}
+ } else {
+ break;
+ }
+ } /* while */
+ }
+ }
+}
- ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.tls_handshake_version);
+/* **************************************** */
- for(i=0; i<ja3.num_cipher; i++) {
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.cipher[i]);
+/* See https://blog.catchpoint.com/2017/05/12/dissecting-tls-using-wireshark/ */
+int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
+ struct ndpi_packet_struct *packet = &flow->packet;
+ u_int32_t certificates_length, length = (packet->payload[1] << 16) + (packet->payload[2] << 8) + packet->payload[3];
+ u_int16_t certificates_offset = 7;
+ u_int8_t num_certificates_found = 0;
+
+#ifdef DEBUG_TLS
+ printf("[TLS] %s() [payload_packet_len=%u][direction: %u][%02X %02X %02X %02X %02X %02X...]\n",
+ __FUNCTION__, packet->payload_packet_len,
+ packet->packet_direction,
+ packet->payload[0], packet->payload[1], packet->payload[2],
+ packet->payload[3], packet->payload[4], packet->payload[5]);
+#endif
- if(rc <= 0) break; else ja3_str_len += rc;
- }
-
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
- if(rc > 0) ja3_str_len += rc;
-
- /* ********** */
+ if(packet->payload_packet_len != (length + 4))
+ return(-1); /* Invalid length */
- for(i=0; i<ja3.num_tls_extension; i++) {
- int rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.tls_extension[i]);
+ certificates_length = (packet->payload[4] << 16) + (packet->payload[5] << 8) + packet->payload[6];
+
+ if((certificates_length+3) != length)
+ return(-2); /* Invalid length */
+
+ if((flow->l4.tcp.tls.srv_cert_fingerprint_ctx = (void*)ndpi_malloc(sizeof(SHA1_CTX))) == NULL)
+ return(-3); /* Not enough memory */
- if(rc <= 0) break; else ja3_str_len += rc;
- }
-
-#ifdef DEBUG_TLS
- printf("TLS [server] %s\n", ja3_str);
-#endif
+ /* Now let's process each individual certificates */
+ while(certificates_offset < certificates_length) {
+ u_int16_t certificate_len = (packet->payload[certificates_offset] << 16) + (packet->payload[certificates_offset+1] << 8) + packet->payload[certificates_offset+2];
+ certificates_offset += 3;
#ifdef DEBUG_TLS
- printf("[JA3] Server: %s \n", ja3_str);
+ printf("[TLS] Processing %u bytes certificate [%02X %02X %02X]\n",
+ certificate_len,
+ packet->payload[certificates_offset],
+ packet->payload[certificates_offset+1],
+ packet->payload[certificates_offset+2]);
#endif
- ndpi_MD5Init(&ctx);
- ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
- ndpi_MD5Final(md5_hash, &ctx);
+ if(num_certificates_found++ == 0) /* Dissect only the first certificate that is the one we care */ {
+ /* For SHA-1 we take into account only the first certificate and not all of them */
+
+ SHA1Init(flow->l4.tcp.tls.srv_cert_fingerprint_ctx);
+
+#ifdef DEBUG_CERTIFICATE_HASH
+ {
+ int i;
+
+ for(i=0;i<certificate_len;i++)
+ printf("%02X ", packet->payload[certificates_offset+i]);
+
+ printf("\n");
+ }
+#endif
+
+ SHA1Update(flow->l4.tcp.tls.srv_cert_fingerprint_ctx,
+ &packet->payload[certificates_offset],
+ certificate_len);
+
+ SHA1Final(flow->l4.tcp.tls.sha1_certificate_fingerprint, flow->l4.tcp.tls.srv_cert_fingerprint_ctx);
- for(i=0, j=0; i<16; i++) {
- int rc = snprintf(&flow->protos.stun_ssl.ssl.ja3_server[j],
- sizeof(flow->protos.stun_ssl.ssl.ja3_server)-j, "%02x", md5_hash[i]);
- if(rc <= 0) break; else j += rc;
- }
-
+ flow->l4.tcp.tls.fingerprint_set = 1;
+
#ifdef DEBUG_TLS
- printf("[JA3] Server: %s \n", flow->protos.stun_ssl.ssl.ja3_server);
+ {
+ int i;
+
+ printf("[TLS] SHA-1: ");
+ for(i=0;i<20;i++)
+ printf("%s%02X", (i > 0) ? ":" : "", flow->l4.tcp.tls.sha1_certificate_fingerprint[i]);
+ printf("\n");
+ }
#endif
- flow->l4.tcp.tls_seen_server_cert = 1;
- } else
- flow->l4.tcp.tls_seen_certificate = 1;
+ processCertificateElements(ndpi_struct, flow, certificates_offset, certificate_len);
+ }
+
+ certificates_offset += certificate_len;
+ }
+
+ flow->extra_packets_func = NULL; /* We're good now */
+ return(1);
+}
- /* Check after handshake protocol header (5 bytes) and message header (4 bytes) */
- for(i = 9; i < packet->payload_packet_len-3; i++) {
- if(((packet->payload[i] == 0x04) && (packet->payload[i+1] == 0x03) && (packet->payload[i+2] == 0x0c))
- || ((packet->payload[i] == 0x04) && (packet->payload[i+1] == 0x03) && (packet->payload[i+2] == 0x13))
- || ((packet->payload[i] == 0x55) && (packet->payload[i+1] == 0x04) && (packet->payload[i+2] == 0x03))) {
- u_int8_t server_len, off = 0;
+/* **************************************** */
- if(packet->payload[i] == 0x55) {
- num_found++, off++;
+static int processTLSBlock(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
+ struct ndpi_packet_struct *packet = &flow->packet;
+
+ switch(packet->payload[0] /* block type */) {
+ case 0x01: /* Client Hello */
+ case 0x02: /* Server Hello */
+ processClientServerHello(ndpi_struct, flow);
+ flow->l4.tcp.tls.hello_processed = 1;
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
+ break;
+
+ case 0x0b: /* Certificate */
+ processCertificate(ndpi_struct, flow);
+ flow->l4.tcp.tls.certificate_processed = 1;
+ break;
- if(num_found != 2) continue;
- }
+ default:
+ return(-1);
+ }
- server_len = packet->payload[i+3+off];
-
- if((server_len+i+3) < packet->payload_packet_len) {
- char *server_name = (char*)&packet->payload[i+4+off];
- u_int8_t begin = 0, len, j, num_dots;
-
- while(begin < server_len) {
- if(!ndpi_isprint(server_name[begin]))
- begin++;
- else
- break;
- }
+ return(0);
+}
- len = ndpi_min(server_len-begin, buffer_len-1);
- // len = buffer_len-1;
-
- strncpy(buffer, &server_name[begin], len);
- buffer[len] = '\0';
-
- // if(len != (buffer_len-1)) printf("len=%u / buffer_len-1=%u\n", len, buffer_len-1);
-
- /* We now have to check if this looks like an IP address or host name */
- for(j=0, num_dots = 0; j<len; j++) {
- if(!ndpi_isprint((buffer[j]))) {
- num_dots = 0; /* This is not what we look for */
- break;
- } else if(buffer[j] == '.') {
- num_dots++;
- if(num_dots >=1) break;
- }
- }
+/* **************************************** */
- if(num_dots >= 1) {
- if(!ndpi_struct->disable_metadata_export) {
- ndpi_protocol_match_result ret_match;
- u_int16_t subproto;
-
- stripCertificateTrailer(buffer, buffer_len);
- snprintf(flow->protos.stun_ssl.ssl.server_certificate,
- sizeof(flow->protos.stun_ssl.ssl.server_certificate), "%s", buffer);
-
-#ifdef DEBUG_TLS
- printf("[server_certificate: %s]\n", flow->protos.stun_ssl.ssl.server_certificate);
+static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
+ struct ndpi_packet_struct *packet = &flow->packet;
+ int rc = 1;
+
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] ndpi_search_tls_tcp() [payload_packet_len: %u]\n",
+ packet->payload_packet_len);
#endif
-
- subproto = ndpi_match_host_subprotocol(ndpi_struct, flow,
- flow->protos.stun_ssl.ssl.server_certificate,
- strlen(flow->protos.stun_ssl.ssl.server_certificate),
- &ret_match,
- NDPI_PROTOCOL_TLS);
-
- if(subproto != NDPI_PROTOCOL_UNKNOWN)
- ndpi_set_detected_protocol(ndpi_struct, flow, subproto, NDPI_PROTOCOL_TLS);
- }
- return(1 /* Server Certificate */);
- }
- }
- }
- }
- } else if(handshake_protocol == 0x01 /* Client Hello */) {
- u_int offset;
+ if(packet->payload_packet_len == 0)
+ return(1); /* Keep working */
-#ifdef DEBUG_TLS
- printf("[base_offset: %u][payload_packet_len: %u]\n", base_offset, packet->payload_packet_len);
+ ndpi_search_tls_tcp_memory(ndpi_struct, flow);
+
+ while(1) {
+ u_int16_t len, p_len;
+ const u_int8_t *p;
+
+ if(flow->l4.tcp.tls.message.buffer_used < 5)
+ return(1); /* Keep working */
+
+ len = (flow->l4.tcp.tls.message.buffer[3] << 8) + flow->l4.tcp.tls.message.buffer[4] + 5;
+
+ if(len > flow->l4.tcp.tls.message.buffer_used) {
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] Not enough TLS data [%u < %u][%02X %02X %02X %02X %02X]\n",
+ len, flow->l4.tcp.tls.message.buffer_used,
+ flow->l4.tcp.tls.message.buffer[0],
+ flow->l4.tcp.tls.message.buffer[1],
+ flow->l4.tcp.tls.message.buffer[2],
+ flow->l4.tcp.tls.message.buffer[3],
+ flow->l4.tcp.tls.message.buffer[4]);
#endif
+ break;
+ }
- if(base_offset + 2 <= packet->payload_packet_len) {
- u_int16_t session_id_len;
- u_int16_t tls_version;
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] Processing %u bytes message\n", len);
+#endif
- if(packet->tcp)
- tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+4]));
- else
- tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+12]));
+ /* Overwriting packet payload */
+ p = packet->payload, p_len = packet->payload_packet_len; /* Backup */
- session_id_len = packet->payload[base_offset];
+ /* Split the element in blocks */
+ u_int16_t processed = 5;
+
+ while((processed+4) < len) {
+ const u_int8_t *block = (const u_int8_t *)&flow->l4.tcp.tls.message.buffer[processed];
+ u_int16_t block_len = (block[1] << 16) + (block[2] << 8) + block[3];
- ja3.tls_handshake_version = tls_version;
+ packet->payload = block, packet->payload_packet_len = block_len+4;
- if((session_id_len+base_offset+2) <= total_len) {
- u_int16_t cipher_len, cipher_offset;
+ if((processed+packet->payload_packet_len) > len)
+ break;
+
+#ifdef DEBUG_TLS_MEMORY
+ printf("*** [TLS Mem] Processing %u bytes block [%02X %02X %02X %02X %02X]\n",
+ packet->payload_packet_len,
+ packet->payload[0], packet->payload[1], packet->payload[2], packet->payload[3], packet->payload[4]);
+#endif
- if(packet->tcp) {
- cipher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8);
- cipher_offset = base_offset + session_id_len + 3;
- } else {
- cipher_len = ntohs(*((u_int16_t*)&packet->payload[base_offset+2]));
- cipher_offset = base_offset+4;
- }
-#ifdef DEBUG_TLS
- printf("Client SSL [client cipher_len: %u][tls_version: 0x%04X]\n", cipher_len, tls_version);
+ processTLSBlock(ndpi_struct, flow);
+ processed += packet->payload_packet_len;
+ }
+
+ packet->payload = p, packet->payload_packet_len = p_len; /* Restore */
+ flow->l4.tcp.tls.message.buffer_used -= len;
+
+ memmove(flow->l4.tcp.tls.message.buffer,
+ &flow->l4.tcp.tls.message.buffer[len],
+ flow->l4.tcp.tls.message.buffer_used);
+
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] Left memory buffer %u bytes\n", flow->l4.tcp.tls.message.buffer_used);
#endif
+ }
+
+#ifdef DEBUG_TLS_MEMORY
+ printf("[TLS Mem] Returning %u\n", rc);
+#endif
+
+ return(rc);
+}
- if((cipher_offset+cipher_len) <= total_len) {
- for(i=0; i<cipher_len;) {
- u_int16_t *id = (u_int16_t*)&packet->payload[cipher_offset+i];
+/* **************************************** */
+static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
+ struct ndpi_packet_struct *packet = &flow->packet;
+ u_int8_t handshake_type;
+ u_int32_t handshake_len;
+ u_int16_t p_len;
+ const u_int8_t *p;
+
#ifdef DEBUG_TLS
- printf("Client SSL [cipher suite: %u/0x%04X] [%d/%u]\n", ntohs(*id), ntohs(*id), i, cipher_len);
+ printf("[TLS] %s()\n", __FUNCTION__);
#endif
- if((*id == 0) || (packet->payload[cipher_offset+i] != packet->payload[cipher_offset+i+1])) {
- /*
- Skip GREASE [https://tools.ietf.org/id/draft-ietf-tls-grease-01.html]
- https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967
- */
-
- if(ja3.num_cipher < MAX_NUM_JA3)
- ja3.cipher[ja3.num_cipher++] = ntohs(*id);
- else {
- invalid_ja3 = 1;
+
+ /* Consider only specific SSL packets (handshake) */
+ if((packet->payload_packet_len < 17)
+ || (packet->payload[0] != 0x16)
+ || (packet->payload[1] != 0xfe) /* We ignore old DTLS versions */
+ || ((packet->payload[2] != 0xff) && (packet->payload[2] != 0xfd))
+ || ((ntohs(*((u_int16_t*)&packet->payload[11]))+13) != packet->payload_packet_len)
+ ) {
+ no_dtls:
+
#ifdef DEBUG_TLS
- printf("Client SSL Invalid cipher %u\n", ja3.num_cipher);
+ printf("[TLS] No DTLS found\n");
#endif
- }
- }
+
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return(0); /* Giveup */
+ }
- i += 2;
- }
- } else {
- invalid_ja3 = 1;
-#ifdef DEBUG_TLS
- printf("Client SSL Invalid len %u vs %u\n", (cipher_offset+cipher_len), total_len);
-#endif
- }
+ handshake_type = packet->payload[13];
+ handshake_len = (packet->payload[14] << 16) + (packet->payload[15] << 8) + packet->payload[16];
- offset = base_offset + session_id_len + cipher_len + 2;
+ if((handshake_len+25) != packet->payload_packet_len)
+ goto no_dtls;
+
+ /* Overwriting packet payload */
+ p = packet->payload, p_len = packet->payload_packet_len; /* Backup */
+ packet->payload = &packet->payload[13], packet->payload_packet_len -= 13;
- flow->l4.tcp.tls_seen_client_cert = 1;
+ processTLSBlock(ndpi_struct, flow);
+
+ packet->payload = p, packet->payload_packet_len = p_len; /* Restore */
+
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
+ return(1); /* Keep working */
+}
- if(offset < total_len) {
- u_int16_t compression_len;
- u_int16_t extensions_len;
+/* **************************************** */
- offset += packet->tcp ? 1 : 2;
- compression_len = packet->payload[offset];
- offset++;
+static void tlsInitExtraPacketProcessing(struct ndpi_flow_struct *flow) {
+ flow->check_extra_packets = 1;
-#ifdef DEBUG_TLS
- printf("Client SSL [compression_len: %u]\n", compression_len);
+ /* At most 12 packets should almost always be enough to find the server certificate if it's there */
+ flow->max_extra_packets_to_check = 12;
+ flow->extra_packets_func = (flow->packet.udp != NULL) ? ndpi_search_tls_udp : ndpi_search_tls_tcp;
+}
+
+/* **************************************** */
+
+static void ndpi_int_tls_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow, u_int32_t protocol) {
+#if DEBUG_TLS
+ printf("[TLS] %s()\n", __FUNCTION__);
#endif
- // offset += compression_len + 3;
- offset += compression_len;
+ if((flow->detected_protocol_stack[0] == protocol)
+ || (flow->detected_protocol_stack[1] == protocol)) {
+ if(!flow->check_extra_packets)
+ tlsInitExtraPacketProcessing(flow);
+ return;
+ }
+
+ if(protocol != NDPI_PROTOCOL_TLS)
+ ;
+ else
+ protocol = ndpi_tls_refine_master_protocol(ndpi_struct, flow, protocol);
- if(offset < total_len) {
- extensions_len = ntohs(*((u_int16_t*)&packet->payload[offset]));
- offset += 2;
+ ndpi_set_detected_protocol(ndpi_struct, flow, protocol, NDPI_PROTOCOL_TLS);
+ tlsInitExtraPacketProcessing(flow);
+}
-#ifdef DEBUG_TLS
- printf("Client SSL [extensions_len: %u]\n", extensions_len);
-#endif
+/* **************************************** */
- if((extensions_len+offset) <= total_len) {
- /* Move to the first extension
- Type is u_int to avoid possible overflow on extension_len addition */
- u_int extension_offset = 0;
- u_int32_t j;
+/* https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967 */
- while(extension_offset < extensions_len) {
- u_int16_t extension_id, extension_len, extn_off = offset+extension_offset;
+#define JA3_STR_LEN 1024
+#define MAX_NUM_JA3 128
- extension_id = ntohs(*((u_int16_t*)&packet->payload[offset+extension_offset]));
- extension_offset += 2;
+struct ja3_info {
+ u_int16_t tls_handshake_version;
+ u_int16_t num_cipher, cipher[MAX_NUM_JA3];
+ u_int16_t num_tls_extension, tls_extension[MAX_NUM_JA3];
+ u_int16_t num_elliptic_curve, elliptic_curve[MAX_NUM_JA3];
+ u_int8_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA3];
+};
- extension_len = ntohs(*((u_int16_t*)&packet->payload[offset+extension_offset]));
- extension_offset += 2;
+/* **************************************** */
+int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
+ struct ndpi_packet_struct *packet = &flow->packet;
+ struct ja3_info ja3;
+ u_int8_t invalid_ja3 = 0;
+ u_int16_t tls_version, ja3_str_len;
+ char ja3_str[JA3_STR_LEN];
+ ndpi_MD5_CTX ctx;
+ u_char md5_hash[16];
+ int i;
+ u_int16_t total_len;
+ u_int8_t handshake_type;
+ char buffer[64] = { '\0' };
+
#ifdef DEBUG_TLS
- printf("Client SSL [extension_id: %u][extension_len: %u]\n", extension_id, extension_len);
+ printf("SSL %s() called\n", __FUNCTION__);
#endif
- if((extension_id == 0) || (packet->payload[extn_off] != packet->payload[extn_off+1])) {
- /* Skip GREASE */
+ memset(&ja3, 0, sizeof(ja3));
- if(ja3.num_tls_extension < MAX_NUM_JA3)
- ja3.tls_extension[ja3.num_tls_extension++] = extension_id;
- else {
- invalid_ja3 = 1;
+ handshake_type = packet->payload[0];
+ total_len = (packet->payload[1] << 16) + (packet->payload[2] << 8) + packet->payload[3];
+
+ if(total_len > packet->payload_packet_len)
+ return(0); /* Not found */
+
+ total_len = packet->payload_packet_len;
+
+ /* At least "magic" 3 bytes, null for string end, otherwise no need to waste cpu cycles */
+ if(total_len > 4) {
+ u_int16_t base_offset = packet->tcp ? 38 : 46;
+ u_int16_t version_offset = packet->tcp ? 4 : 12;
+ u_int16_t offset = 38, extension_len, j;
+ u_int8_t session_id_len = packet->tcp ? packet->payload[offset] : packet->payload[46];
+
#ifdef DEBUG_TLS
- printf("Client SSL Invalid extensions %u\n", ja3.num_tls_extension);
+ printf("SSL [len: %u][handshake_type: %02X]\n", packet->payload_packet_len, handshake_type);
#endif
- }
- }
-
- if(extension_id == 0 /* server name */) {
- u_int16_t len;
-
- len = (packet->payload[offset+extension_offset+3] << 8) + packet->payload[offset+extension_offset+4];
- len = (u_int)ndpi_min(len, buffer_len-1);
-
- if((offset+extension_offset+5+len) < packet->payload_packet_len) {
- strncpy(buffer, (char*)&packet->payload[offset+extension_offset+5], len);
- buffer[len] = '\0';
-
- stripCertificateTrailer(buffer, buffer_len);
-
- if(!ndpi_struct->disable_metadata_export) {
- snprintf(flow->protos.stun_ssl.ssl.client_certificate,
- sizeof(flow->protos.stun_ssl.ssl.client_certificate), "%s", buffer);
- }
- }
- } else if(extension_id == 10 /* supported groups */) {
- u_int16_t s_offset = offset+extension_offset + 2;
+ tls_version = ntohs(*((u_int16_t*)&packet->payload[version_offset]));
+ flow->protos.stun_ssl.ssl.ssl_version = ja3.tls_handshake_version = tls_version;
+
+ if(handshake_type == 0x02 /* Server Hello */) {
+ int i, rc;
+
#ifdef DEBUG_TLS
- printf("Client SSL [EllipticCurveGroups: len=%u]\n", extension_len);
+ printf("SSL Server Hello [version: 0x%04X]\n", tls_version);
#endif
- if((s_offset+extension_len-2) <= total_len) {
- for(i=0; i<extension_len-2;) {
- u_int16_t s_group = ntohs(*((u_int16_t*)&packet->payload[s_offset+i]));
+ /*
+ The server hello decides about the SSL version of this flow
+ https://networkengineering.stackexchange.com/questions/55752/why-does-wireshark-show-version-tls-1-2-here-instead-of-tls-1-3
+ */
+ if(packet->udp)
+ offset += 1;
+ else {
+ if(tls_version < 0x7F15 /* TLS 1.3 lacks of session id */)
+ offset += session_id_len+1;
+ }
-#ifdef DEBUG_TLS
- printf("Client SSL [EllipticCurve: %u/0x%04X]\n", s_group, s_group);
-#endif
- if((s_group == 0) || (packet->payload[s_offset+i] != packet->payload[s_offset+i+1])) {
- /* Skip GREASE */
- if(ja3.num_elliptic_curve < MAX_NUM_JA3)
- ja3.elliptic_curve[ja3.num_elliptic_curve++] = s_group;
- else {
- invalid_ja3 = 1;
-#ifdef DEBUG_TLS
- printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve);
-#endif
- }
- }
+ ja3.num_cipher = 1, ja3.cipher[0] = ntohs(*((u_int16_t*)&packet->payload[offset]));
+ flow->protos.stun_ssl.ssl.server_unsafe_cipher = ndpi_is_safe_ssl_cipher(ja3.cipher[0]);
+ flow->protos.stun_ssl.ssl.server_cipher = ja3.cipher[0];
- i += 2;
- }
- } else {
- invalid_ja3 = 1;
#ifdef DEBUG_TLS
- printf("Client SSL Invalid len %u vs %u\n", (s_offset+extension_len-1), total_len);
+ printf("TLS [server][session_id_len: %u][cipher: %04X]\n", session_id_len, ja3.cipher[0]);
#endif
- }
- } else if(extension_id == 11 /* ec_point_formats groups */) {
- u_int16_t s_offset = offset+extension_offset + 1;
-#ifdef DEBUG_TLS
- printf("Client SSL [EllipticCurveFormat: len=%u]\n", extension_len);
-#endif
- if((s_offset+extension_len) < total_len) {
- for(i=0; i<extension_len-1;i++) {
- u_int8_t s_group = packet->payload[s_offset+i];
+ offset += 2 + 1;
-#ifdef DEBUG_TLS
- printf("Client SSL [EllipticCurveFormat: %u]\n", s_group);
-#endif
+ if((offset + 1) < packet->payload_packet_len) /* +1 because we are goint to read 2 bytes */
+ extension_len = ntohs(*((u_int16_t*)&packet->payload[offset]));
+ else
+ extension_len = 0;
- if(ja3.num_elliptic_curve_point_format < MAX_NUM_JA3)
- ja3.elliptic_curve_point_format[ja3.num_elliptic_curve_point_format++] = s_group;
- else {
- invalid_ja3 = 1;
#ifdef DEBUG_TLS
- printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve_point_format);
+ printf("TLS [server][extension_len: %u]\n", extension_len);
#endif
- }
- }
- } else {
- invalid_ja3 = 1;
-#ifdef DEBUG_TLS
- printf("Client SSL Invalid len %u vs %u\n", s_offset+extension_len, total_len);
-#endif
- }
- } else if(extension_id == 43 /* supported versions */) {
- u_int8_t version_len = packet->payload[offset+4];
-
- if(version_len == (extension_len-1)) {
-#ifdef DEBUG_TLS
- u_int8_t j;
-
- for(j=0; j<version_len; j += 2) {
- u_int16_t tls_version = ntohs(*((u_int16_t*)&packet->payload[offset+5+j]));
-
- printf("Client SSL [TLS version: 0x%04X]\n", tls_version);
- }
-#endif
- }
- }
+ offset += 2;
- extension_offset += extension_len;
+ for(i=0; i<extension_len; ) {
+ u_int16_t extension_id, extension_len;
-#ifdef DEBUG_TLS
- printf("Client SSL [extension_offset/len: %u/%u]\n", extension_offset, extension_len);
-#endif
- } /* while */
-
- if(!invalid_ja3) {
- int rc;
-
- compute_ja3c:
- ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.tls_handshake_version);
-
- for(i=0; i<ja3.num_cipher; i++) {
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
- (i > 0) ? "-" : "", ja3.cipher[i]);
- if(rc > 0) ja3_str_len += rc; else break;
- }
+ if(offset >= (packet->payload_packet_len+4)) break;
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
- if(rc > 0) ja3_str_len += rc;
-
- /* ********** */
+ extension_id = ntohs(*((u_int16_t*)&packet->payload[offset]));
+ extension_len = ntohs(*((u_int16_t*)&packet->payload[offset+2]));
- for(i=0; i<ja3.num_tls_extension; i++) {
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
- (i > 0) ? "-" : "", ja3.tls_extension[i]);
- if(rc > 0) ja3_str_len += rc; else break;
- }
-
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
- if(rc > 0) ja3_str_len += rc;
-
- /* ********** */
-
- for(i=0; i<ja3.num_elliptic_curve; i++) {
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
- (i > 0) ? "-" : "", ja3.elliptic_curve[i]);
- if(rc > 0) ja3_str_len += rc; else break;
- }
-
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
- if(rc > 0) ja3_str_len += rc;
-
- for(i=0; i<ja3.num_elliptic_curve_point_format; i++) {
- rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
- (i > 0) ? "-" : "", ja3.elliptic_curve_point_format[i]);
- if(rc > 0) ja3_str_len += rc; else break;
- }
+ if(ja3.num_tls_extension < MAX_NUM_JA3)
+ ja3.tls_extension[ja3.num_tls_extension++] = extension_id;
#ifdef DEBUG_TLS
- printf("[JA3] Client: %s \n", ja3_str);
+ printf("TLS [server][extension_id: %u/0x%04X][len: %u]\n",
+ extension_id, extension_id, extension_len);
#endif
- ndpi_MD5Init(&ctx);
- ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
- ndpi_MD5Final(md5_hash, &ctx);
+ if(extension_id == 43 /* supported versions */) {
+ if(extension_len >= 2) {
+ u_int16_t tls_version = ntohs(*((u_int16_t*)&packet->payload[offset+4]));
- for(i=0, j=0; i<16; i++) {
- rc = snprintf(&flow->protos.stun_ssl.ssl.ja3_client[j],
- sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x",
- md5_hash[i]);
- if(rc > 0) j += rc; else break;
- }
#ifdef DEBUG_TLS
- printf("[JA3] Client: %s \n", flow->protos.stun_ssl.ssl.ja3_client);
+ printf("TLS [server] [TLS version: 0x%04X]\n", tls_version);
#endif
- }
- return(2 /* Client Certificate */);
- }
- } else if(offset == total_len) {
- /* SSL does not have extensions etc */
- goto compute_ja3c;
- }
- }
+ flow->protos.stun_ssl.ssl.ssl_version = tls_version;
}
}
+
+ i += 4 + extension_len, offset += 4 + extension_len;
}
- }
- }
- return(0); /* Not found */
-}
+ ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.tls_handshake_version);
-/* **************************************** */
+ for(i=0; i<ja3.num_cipher; i++) {
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.cipher[i]);
-/* See https://blog.catchpoint.com/2017/05/12/dissecting-tls-using-wireshark/ */
-int getSSCertificateFingerprint(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow) {
- struct ndpi_packet_struct *packet = &flow->packet;
- u_int8_t multiple_messages;
+ if(rc <= 0) break; else ja3_str_len += rc;
+ }
- if(flow->l4.tcp.tls_srv_cert_fingerprint_processed)
- return(0); /* We're good */
-
-#ifdef DEBUG_TLS
- printf("=>> [TLS] %s() [tls_record_offset=%d][payload_packet_len=%u][direction: %u][%02X %02X %02X...]\n",
- __FUNCTION__, flow->l4.tcp.tls_record_offset, packet->payload_packet_len,
- packet->packet_direction,
- packet->payload[0], packet->payload[1], packet->payload[2]);
-#endif
-
- if((packet->packet_direction == 0) /* Client -> Server */
- || (packet->payload_packet_len == 0))
- return(1); /* More packets please */
- else if(flow->l4.tcp.tls_srv_cert_fingerprint_processed)
- return(0); /* We're good */
-
- if(packet->payload_packet_len <= flow->l4.tcp.tls_record_offset) {
- /* Avoid invalid memory accesses */
- return(1);
- }
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
+ if(rc > 0) ja3_str_len += rc;
- if(flow->l4.tcp.tls_fingerprint_len > 0) {
- unsigned int avail = packet->payload_packet_len - flow->l4.tcp.tls_record_offset;
+ /* ********** */
- if(avail > flow->l4.tcp.tls_fingerprint_len)
- avail = flow->l4.tcp.tls_fingerprint_len;
+ for(i=0; i<ja3.num_tls_extension; i++) {
+ int rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.tls_extension[i]);
-#ifdef DEBUG_TLS
- printf("=>> [TLS] Certificate record [%02X %02X %02X...][missing: %u][offset: %u][avail: %u] (B)\n",
- packet->payload[flow->l4.tcp.tls_record_offset],
- packet->payload[flow->l4.tcp.tls_record_offset+1],
- packet->payload[flow->l4.tcp.tls_record_offset+2],
- flow->l4.tcp.tls_fingerprint_len, flow->l4.tcp.tls_record_offset, avail
- );
-#endif
-
-#ifdef DEBUG_CERTIFICATE_HASH
- for(i=0;i<avail;i++)
- printf("%02X ", packet->payload[flow->l4.tcp.tls_record_offset+i]);
- printf("\n");
-#endif
-
- SHA1Update(flow->l4.tcp.tls_srv_cert_fingerprint_ctx,
- &packet->payload[flow->l4.tcp.tls_record_offset],
- avail);
-
- flow->l4.tcp.tls_fingerprint_len -= avail;
-
- if(flow->l4.tcp.tls_fingerprint_len == 0) {
- SHA1Final(flow->l4.tcp.tls_sha1_certificate_fingerprint, flow->l4.tcp.tls_srv_cert_fingerprint_ctx);
+ if(rc <= 0) break; else ja3_str_len += rc;
+ }
#ifdef DEBUG_TLS
- {
- int i;
-
- printf("=>> [TLS] SHA-1: ");
- for(i=0;i<20;i++)
- printf("%s%02X", (i > 0) ? ":" : "", flow->l4.tcp.tls_sha1_certificate_fingerprint[i]);
- printf("\n");
- }
+ printf("TLS [server] %s\n", ja3_str);
#endif
-
- flow->l4.tcp.tls_srv_cert_fingerprint_processed = 1;
- return(0); /* We're good */
- } else {
- flow->l4.tcp.tls_record_offset = 0;
+
#ifdef DEBUG_TLS
- printf("=>> [TLS] Certificate record: still missing %u bytes\n", flow->l4.tcp.tls_fingerprint_len);
+ printf("[JA3] Server: %s \n", ja3_str);
#endif
- return(1); /* More packets please */
- }
- }
- if(packet->payload[flow->l4.tcp.tls_record_offset] == 0x15 /* Alert */) {
- u_int len = ntohs(*(u_int16_t*)&packet->payload[flow->l4.tcp.tls_record_offset+3]) + 5 /* SSL header len */;
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
+ ndpi_MD5Final(md5_hash, &ctx);
- if(len < 10 /* Sanity check */) {
- if((flow->l4.tcp.tls_record_offset+len) < packet->payload_packet_len)
- flow->l4.tcp.tls_record_offset += len;
- } else
- goto invalid_len;
- }
-
- multiple_messages = (packet->payload[flow->l4.tcp.tls_record_offset] == 0x16 /* Handshake */) ? 0 : 1;
+ for(i=0, j=0; i<16; i++) {
+ int rc = snprintf(&flow->protos.stun_ssl.ssl.ja3_server[j],
+ sizeof(flow->protos.stun_ssl.ssl.ja3_server)-j, "%02x", md5_hash[i]);
+ if(rc <= 0) break; else j += rc;
+ }
#ifdef DEBUG_TLS
- printf("=>> [TLS] [multiple_messages: %d]\n", multiple_messages);
-#endif
-
- if((!multiple_messages) && (packet->payload[flow->l4.tcp.tls_record_offset] != 0x16 /* Handshake */))
- return(1);
- else if(((!multiple_messages) && (packet->payload[flow->l4.tcp.tls_record_offset+5] == 0xb) /* Certificate */)
- || (packet->payload[flow->l4.tcp.tls_record_offset] == 0xb) /* Certificate */) {
- /* TODO: Do not take into account all certificates but only the first one */
+ printf("[JA3] Server: %s \n", flow->protos.stun_ssl.ssl.ja3_server);
+#endif
+ } else if(handshake_type == 0x01 /* Client Hello */) {
+ u_int16_t cipher_len, cipher_offset;
+
+ if(packet->tcp) {
+ cipher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8);
+ cipher_offset = base_offset + session_id_len + 3;
+ } else {
+ cipher_len = ntohs(*((u_int16_t*)&packet->payload[base_offset+2]));
+ cipher_offset = base_offset+4;
+ }
+
#ifdef DEBUG_TLS
- printf("=>> [TLS] Certificate found\n");
+ printf("Client SSL [client cipher_len: %u][tls_version: 0x%04X]\n", cipher_len, tls_version);
#endif
- if(flow->l4.tcp.tls_srv_cert_fingerprint_ctx == NULL)
- flow->l4.tcp.tls_srv_cert_fingerprint_ctx = (void*)ndpi_malloc(sizeof(SHA1_CTX));
- else {
-#ifdef DEBUG_TLS
- printf("[TLS] Internal error: double allocation\n:");
-#endif
- }
-
- if(flow->l4.tcp.tls_srv_cert_fingerprint_ctx) {
- SHA1Init(flow->l4.tcp.tls_srv_cert_fingerprint_ctx);
- flow->l4.tcp.tls_srv_cert_fingerprint_found = 1;
- flow->l4.tcp.tls_record_offset += (!multiple_messages) ? 13 : 8;
- flow->l4.tcp.tls_fingerprint_len = ntohs(*(u_int16_t*)&packet->payload[flow->l4.tcp.tls_record_offset]);
- flow->l4.tcp.tls_record_offset = flow->l4.tcp.tls_record_offset+2;
+ if((cipher_offset+cipher_len) <= total_len) {
+ for(i=0; i<cipher_len;) {
+ u_int16_t *id = (u_int16_t*)&packet->payload[cipher_offset+i];
+
#ifdef DEBUG_TLS
- printf("=>> [TLS] Certificate [total certificate len: %u][certificate initial offset: %u]\n",
- flow->l4.tcp.tls_fingerprint_len, flow->l4.tcp.tls_record_offset);
+ printf("Client SSL [cipher suite: %u/0x%04X] [%d/%u]\n", ntohs(*id), ntohs(*id), i, cipher_len);
#endif
- return(getSSCertificateFingerprint(ndpi_struct, flow));
- } else
- return(0); /* That's all */
- } else if(flow->l4.tcp.tls_seen_certificate)
- return(0); /* That's all */
- else if(packet->payload_packet_len > flow->l4.tcp.tls_record_offset+7+1/* +1 because we are going to read 2 bytes */) {
- /* This is a handshake but not a certificate record */
- u_int16_t len = ntohs(*(u_int16_t*)&packet->payload[flow->l4.tcp.tls_record_offset+7]);
-
+ if((*id == 0) || (packet->payload[cipher_offset+i] != packet->payload[cipher_offset+i+1])) {
+ /*
+ Skip GREASE [https://tools.ietf.org/id/draft-ietf-tls-grease-01.html]
+ https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967
+ */
+
+ if(ja3.num_cipher < MAX_NUM_JA3)
+ ja3.cipher[ja3.num_cipher++] = ntohs(*id);
+ else {
+ invalid_ja3 = 1;
#ifdef DEBUG_TLS
- printf("=>> [TLS] Found record %02X [len: %u]\n",
- packet->payload[flow->l4.tcp.tls_record_offset+5], len);
+ printf("Client SSL Invalid cipher %u\n", ja3.num_cipher);
#endif
+ }
+ }
- if(len > 4096) {
- invalid_len:
- /* This looks an invalid len: we giveup */
- flow->l4.tcp.tls_record_offset = 0, flow->l4.tcp.tls_srv_cert_fingerprint_processed = 1;
+ i += 2;
+ }
+ } else {
+ invalid_ja3 = 1;
#ifdef DEBUG_TLS
- printf("=>> [TLS] Invalid fingerprint processing %u <-> %u\n",
- ntohs(packet->tcp->source), ntohs(packet->tcp->dest));
+ printf("Client SSL Invalid len %u vs %u\n", (cipher_offset+cipher_len), total_len);
#endif
- return(0);
- } else {
- flow->l4.tcp.tls_record_offset += len + 9;
-
- if(flow->l4.tcp.tls_record_offset < packet->payload_packet_len)
- return(getSSCertificateFingerprint(ndpi_struct, flow));
- else {
- flow->l4.tcp.tls_record_offset -= packet->payload_packet_len;
}
- }
- }
-
- flow->extra_packets_func = NULL; /* We're good now */
- return(1);
-}
-/* **************************************** */
+ offset = base_offset + session_id_len + cipher_len + 2;
-/* See https://blog.catchpoint.com/2017/05/12/dissecting-tls-using-wireshark/ */
-void getSSLorganization(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow,
- char *buffer, int buffer_len) {
- struct ndpi_packet_struct *packet = &flow->packet;
- u_int16_t total_len;
- u_int8_t handshake_protocol;
-
- if(packet->payload[0] != 0x16 /* Handshake */)
- return;
+ if(offset < total_len) {
+ u_int16_t compression_len;
+ u_int16_t extensions_len;
- total_len = (packet->payload[3] << 8) + packet->payload[4] + 5 /* SSL Header */;
- handshake_protocol = packet->payload[5]; /* handshake protocol a bit misleading, it is message type according TLS specs */
-
- if((handshake_protocol != 0x02)
- && (handshake_protocol != 0xb) /* Server Hello and Certificate message types are interesting for us */)
- return;
+ offset += packet->tcp ? 1 : 2;
+ compression_len = packet->payload[offset];
+ offset++;
#ifdef DEBUG_TLS
- printf("=>> [TLS] Certificate [total_len: %u/%u]\n", ntohs(*(u_int16_t*)&packet->payload[3]), total_len);
+ printf("Client SSL [compression_len: %u]\n", compression_len);
#endif
-
- /* Truncate total len, search at least in incomplete packet */
- if(total_len > packet->payload_packet_len)
- total_len = packet->payload_packet_len;
- memset(buffer, 0, buffer_len);
+ // offset += compression_len + 3;
+ offset += compression_len;
- /* Check after handshake protocol header (5 bytes) and message header (4 bytes) */
- u_int num_found = 0;
- u_int i, j;
- for(i = 9; i < packet->payload_packet_len-4; i++) {
- /* Organization OID: 2.5.4.10 */
- if((packet->payload[i] == 0x55) && (packet->payload[i+1] == 0x04) && (packet->payload[i+2] == 0x0a)) {
- u_int8_t server_len = packet->payload[i+4];
+ if(offset < total_len) {
+ extensions_len = ntohs(*((u_int16_t*)&packet->payload[offset]));
+ offset += 2;
- num_found++;
- /* what we want is subject certificate, so we bypass the issuer certificate */
- if(num_found != 2) continue;
+#ifdef DEBUG_TLS
+ printf("Client SSL [extensions_len: %u]\n", extensions_len);
+#endif
- // packet is truncated... further inspection is not needed
- if(i+4+server_len >= packet->payload_packet_len) {
- break;
- }
+ if((extensions_len+offset) <= total_len) {
+ /* Move to the first extension
+ Type is u_int to avoid possible overflow on extension_len addition */
+ u_int extension_offset = 0;
+ u_int32_t j;
- char *server_org = (char*)&packet->payload[i+5];
+ while(extension_offset < extensions_len) {
+ u_int16_t extension_id, extension_len, extn_off = offset+extension_offset;
- u_int len = (u_int)ndpi_min(server_len, buffer_len-1);
- strncpy(buffer, server_org, len);
- buffer[len] = '\0';
+ extension_id = ntohs(*((u_int16_t*)&packet->payload[offset+extension_offset]));
+ extension_offset += 2;
- // check if organization string are all printable
- u_int8_t is_printable = 1;
- for (j = 0; j < len; j++) {
- if(!ndpi_isprint(buffer[j])) {
- is_printable = 0;
- break;
- }
- }
+ extension_len = ntohs(*((u_int16_t*)&packet->payload[offset+extension_offset]));
+ extension_offset += 2;
- if(is_printable == 1) {
- snprintf(flow->protos.stun_ssl.ssl.server_organization,
- sizeof(flow->protos.stun_ssl.ssl.server_organization), "%s", buffer);
#ifdef DEBUG_TLS
- printf("Certificate organization: %s\n", flow->protos.stun_ssl.ssl.server_organization);
+ printf("Client SSL [extension_id: %u][extension_len: %u]\n", extension_id, extension_len);
#endif
- }
- } else if((packet->payload[i] == 0x30) && (packet->payload[i+1] == 0x1e) && (packet->payload[i+2] == 0x17)) {
- u_int8_t len = packet->payload[i+3];
- u_int offset = i+4;
- if((offset+len) < packet->payload_packet_len) {
- char utcDate[32];
+ if((extension_id == 0) || (packet->payload[extn_off] != packet->payload[extn_off+1])) {
+ /* Skip GREASE */
+ if(ja3.num_tls_extension < MAX_NUM_JA3)
+ ja3.tls_extension[ja3.num_tls_extension++] = extension_id;
+ else {
+ invalid_ja3 = 1;
#ifdef DEBUG_TLS
- printf("[CERTIFICATE] notBefore [len: %u][", len);
- for(j=0; j<len; j++) printf("%c", packet->payload[i+4+j]);
- printf("]\n");
+ printf("Client SSL Invalid extensions %u\n", ja3.num_tls_extension);
#endif
+ }
+ }
- if(len < (sizeof(utcDate)-1)) {
- struct tm utc;
- utc.tm_isdst = -1; /* Not set by strptime */
-
- strncpy(utcDate, (const char*)&packet->payload[i+4], len);
- utcDate[len] = '\0';
+ if(extension_id == 0 /* server name */) {
+ u_int16_t len;
- /* 141021000000Z */
- if(strptime(utcDate, "%y%m%d%H%M%SZ", &utc) != NULL) {
- flow->protos.stun_ssl.ssl.notBefore = timegm(&utc);
#ifdef DEBUG_TLS
- printf("[CERTIFICATE] notBefore %u [%s]\n",
- flow->protos.stun_ssl.ssl.notBefore, utcDate);
+ printf("[TLS] Extensions: found server name\n");
#endif
- }
- }
- offset += len;
+ len = (packet->payload[offset+extension_offset+3] << 8) + packet->payload[offset+extension_offset+4];
+ len = (u_int)ndpi_min(len, sizeof(buffer)-1);
- if((offset+1) < packet->payload_packet_len) {
- len = packet->payload[offset+1];
+ if((offset+extension_offset+5+len) < packet->payload_packet_len) {
+ strncpy(buffer, (char*)&packet->payload[offset+extension_offset+5], len);
+ buffer[len] = '\0';
- offset += 2;
+ cleanupServerName(buffer, sizeof(buffer));
- if((offset+len) < packet->payload_packet_len) {
+ snprintf(flow->protos.stun_ssl.ssl.client_requested_server_name,
+ sizeof(flow->protos.stun_ssl.ssl.client_requested_server_name),
+ "%s", buffer);
+
+ if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS, buffer, strlen(buffer)))
+ flow->l4.tcp.tls.subprotocol_detected = 1;
+ } else {
#ifdef DEBUG_TLS
- printf("[CERTIFICATE] notAfter [len: %u][", len);
- for(j=0; j<len; j++) printf("%c", packet->payload[offset+j]);
- printf("]\n");
+ printf("[TLS] Extensions server len too short: %u vs %u\n",
+ offset+extension_offset+5+len,
+ packet->payload_packet_len);
#endif
+ }
+ } else if(extension_id == 10 /* supported groups */) {
+ u_int16_t s_offset = offset+extension_offset + 2;
- if(len < (sizeof(utcDate)-1)) {
- struct tm utc;
- utc.tm_isdst = -1; /* Not set by strptime */
-
- strncpy(utcDate, (const char*)&packet->payload[offset], len);
- utcDate[len] = '\0';
-
- /* 141021000000Z */
- if(strptime(utcDate, "%y%m%d%H%M%SZ", &utc) != NULL) {
- flow->protos.stun_ssl.ssl.notAfter = timegm(&utc);
#ifdef DEBUG_TLS
- printf("[CERTIFICATE] notAfter %u [%s]\n",
- flow->protos.stun_ssl.ssl.notAfter, utcDate);
+ printf("Client SSL [EllipticCurveGroups: len=%u]\n", extension_len);
#endif
- }
- }
- }
- }
- }
- }
- }
-}
-
-/* **************************************** */
-
-int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow) {
- struct ndpi_packet_struct *packet = &flow->packet;
- int rc = 1;
-
- if(packet->tcp) {
- if(!flow->l4.tcp.tls_srv_cert_fingerprint_processed)
- getSSCertificateFingerprint(ndpi_struct, flow);
- }
-
-#if 1
- /* 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 = getTLScertificate(ndpi_struct, flow, certificate, sizeof(certificate));
- packet->tls_certificate_num_checks++;
- if(rc > 0) {
- char organization[64];
+ if((s_offset+extension_len-2) <= total_len) {
+ for(i=0; i<extension_len-2;) {
+ u_int16_t s_group = ntohs(*((u_int16_t*)&packet->payload[s_offset+i]));
- // try fetch server organization once server certificate is found
- organization[0] = '\0';
- getSSLorganization(ndpi_struct, flow, organization, sizeof(organization));
-
- packet->tls_certificate_detected++;
-#if 0
- if((flow->l4.tcp.tls_seen_server_cert == 1)
- && (flow->protos.stun_ssl.ssl.server_certificate[0] != '\0'))
- /* 0 means we've done processing extra packets (since we found what we wanted) */
- return 0;
+#ifdef DEBUG_TLS
+ printf("Client SSL [EllipticCurve: %u/0x%04X]\n", s_group, s_group);
#endif
- }
-
- if(flow->l4.tcp.tls_record_offset == 0) {
- /* Client hello, Server Hello, and certificate packets probably all checked in this case */
- if(((packet->tls_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 */
- && flow->l4.tcp.tls_srv_cert_fingerprint_processed)
- /* || (flow->protos.stun_ssl.ssl.ja3_server[0] != '\0') */
- ) {
- /* We're done processing extra packets since we've probably checked all possible cert packets */
- return(rc);
- }
- }
- }
+ if((s_group == 0) || (packet->payload[s_offset+i] != packet->payload[s_offset+i+1])) {
+ /* Skip GREASE */
+ if(ja3.num_elliptic_curve < MAX_NUM_JA3)
+ ja3.elliptic_curve[ja3.num_elliptic_curve++] = s_group;
+ else {
+ invalid_ja3 = 1;
+#ifdef DEBUG_TLS
+ printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve);
#endif
-
- /* 1 means keep looking for more packets */
- if(!flow->l4.tcp.tls_srv_cert_fingerprint_processed) rc = 1;
- return(rc);
-}
-
-/* **************************************** */
-
-int tlsDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow,
- u_int8_t skip_cert_processing) {
- struct ndpi_packet_struct *packet = &flow->packet;
-
- if((!skip_cert_processing) && packet->tcp) {
- if(!flow->l4.tcp.tls_srv_cert_fingerprint_processed)
- getSSCertificateFingerprint(ndpi_struct, flow);
- }
-
- if((packet->payload_packet_len > 9)
- && (packet->payload[0] == 0x16 /* consider only specific SSL packets (handshake) */)) {
- if((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN)
- || (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS)) {
- char certificate[64];
- int rc;
-
- certificate[0] = '\0';
- rc = getTLScertificate(ndpi_struct, flow, certificate, sizeof(certificate));
- packet->tls_certificate_num_checks++;
+ }
+ }
- if(rc > 0) {
- packet->tls_certificate_detected++;
+ i += 2;
+ }
+ } else {
+ invalid_ja3 = 1;
#ifdef DEBUG_TLS
- NDPI_LOG_DBG2(ndpi_struct, "***** [SSL] %s\n", certificate);
+ printf("Client SSL Invalid len %u vs %u\n", (s_offset+extension_len-1), total_len);
#endif
- ndpi_protocol_match_result ret_match;
- u_int16_t subproto;
-
- if(certificate[0] == '\0')
- subproto = NDPI_PROTOCOL_UNKNOWN;
- else
- subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, certificate,
- strlen(certificate),
- &ret_match,
- NDPI_PROTOCOL_TLS);
-
- 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->l4.tcp.tls_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0'))
- && ((flow->l4.tcp.tls_seen_server_cert != 1) && (flow->protos.stun_ssl.ssl.server_certificate[0] == '\0'))) {
- sslInitExtraPacketProcessing(flow);
- }
-
- ndpi_set_detected_protocol(ndpi_struct, flow, subproto,
- ndpi_tls_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS));
- return(rc);
- }
-
- if(ndpi_is_tls_tor(ndpi_struct, flow, certificate) != 0)
- return(rc);
- }
+ }
+ } else if(extension_id == 11 /* ec_point_formats groups */) {
+ u_int16_t s_offset = offset+extension_offset + 1;
#ifdef DEBUG_TLS
- printf("[TLS] %s() [tls_certificate_num_checks: %u][tls_srv_cert_fingerprint_processed: %u][tls_certificate_detected: %u][%u/%u]",
- __FUNCTION__, packet->tls_certificate_num_checks, flow->l4.tcp.tls_srv_cert_fingerprint_processed,
- packet->tls_certificate_detected,
- flow->l4.tcp.tls_seen_client_cert,
- flow->l4.tcp.tls_seen_server_cert
- );
+ printf("Client SSL [EllipticCurveFormat: len=%u]\n", extension_len);
#endif
+ if((s_offset+extension_len) < total_len) {
+ for(i=0; i<extension_len-1;i++) {
+ u_int8_t s_group = packet->payload[s_offset+i];
-
- if(((packet->tls_certificate_num_checks >= 1)
-#if 0
- && (flow->l4.tcp.seen_syn /* User || to be tolerant */
- || flow->l4.tcp.seen_syn_ack
- || flow->l4.tcp.seen_ack /* We have seen the 3-way handshake */)
+#ifdef DEBUG_TLS
+ printf("Client SSL [EllipticCurveFormat: %u]\n", s_group);
#endif
- && (flow->l4.tcp.tls_srv_cert_fingerprint_processed
- || flow->l4.tcp.tls_seen_client_cert
- || flow->l4.tcp.tls_seen_server_cert
- || packet->tls_certificate_detected)
- )
- /*
- || ((flow->l4.tcp.tls_seen_certificate == 1)
- && (flow->l4.tcp.tls_seen_server_cert == 1)
- && (flow->protos.stun_ssl.ssl.server_certificate[0] != '\0'))
- */
- /* || ((flow->l4.tcp.tls_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0')) */
- ) {
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
- }
- }
- }
-
- return(0);
-}
-
-/* **************************************** */
-
-static void tls_mark_and_payload_search(struct ndpi_detection_module_struct
- *ndpi_struct, struct ndpi_flow_struct *flow,
- u_int8_t skip_cert_processing) {
- struct ndpi_packet_struct *packet = &flow->packet;
- u_int32_t a;
- u_int32_t end;
+ if(ja3.num_elliptic_curve_point_format < MAX_NUM_JA3)
+ ja3.elliptic_curve_point_format[ja3.num_elliptic_curve_point_format++] = s_group;
+ else {
+ invalid_ja3 = 1;
#ifdef DEBUG_TLS
- printf("[TLS] %s()\n", __FUNCTION__);
+ printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve_point_format);
#endif
-
- if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, NDPI_PROTOCOL_UNENCRYPTED_JABBER) != 0)
- goto check_for_tls_payload;
-
- if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, NDPI_PROTOCOL_OSCAR) != 0)
- goto check_for_tls_payload;
- else
- goto no_check_for_tls_payload;
-
- check_for_tls_payload:
- end = packet->payload_packet_len - 20;
- for (a = 5; a < end; a++) {
-
- if(packet->payload[a] == 't') {
- if(memcmp(&packet->payload[a], "talk.google.com", 15) == 0) {
- if(NDPI_COMPARE_PROTOCOL_TO_BITMASK
- (ndpi_struct->detection_bitmask, NDPI_PROTOCOL_UNENCRYPTED_JABBER) != 0) {
- NDPI_LOG_INFO(ndpi_struct, "found ssl jabber unencrypted\n");
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_UNENCRYPTED_JABBER);
- return;
- }
- }
- }
+ }
+ }
+ } else {
+ invalid_ja3 = 1;
+#ifdef DEBUG_TLS
+ printf("Client SSL Invalid len %u vs %u\n", s_offset+extension_len, total_len);
+#endif
+ }
+ } else if(extension_id == 43 /* supported versions */) {
+ u_int8_t version_len = packet->payload[offset+4];
- if(packet->payload[a] == 'A' || packet->payload[a] == 'k' || packet->payload[a] == 'c'
- || packet->payload[a] == 'h') {
- if(((a + 19) < packet->payload_packet_len && memcmp(&packet->payload[a], "America Online Inc.", 19) == 0)
- // || (end - c > 3 memcmp (&packet->payload[c],"AOL", 3) == 0 )
- // || (end - c > 7 && memcmp (&packet->payload[c], "AOL LLC", 7) == 0)
- || ((a + 15) < packet->payload_packet_len && memcmp(&packet->payload[a], "kdc.uas.aol.com", 15) == 0)
- || ((a + 14) < packet->payload_packet_len && memcmp(&packet->payload[a], "corehc@aol.net", 14) == 0)
- || ((a + 41) < packet->payload_packet_len
- && memcmp(&packet->payload[a], "http://crl.aol.com/AOLMSPKI/aolServerCert", 41) == 0)
- || ((a + 28) < packet->payload_packet_len
- && memcmp(&packet->payload[a], "http://ocsp.web.aol.com/ocsp", 28) == 0)
- || ((a + 32) < packet->payload_packet_len
- && memcmp(&packet->payload[a], "http://pki-info.aol.com/AOLMSPKI", 32) == 0)) {
- NDPI_LOG_INFO(ndpi_struct, "found OSCAR SERVER SSL DETECTED\n");
-
- if(flow->dst != NULL && packet->payload_packet_len > 75) {
- memcpy(flow->dst->oscar_ssl_session_id, &packet->payload[44], 32);
- flow->dst->oscar_ssl_session_id[32] = '\0';
- flow->dst->oscar_last_safe_access_time = packet->tick_timestamp;
- }
+ if(version_len == (extension_len-1)) {
+#ifdef DEBUG_TLS
+ u_int8_t j;
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR);
- return;
- }
- }
+ for(j=0; j<version_len; j += 2) {
+ u_int16_t tls_version = ntohs(*((u_int16_t*)&packet->payload[offset+5+j]));
- if(packet->payload[a] == 'm' || packet->payload[a] == 's') {
- if((a + 21) < packet->payload_packet_len &&
- (memcmp(&packet->payload[a], "my.screenname.aol.com", 21) == 0
- || memcmp(&packet->payload[a], "sns-static.aolcdn.com", 21) == 0)) {
- NDPI_LOG_DBG(ndpi_struct, "found OSCAR SERVER SSL DETECTED\n");
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR);
- return;
- }
- }
- }
+ printf("Client SSL [TLS version: 0x%04X]\n", tls_version);
+ }
+#endif
+ }
+ }
- no_check_for_tls_payload:
- if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) {
- NDPI_LOG_DBG(ndpi_struct, "found ssl connection\n");
- tlsDetectProtocolFromCertificate(ndpi_struct, flow, skip_cert_processing);
+ extension_offset += extension_len;
#ifdef DEBUG_TLS
- printf("[TLS] %s() [tls_seen_client_cert: %u][tls_seen_server_cert: %u]\n", __FUNCTION__,
- flow->l4.tcp.tls_seen_client_cert, flow->l4.tcp.tls_seen_server_cert);
+ printf("Client SSL [extension_offset/len: %u/%u]\n", extension_offset, extension_len);
#endif
+ } /* while */
- if(!packet->tls_certificate_detected
- && (!(flow->l4.tcp.tls_seen_client_cert && flow->l4.tcp.tls_seen_server_cert))) {
- /* SSL without certificate (Skype, Ultrasurf?) */
- NDPI_LOG_INFO(ndpi_struct, "found ssl NO_CERT\n");
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
- } else if((packet->tls_certificate_num_checks >= 3)
- && flow->l4.tcp.tls_srv_cert_fingerprint_processed) {
- NDPI_LOG_INFO(ndpi_struct, "found ssl\n");
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
- }
- }
-}
+ if(!invalid_ja3) {
+ int rc;
-/* **************************************** */
+ compute_ja3c:
+ ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.tls_handshake_version);
-static u_int8_t ndpi_search_tlsv3_direction1(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow) {
- struct ndpi_packet_struct *packet = &flow->packet;
+ for(i=0; i<ja3.num_cipher; i++) {
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
+ (i > 0) ? "-" : "", ja3.cipher[i]);
+ if(rc > 0) ja3_str_len += rc; else break;
+ }
- if((packet->payload_packet_len >= 5)
- && ((packet->payload[0] == 0x16) || packet->payload[0] == 0x17)
- && (packet->payload[1] == 0x03)
- && ((packet->payload[2] == 0x00) || (packet->payload[2] == 0x01) ||
- (packet->payload[2] == 0x02) || (packet->payload[2] == 0x03))) {
- u_int32_t temp;
- NDPI_LOG_DBG2(ndpi_struct, "search sslv3\n");
- // SSLv3 Record
- if(packet->payload_packet_len >= 1300) {
- return 1;
- }
- temp = ntohs(get_u_int16_t(packet->payload, 3)) + 5;
- NDPI_LOG_DBG2(ndpi_struct, "temp = %u\n", temp);
- if(packet->payload_packet_len == temp
- || (temp < packet->payload_packet_len && packet->payload_packet_len > 500)) {
- return 1;
- }
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
+ if(rc > 0) ja3_str_len += rc;
- if(packet->payload_packet_len < temp && temp < 5000 && packet->payload_packet_len > 9) {
- /* the server hello may be split into small packets */
- u_int32_t cert_start;
+ /* ********** */
- NDPI_LOG_DBG2(ndpi_struct,
- "maybe SSLv3 server hello split into smaller packets\n");
+ for(i=0; i<ja3.num_tls_extension; i++) {
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
+ (i > 0) ? "-" : "", ja3.tls_extension[i]);
+ if(rc > 0) ja3_str_len += rc; else break;
+ }
- /* lets hope at least the server hello and the start of the certificate block are in the first packet */
- cert_start = ntohs(get_u_int16_t(packet->payload, 7)) + 5 + 4;
- NDPI_LOG_DBG2(ndpi_struct, "suspected start of certificate: %u\n",
- cert_start);
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
+ if(rc > 0) ja3_str_len += rc;
- if(cert_start < packet->payload_packet_len && packet->payload[cert_start] == 0x0b) {
- NDPI_LOG_DBG2(ndpi_struct,
- "found 0x0b at suspected start of certificate block\n");
- return 2;
- }
- }
+ /* ********** */
- if((packet->payload_packet_len > temp) && (packet->payload_packet_len > 100)) {
- /* the server hello may be split into small packets and the certificate has its own SSL Record
- * so temp contains only the length for the first ServerHello block */
- u_int32_t cert_start;
+ for(i=0; i<ja3.num_elliptic_curve; i++) {
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
+ (i > 0) ? "-" : "", ja3.elliptic_curve[i]);
+ if(rc > 0) ja3_str_len += rc; else break;
+ }
- NDPI_LOG_DBG2(ndpi_struct,
- "maybe SSLv3 server hello split into smaller packets but with seperate record for the certificate\n");
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
+ if(rc > 0) ja3_str_len += rc;
- /* lets hope at least the server hello record and the start of the certificate record are in the first packet */
- cert_start = ntohs(get_u_int16_t(packet->payload, 7)) + 5 + 5 + 4;
- NDPI_LOG_DBG2(ndpi_struct, "suspected start of certificate: %u\n",
- cert_start);
+ for(i=0; i<ja3.num_elliptic_curve_point_format; i++) {
+ rc = snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
+ (i > 0) ? "-" : "", ja3.elliptic_curve_point_format[i]);
+ if(rc > 0) ja3_str_len += rc; else break;
+ }
- if(cert_start < packet->payload_packet_len && packet->payload[cert_start] == 0x0b) {
- NDPI_LOG_DBG2(ndpi_struct,
- "found 0x0b at suspected start of certificate block\n");
- return 2;
- }
- }
+#ifdef DEBUG_TLS
+ printf("[JA3] Client: %s \n", ja3_str);
+#endif
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
+ ndpi_MD5Final(md5_hash, &ctx);
- if(packet->payload_packet_len >= temp + 5 && (packet->payload[temp] == 0x14 || packet->payload[temp] == 0x16)
- && packet->payload[temp + 1] == 0x03) {
- u_int32_t temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5;
- if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) {
- return 1;
- }
- temp += temp2;
- NDPI_LOG_DBG2(ndpi_struct, "temp = %u\n", temp);
- if(packet->payload_packet_len == temp) {
- return 1;
- }
- if(packet->payload_packet_len >= temp + 5 &&
- packet->payload[temp] == 0x16 && packet->payload[temp + 1] == 0x03) {
- temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5;
- if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) {
- return 1;
- }
- temp += temp2;
- NDPI_LOG_DBG2(ndpi_struct, "temp = %u\n", temp);
- if(packet->payload_packet_len == temp) {
- return 1;
- }
- if(packet->payload_packet_len >= temp + 5 &&
- packet->payload[temp] == 0x16 && packet->payload[temp + 1] == 0x03) {
- temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5;
- if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) {
- return 1;
- }
- temp += temp2;
- NDPI_LOG_DBG2(ndpi_struct, "temp = %u\n", temp);
- if(temp == packet->payload_packet_len) {
- return 1;
+ for(i=0, j=0; i<16; i++) {
+ rc = snprintf(&flow->protos.stun_ssl.ssl.ja3_client[j],
+ sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x",
+ md5_hash[i]);
+ if(rc > 0) j += rc; else break;
+ }
+#ifdef DEBUG_TLS
+ printf("[JA3] Client: %s \n", flow->protos.stun_ssl.ssl.ja3_client);
+#endif
+ }
+
+ return(2 /* Client Certificate */);
+ } else {
+#ifdef DEBUG_TLS
+ printf("[TLS] Client: too short [%u vs %u]\n",
+ (extensions_len+offset), total_len);
+#endif
}
+ } else if(offset == total_len) {
+ /* SSL does not have extensions etc */
+ goto compute_ja3c;
}
+ } else {
+#ifdef DEBUG_TLS
+ printf("[JA3] Client: invalid length detected\n");
+#endif
}
}
}
-
- return 0;
+
+ return(0); /* Not found */
}
/* **************************************** */
-void ndpi_search_tls_tcp_udp(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow) {
+static void ndpi_search_tls_tcp_udp(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
- u_int8_t ret, skip_cert_processing = 0;
#ifdef DEBUG_TLS
- printf("==>> %u [len: %u][version: %u]\n",
+ printf("==>> %s() %u [len: %u][version: %u]\n",
+ __FUNCTION__,
flow->guessed_host_protocol_id,
packet->payload_packet_len,
flow->protos.stun_ssl.ssl.ssl_version);
#endif
-
- if(packet->udp != NULL) {
- /* DTLS dissector */
- int rc = sslTryAndRetrieveServerCertificate(ndpi_struct, flow);
-
- if((rc == 0) && (flow->protos.stun_ssl.ssl.ssl_version != 0)) {
- flow->guessed_protocol_id = NDPI_PROTOCOL_TLS;
-
- if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) {
- if(ndpi_struct->stun_cache == NULL)
- ndpi_struct->stun_cache = ndpi_lru_cache_init(1024);
-
- if(ndpi_struct->stun_cache) {
-#ifdef DEBUG_TLS
- printf("[LRU] Adding Signal cached keys\n");
-#endif
-
- ndpi_lru_add_to_cache(ndpi_struct->stun_cache, get_stun_lru_key(flow, 0), NDPI_PROTOCOL_SIGNAL);
- ndpi_lru_add_to_cache(ndpi_struct->stun_cache, get_stun_lru_key(flow, 1), NDPI_PROTOCOL_SIGNAL);
- }
-
- /* In Signal protocol STUN turns into DTLS... */
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SIGNAL);
- } else if(flow->protos.stun_ssl.ssl.ja3_server[0] != '\0') {
- /* Wait the server certificate the bless this flow as TLS */
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
- }
- }
- return;
- }
-
- if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) {
- if(flow->l4.tcp.tls_stage == 3 && packet->payload_packet_len > 20 && flow->packet_counter < 5) {
- /* this should only happen, when we detected SSL with a packet that had parts of the certificate in subsequent packets
- * so go on checking for certificate patterns for a couple more packets
- */
- NDPI_LOG_DBG2(ndpi_struct,
- "ssl flow but check another packet for patterns\n");
- tls_mark_and_payload_search(ndpi_struct, flow, skip_cert_processing);
-
- if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) {
- /* still ssl so check another packet */
- return;
- } else {
- /* protocol has changed so we are done */
- return;
- }
- }
-
- return;
- }
-
- NDPI_LOG_DBG(ndpi_struct, "search ssl\n");
-
- /* Check if this is whatsapp first (this proto runs over port 443) */
- if((packet->payload_packet_len > 5)
- && ((packet->payload[0] == 'W')
- && (packet->payload[1] == 'A')
- && (packet->payload[4] == 0)
- && (packet->payload[2] <= 9)
- && (packet->payload[3] <= 9))) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_WHATSAPP, NDPI_PROTOCOL_UNKNOWN);
- return;
- } else if((packet->payload_packet_len == 4)
- && (packet->payload[0] == 'W')
- && (packet->payload[1] == 'A')) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_WHATSAPP, NDPI_PROTOCOL_UNKNOWN);
- return;
- } else {
- /* No whatsapp, let's try SSL */
- if(tlsDetectProtocolFromCertificate(ndpi_struct, flow, skip_cert_processing) > 0)
- return;
- else
- skip_cert_processing = 1;
- }
-
- if(packet->payload_packet_len > 40 && flow->l4.tcp.tls_stage == 0) {
- NDPI_LOG_DBG2(ndpi_struct, "first ssl packet\n");
- // SSLv2 Record
- if(packet->payload[2] == 0x01 && packet->payload[3] == 0x03
- && (packet->payload[4] == 0x00 || packet->payload[4] == 0x01 || packet->payload[4] == 0x02)
- && (packet->payload_packet_len - packet->payload[1] == 2)) {
- NDPI_LOG_DBG2(ndpi_struct, "sslv2 len match\n");
- flow->l4.tcp.tls_stage = 1 + packet->packet_direction;
- return;
- }
-
- if(packet->payload[0] == 0x16 && packet->payload[1] == 0x03
- && (packet->payload[2] == 0x00 || packet->payload[2] == 0x01 || packet->payload[2] == 0x02)
- && (packet->payload_packet_len - ntohs(get_u_int16_t(packet->payload, 3)) == 5)) {
- // SSLv3 Record
- NDPI_LOG_DBG2(ndpi_struct, "sslv3 len match\n");
- flow->l4.tcp.tls_stage = 1 + packet->packet_direction;
- return;
- }
-
- // Application Data pkt
- if(packet->payload[0] == 0x17 && packet->payload[1] == 0x03
- && (packet->payload[2] == 0x00 || packet->payload[2] == 0x01 ||
- packet->payload[2] == 0x02 || packet->payload[2] == 0x03)) {
- if(packet->payload_packet_len - ntohs(get_u_int16_t(packet->payload, 3)) == 5) {
- NDPI_LOG_DBG2(ndpi_struct, "TLS len match\n");
- flow->l4.tcp.tls_stage = 1 + packet->packet_direction;
- return;
- }
- }
- }
-
- if(packet->payload_packet_len > 40 &&
- flow->l4.tcp.tls_stage == 1 + packet->packet_direction
- && flow->packet_direction_counter[packet->packet_direction] < 5) {
- return;
- }
-
- if(packet->payload_packet_len > 40 && flow->l4.tcp.tls_stage == 2 - packet->packet_direction) {
- NDPI_LOG_DBG2(ndpi_struct, "second ssl packet\n");
- // SSLv2 Record
- if(packet->payload[2] == 0x01 && packet->payload[3] == 0x03
- && (packet->payload[4] == 0x00 || packet->payload[4] == 0x01 || packet->payload[4] == 0x02)
- && (packet->payload_packet_len - 2) >= packet->payload[1]) {
- NDPI_LOG_DBG2(ndpi_struct, "sslv2 server len match\n");
- tls_mark_and_payload_search(ndpi_struct, flow, skip_cert_processing);
- return;
- }
-
- ret = ndpi_search_tlsv3_direction1(ndpi_struct, flow);
- if(ret == 1) {
- NDPI_LOG_DBG2(ndpi_struct, "sslv3 server len match\n");
- tls_mark_and_payload_search(ndpi_struct, flow, skip_cert_processing);
- return;
- } else if(ret == 2) {
- NDPI_LOG_DBG2(ndpi_struct,
- "sslv3 server len match with split packet -> check some more packets for SSL patterns\n");
- tls_mark_and_payload_search(ndpi_struct, flow, skip_cert_processing);
-
- if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS)
- flow->l4.tcp.tls_stage = 3;
- return;
- }
-
- if(packet->payload_packet_len > 40 && flow->packet_direction_counter[packet->packet_direction] < 5) {
- NDPI_LOG_DBG2(ndpi_struct, "need next packet\n");
- return;
- }
- }
-
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
-
- return;
+ if(packet->udp != NULL)
+ ndpi_search_tls_udp(ndpi_struct, flow);
+ else
+ ndpi_search_tls_tcp(ndpi_struct, flow);
}
/* **************************************** */
diff --git a/src/lib/protocols/ubntac2.c b/src/lib/protocols/ubntac2.c
index 6fc004228..49a63ed0a 100644
--- a/src/lib/protocols/ubntac2.c
+++ b/src/lib/protocols/ubntac2.c
@@ -64,11 +64,9 @@ void ndpi_search_ubntac2(struct ndpi_detection_module_struct *ndpi_struct, struc
version[j] = '\0';
- if(!ndpi_struct->disable_metadata_export) {
- len = ndpi_min(sizeof(flow->protos.ubntac2.version)-1, j);
- strncpy(flow->protos.ubntac2.version, (const char *)version, len);
- flow->protos.ubntac2.version[len] = '\0';
- }
+ len = ndpi_min(sizeof(flow->protos.ubntac2.version)-1, j);
+ strncpy(flow->protos.ubntac2.version, (const char *)version, len);
+ flow->protos.ubntac2.version[len] = '\0';
}
NDPI_LOG_INFO(ndpi_struct, "UBNT AirControl 2 request\n");
diff --git a/src/lib/protocols/whoisdas.c b/src/lib/protocols/whoisdas.c
index 9a65656a8..6ccac8c77 100644
--- a/src/lib/protocols/whoisdas.c
+++ b/src/lib/protocols/whoisdas.c
@@ -40,15 +40,13 @@ void ndpi_search_whois_das(struct ndpi_detection_module_struct *ndpi_struct, str
u_int max_len = sizeof(flow->host_server_name) - 1;
u_int i, j;
- if(!ndpi_struct->disable_metadata_export) {
- for(i=strlen((const char *)flow->host_server_name), j=0; (i<max_len) && (j<packet->payload_packet_len); i++, j++) {
- if((packet->payload[j] == '\n') || (packet->payload[j] == '\r')) break;
- flow->host_server_name[i] = packet->payload[j];
- }
-
- flow->host_server_name[i] = '\0';
+ for(i=strlen((const char *)flow->host_server_name), j=0; (i<max_len) && (j<packet->payload_packet_len); i++, j++) {
+ if((packet->payload[j] == '\n') || (packet->payload[j] == '\r')) break;
+ flow->host_server_name[i] = packet->payload[j];
}
+ flow->host_server_name[i] = '\0';
+
flow->server_id = ((sport == 43) || (sport == 4343)) ? flow->src : flow->dst;
NDPI_LOG_INFO(ndpi_struct, "[WHOIS/DAS] %s\n", flow->host_server_name);