Reworked TLS dissector to export further metadata (#3066)

* Reworked TLS dissector to give users the ability to )optionnaly)
collect and export TLS metadata via "--cfg=tls,metadata.ja_data,1"
This commit is contained in:
Luca Deri 2025-12-20 17:33:09 +01:00 committed by GitHub
parent 712f4bc72a
commit 45e3213d7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 225 additions and 111 deletions

View file

@ -363,4 +363,8 @@ static inline uint64_t get_u_int64_t(const uint8_t* X, int O)
/* Maximum number of plugins supported by nDPI */
#define NDPI_MAX_NUM_PLUGINS 32
/* JA3/4 Information */
#define MAX_NUM_JA 128
#define MAX_JA_STRLEN 256
#endif /* __NDPI_DEFINE_INCLUDE_FILE__ */

View file

@ -297,6 +297,7 @@ struct ndpi_detection_module_config_struct {
int tls_ja3s_fingerprint_enabled;
int tls_ja4c_fingerprint_enabled;
int tls_ja4r_fingerprint_enabled;
int tls_ja_data_enabled;
int tls_subclassification_enabled;
int tls_blocks_analysis_enabled;
int quic_subclassification_enabled;

View file

@ -1518,6 +1518,28 @@ typedef struct ndpi_protocol_plugin {
typedef int (*ProcessExtraPacketsFunc) (struct ndpi_detection_module_struct *, struct ndpi_flow_struct *flow);
typedef struct {
u_int16_t tls_handshake_version;
u_int16_t num_ciphers, cipher[MAX_NUM_JA];
u_int16_t num_tls_extensions, tls_extension[MAX_NUM_JA];
u_int16_t num_elliptic_curve_groups, elliptic_curve_group[MAX_NUM_JA];
u_int16_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA];
u_int16_t num_signature_algorithms, signature_algorithm[MAX_NUM_JA];
u_int16_t num_supported_versions, supported_version[MAX_NUM_JA];
u_int16_t num_key_share_groups, key_share_group[MAX_NUM_JA];
char signature_algorithms_str[MAX_JA_STRLEN], alpn[MAX_JA_STRLEN];
char alpn_original_last; /* Store original last character before null terminator */
} ndpi_tls_client_info;
typedef struct {
u_int16_t tls_handshake_version;
u_int16_t num_ciphers, cipher[MAX_NUM_JA];
u_int16_t num_tls_extensions, tls_extension[MAX_NUM_JA];
u_int16_t tls_supported_version;
u_int16_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA];
char alpn[MAX_JA_STRLEN];
} ndpi_tls_server_info;
struct ndpi_flow_struct {
u_int16_t detected_protocol_stack[NDPI_PROTOCOL_SIZE];
struct ndpi_proto_stack protocol_stack;
@ -1693,8 +1715,7 @@ struct ndpi_flow_struct {
u_int16_t server_cipher;
u_int8_t sha1_certificate_fingerprint[20];
u_int8_t client_hello_processed:1, ch_direction:1, subprotocol_detected:1,
server_hello_processed:1, fingerprint_set:1, webrtc:1,
pq_key_share:1, pq_supported_groups:1;
server_hello_processed:1, fingerprint_set:1, webrtc:1;
#ifdef TLS_HANDLE_SIGNATURE_ALGORITMS
/* Under #ifdef to save memory for those who do not need them */
@ -1713,6 +1734,10 @@ struct ndpi_flow_struct {
u_int32_t quic_version;
u_int32_t quic_idle_timeout_sec;
/* Optionally allocated based on nDPI configuration */
ndpi_tls_client_info *ja_client;
ndpi_tls_server_info *ja_server;
} tls_quic; /* Used also by DTLS and POPS/IMAPS/SMTPS/FTPS */
struct {
@ -1918,11 +1943,11 @@ struct ndpi_flow_struct {
#if !defined(NDPI_CFFI_PREPROCESSING) && defined(__linux__)
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
_Static_assert(sizeof(((struct ndpi_flow_struct *)0)->protos) <= 264,
"Size of the struct member protocols increased to more than 264 bytes, "
_Static_assert(sizeof(((struct ndpi_flow_struct *)0)->protos) <= 328,
"Size of the struct member protocols increased to more than 328 bytes, "
"please check if this change is necessary.");
_Static_assert(sizeof(struct ndpi_flow_struct) <= 1240,
"Size of the flow struct increased to more than 1240 bytes, "
_Static_assert(sizeof(struct ndpi_flow_struct) <= 1304,
"Size of the flow struct increased to more than 1304 bytes, "
"please check if this change is necessary.");
#endif
#endif

View file

@ -150,6 +150,7 @@ static const struct cfg_param {
{ "tls", "metadata.ja3s_fingerprint", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_ja3s_fingerprint_enabled), NULL },
{ "tls", "metadata.ja4c_fingerprint", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_ja4c_fingerprint_enabled), NULL },
{ "tls", "metadata.ja4r_fingerprint", "disable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_ja4r_fingerprint_enabled), NULL },
{ "tls", "metadata.ja_data", "disable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_ja_data_enabled), NULL },
{ "tls", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_subclassification_enabled), NULL },
{ "tls", "blocks_analysis", "disable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_blocks_analysis_enabled), NULL },

View file

@ -7890,6 +7890,12 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) {
if(flow->protos.tls_quic.ja4_client_raw)
ndpi_free(flow->protos.tls_quic.ja4_client_raw);
if(flow->protos.tls_quic.ja_client)
ndpi_free(flow->protos.tls_quic.ja_client);
if(flow->protos.tls_quic.ja_server)
ndpi_free(flow->protos.tls_quic.ja_server);
}
if(flow_is_proto(flow, NDPI_PROTOCOL_SIP)) {

View file

@ -1208,8 +1208,7 @@ void ndpi_serialize_proto(struct ndpi_detection_module_struct *ndpi_struct,
static void ndpi_tls2json(ndpi_serializer *serializer, struct ndpi_flow_struct *flow, bool is_tls_proto)
{
if(flow->protos.tls_quic.ssl_version)
{
if(flow->protos.tls_quic.ssl_version) {
char buf[64];
char notBefore[32], notAfter[32];
struct tm a, b, *before = NULL, *after = NULL;
@ -1220,33 +1219,26 @@ static void ndpi_tls2json(ndpi_serializer *serializer, struct ndpi_flow_struct *
ndpi_ssl_version2str(version, sizeof(version), flow->protos.tls_quic.ssl_version, &unknown_tls_version);
if(flow->protos.tls_quic.notBefore)
{
before = ndpi_gmtime_r((const time_t *)&flow->protos.tls_quic.notBefore, &a);
}
if(flow->protos.tls_quic.notAfter)
{
after = ndpi_gmtime_r((const time_t *)&flow->protos.tls_quic.notAfter, &b);
}
if(!unknown_tls_version)
{
if(flow->protos.tls_quic.notAfter)
after = ndpi_gmtime_r((const time_t *)&flow->protos.tls_quic.notAfter, &b);
if(!unknown_tls_version) {
ndpi_serialize_start_of_block(serializer, "tls");
ndpi_serialize_string_string(serializer, "version", version);
if(flow->protos.tls_quic.server_names)
{
if(flow->protos.tls_quic.server_names) {
ndpi_serialize_string_string(serializer, "server_names",
flow->protos.tls_quic.server_names);
}
if(before)
{
if(before) {
strftime(notBefore, sizeof(notBefore), "%Y-%m-%d %H:%M:%S", before);
ndpi_serialize_string_string(serializer, "notbefore", notBefore);
}
if(after)
{
if(after) {
strftime(notAfter, sizeof(notAfter), "%Y-%m-%d %H:%M:%S", after);
ndpi_serialize_string_string(serializer, "notafter", notAfter);
}
@ -1258,30 +1250,22 @@ static void ndpi_tls2json(ndpi_serializer *serializer, struct ndpi_flow_struct *
ndpi_cipher2str(flow->protos.tls_quic.server_cipher, unknown_cipher));
if(flow->protos.tls_quic.issuerDN)
{
ndpi_serialize_string_string(serializer, "issuerDN", flow->protos.tls_quic.issuerDN);
}
if(flow->protos.tls_quic.subjectDN)
{
ndpi_serialize_string_string(serializer, "subjectDN", flow->protos.tls_quic.subjectDN);
}
if(flow->protos.tls_quic.advertised_alpns)
{
ndpi_serialize_string_string(serializer, "advertised_alpns", flow->protos.tls_quic.advertised_alpns);
}
if(flow->protos.tls_quic.negotiated_alpn)
{
ndpi_serialize_string_string(serializer, "negotiated_alpn", flow->protos.tls_quic.negotiated_alpn);
}
if(flow->protos.tls_quic.tls_supported_versions)
{
ndpi_serialize_string_string(serializer, "tls_supported_versions", flow->protos.tls_quic.tls_supported_versions);
}
if(flow->protos.tls_quic.sha1_certificate_fingerprint[0] != '\0')
{
for(i=0, off=0; i<20; i++)
{
if(flow->protos.tls_quic.subjectDN)
ndpi_serialize_string_string(serializer, "subjectDN", flow->protos.tls_quic.subjectDN);
if(flow->protos.tls_quic.advertised_alpns)
ndpi_serialize_string_string(serializer, "advertised_alpns", flow->protos.tls_quic.advertised_alpns);
if(flow->protos.tls_quic.negotiated_alpn)
ndpi_serialize_string_string(serializer, "negotiated_alpn", flow->protos.tls_quic.negotiated_alpn);
if(flow->protos.tls_quic.tls_supported_versions)
ndpi_serialize_string_string(serializer, "tls_supported_versions", flow->protos.tls_quic.tls_supported_versions);
if(flow->protos.tls_quic.sha1_certificate_fingerprint[0] != '\0') {
for(i=0, off=0; i<20; i++) {
int rc = ndpi_snprintf(&buf[off], sizeof(buf)-off,"%s%02X", (i > 0) ? ":" : "",
flow->protos.tls_quic.sha1_certificate_fingerprint[i] & 0xFF);
@ -1292,13 +1276,120 @@ static void ndpi_tls2json(ndpi_serializer *serializer, struct ndpi_flow_struct *
}
if (is_tls_proto == true)
{
ndpi_serialize_string_uint32(serializer, "blocks", flow->l4.tcp.tls.num_tls_blocks);
}
#ifdef TLS_HANDLE_SIGNATURE_ALGORITMS
ndpi_serialize_string_uint32(serializer, "sig_algs", flow->protos.tls_quic.num_tls_signature_algorithms);
#endif
if(flow->protos.tls_quic.ja_client != NULL) {
ndpi_tls_client_info *c = flow->protos.tls_quic.ja_client;
u_int16_t i;
ndpi_serialize_start_of_block(serializer, "client_data");
if(c->num_ciphers > 0) {
ndpi_serialize_start_of_list(serializer, "ciphers");
for(i=0; i<c->num_ciphers; i++)
ndpi_serialize_string_uint32(serializer, "", c->cipher[i]);
ndpi_serialize_end_of_list(serializer);
}
if(c->num_tls_extensions > 0) {
ndpi_serialize_start_of_list(serializer, "tls_extensions");
for(i=0; i<c->num_tls_extensions; i++)
ndpi_serialize_string_uint32(serializer, "", c->tls_extension[i]);
ndpi_serialize_end_of_list(serializer);
}
if(c->num_elliptic_curve_groups > 0) {
ndpi_serialize_start_of_list(serializer, "elliptic_curve_groups");
for(i=0; i<c->num_elliptic_curve_groups; i++)
ndpi_serialize_string_uint32(serializer, "", c->elliptic_curve_group[i]);
ndpi_serialize_end_of_list(serializer);
}
if(c->num_elliptic_curve_point_format > 0) {
ndpi_serialize_start_of_list(serializer, "elliptic_curve_point_format");
for(i=0; i<c->num_elliptic_curve_point_format; i++)
ndpi_serialize_string_uint32(serializer, "", c->elliptic_curve_point_format[i]);
ndpi_serialize_end_of_list(serializer);
}
if(c->num_signature_algorithms > 0) {
ndpi_serialize_start_of_list(serializer, "signature_algorithms");
for(i=0; i<c->num_signature_algorithms; i++)
ndpi_serialize_string_uint32(serializer, "", c->signature_algorithm[i]);
ndpi_serialize_end_of_list(serializer);
}
if(c->num_key_share_groups > 0) {
ndpi_serialize_start_of_list(serializer, "key_share_groups");
for(i=0; i<c->num_key_share_groups; i++)
ndpi_serialize_string_uint32(serializer, "", c->key_share_group[i]);
ndpi_serialize_end_of_list(serializer);
}
if(c->num_supported_versions > 0) {
ndpi_serialize_start_of_list(serializer, "supported_versions");
for(i=0; i<c->num_supported_versions; i++)
ndpi_serialize_string_uint32(serializer, "", c->supported_version[i]);
ndpi_serialize_end_of_list(serializer);
}
ndpi_serialize_end_of_block(serializer);
}
if(flow->protos.tls_quic.ja_server != NULL) {
ndpi_tls_server_info *s = flow->protos.tls_quic.ja_server;
u_int16_t i;
ndpi_serialize_start_of_block(serializer, "server_data");
if(s->num_ciphers > 0) {
ndpi_serialize_start_of_list(serializer, "ciphers");
for(i=0; i<s->num_ciphers; i++)
ndpi_serialize_string_uint32(serializer, "", s->cipher[i]);
ndpi_serialize_end_of_list(serializer);
}
if(s->num_tls_extensions > 0) {
ndpi_serialize_start_of_list(serializer, "tls_extensions");
for(i=0; i<s->num_tls_extensions; i++)
ndpi_serialize_string_uint32(serializer, "", s->tls_extension[i]);
ndpi_serialize_end_of_list(serializer);
}
if(s->num_elliptic_curve_point_format > 0) {
ndpi_serialize_start_of_list(serializer, "elliptic_curve_point_format");
for(i=0; i<s->num_elliptic_curve_point_format; i++)
ndpi_serialize_string_uint32(serializer, "", s->elliptic_curve_point_format[i]);
ndpi_serialize_end_of_list(serializer);
}
ndpi_serialize_end_of_block(serializer);
}
ndpi_serialize_end_of_block(serializer);
}
}

View file

@ -57,30 +57,10 @@ static void ndpi_search_tls_wrapper(struct ndpi_detection_module_struct *ndpi_st
*/
#define JA_STR_LEN 1024
#define MAX_NUM_JA 128
#define MAX_JA_STRLEN 256
union ja_info {
struct {
u_int16_t tls_handshake_version;
u_int16_t num_ciphers, cipher[MAX_NUM_JA];
u_int16_t num_tls_extensions, tls_extension[MAX_NUM_JA];
u_int16_t num_elliptic_curve, elliptic_curve[MAX_NUM_JA];
u_int16_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA];
u_int16_t num_signature_algorithms, signature_algorithms[MAX_NUM_JA];
u_int16_t num_supported_versions, supported_versions[MAX_NUM_JA];
char signature_algorithms_str[MAX_JA_STRLEN], alpn[MAX_JA_STRLEN];
char alpn_original_last; /* Store original last character before null terminator */
} client;
struct {
u_int16_t tls_handshake_version;
u_int16_t num_ciphers, cipher[MAX_NUM_JA];
u_int16_t num_tls_extensions, tls_extension[MAX_NUM_JA];
u_int16_t tls_supported_version;
u_int16_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA];
char alpn[MAX_JA_STRLEN];
} server;
union ndpi_ja_info {
ndpi_tls_client_info client;
ndpi_tls_server_info server;
};
/*
@ -2081,7 +2061,7 @@ static bool is_grease_version(u_int16_t version) {
static void ndpi_compute_ja4(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
u_int32_t quic_version,
union ja_info *ja) {
union ndpi_ja_info *ja) {
u_int8_t tmp_str[JA_STR_LEN];
u_int tmp_str_len, num_extn;
u_int8_t sha_hash[NDPI_SHA256_BLOCK_SIZE];
@ -2115,9 +2095,9 @@ static void ndpi_compute_ja4(struct ndpi_detection_module_struct *ndpi_struct,
ja_str[0] = is_dtls ? 'd' : ((quic_version != 0) ? 'q' : 't');
for(i=0; i<ja->client.num_supported_versions; i++) {
if((!is_grease_version(ja->client.supported_versions[i]))
&& (tls_handshake_version < ja->client.supported_versions[i]))
tls_handshake_version = ja->client.supported_versions[i];
if((!is_grease_version(ja->client.supported_version[i]))
&& (tls_handshake_version < ja->client.supported_version[i]))
tls_handshake_version = ja->client.supported_version[i];
}
switch(tls_handshake_version) {
@ -2255,7 +2235,7 @@ static void ndpi_compute_ja4(struct ndpi_detection_module_struct *ndpi_struct,
for(i=0; i<ja->client.num_signature_algorithms; i++) {
rc = ndpi_snprintf((char *)&tmp_str[tmp_str_len], JA_STR_LEN-tmp_str_len, "%s%04x",
(i > 0) ? "," : "_", ja->client.signature_algorithms[i]);
(i > 0) ? "," : "_", ja->client.signature_algorithm[i]);
if((rc > 0) && (tmp_str_len + rc < JA_STR_LEN)) tmp_str_len += rc; else break;
}
@ -2297,7 +2277,7 @@ static void ndpi_compute_ja4(struct ndpi_detection_module_struct *ndpi_struct,
int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow, u_int32_t quic_version) {
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
union ja_info ja;
union ndpi_ja_info ja;
u_int8_t invalid_ja = 0;
u_int16_t tls_version;
u_int32_t i, j;
@ -2341,11 +2321,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
if(handshake_type == 0x02 /* Server Hello */) {
int rc;
ja.server.num_ciphers = 0;
ja.server.num_tls_extensions = 0;
ja.server.num_elliptic_curve_point_format = 0;
ja.server.alpn[0] = '\0';
memset(&ja.server, 0, sizeof(ja.server));
ja.server.tls_handshake_version = tls_version;
#ifdef DEBUG_TLS
@ -2586,21 +2563,23 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#ifdef DEBUG_TLS
printf("[JA3] Server: %s \n", flow->protos.tls_quic.ja3_server);
#endif
if(ndpi_struct->cfg.tls_ja_data_enabled) {
if(flow->protos.tls_quic.ja_server == NULL) {
flow->protos.tls_quic.ja_server = ndpi_malloc(sizeof(ndpi_tls_server_info));
if(flow->protos.tls_quic.ja_server != NULL)
memcpy(flow->protos.tls_quic.ja_server, &ja.server, sizeof(ndpi_tls_server_info));
}
}
}
} else if(handshake_type == 0x01 /* Client Hello */) {
u_int16_t cipher_len, cipher_offset;
u_int8_t cookie_len = 0;
ja.client.num_ciphers = 0;
ja.client.num_tls_extensions = 0;
ja.client.num_elliptic_curve = 0;
ja.client.num_elliptic_curve_point_format = 0;
ja.client.num_signature_algorithms = 0;
ja.client.num_supported_versions = 0;
ja.client.signature_algorithms_str[0] = '\0';
ja.client.alpn[0] = '\0', ja.client.alpn[1] = '\0' /* used by JA4 */;
memset(&ja.client, 0, sizeof(ja.client));
ja.client.alpn_original_last = '0'; /* Initialize to '0' if no ALPN */
flow->protos.tls_quic.ssl_version = ja.client.tls_handshake_version = tls_version;
if(flow->protos.tls_quic.ssl_version < 0x0303) /* < TLSv1.2 */ {
if(is_flowrisk_info_enabled(ndpi_struct, NDPI_TLS_OBSOLETE_VERSION)) {
@ -2916,21 +2895,16 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#ifdef DEBUG_TLS
printf("Client TLS [EllipticCurve: %u/0x%04X]\n", s_group, s_group);
#endif
switch(s_group) {
case 0x11EC: /* X25519MLKEM768 */
flow->protos.tls_quic.pq_supported_groups = 1;
break;
}
if((s_group == 0) || (packet->payload[s_offset+i] != packet->payload[s_offset+i+1])
|| ((packet->payload[s_offset+i] & 0xF) != 0xA)) {
/* Skip GREASE */
if(ja.client.num_elliptic_curve < MAX_NUM_JA)
ja.client.elliptic_curve[ja.client.num_elliptic_curve++] = s_group;
if(ja.client.num_elliptic_curve_groups < MAX_NUM_JA)
ja.client.elliptic_curve_group[ja.client.num_elliptic_curve_groups++] = s_group;
else {
invalid_ja = 1;
#ifdef DEBUG_TLS
printf("Client TLS Invalid num elliptic %u\n", ja.client.num_elliptic_curve);
printf("Client TLS Invalid num elliptic group %u\n", ja.client.num_elliptic_curve_groups);
#endif
}
}
@ -2992,9 +2966,9 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
}
#endif
for(i=0, id=0; i<tot_signature_algorithms_len && s_offset+i+1<total_len; i += 2) {
ja.client.signature_algorithms[id++] = ntohs(*(u_int16_t*)&packet->payload[s_offset+i]);
}
for(i=0, id=0; i<tot_signature_algorithms_len && s_offset+i+1<total_len; i += 2)
ja.client.signature_algorithm[id++] = ntohs(*(u_int16_t*)&packet->payload[s_offset+i]);
ja.client.num_signature_algorithms = id;
for(i=0, id=0; i<tot_signature_algorithms_len && s_offset+i+1<total_len; i++) {
@ -3236,7 +3210,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
version_str_len += rc;
if(ja.client.num_supported_versions < MAX_NUM_JA)
ja.client.supported_versions[ja.client.num_supported_versions++] = tls_version;
ja.client.supported_version[ja.client.num_supported_versions++] = tls_version;
}
}
@ -3355,13 +3329,11 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
extn_offset,
group_id, key_extn_len);
#endif
switch(group_id) {
case 0x11EC: /* X25519MLKEM768 */
flow->protos.tls_quic.pq_key_share = 1;
break;
}
if(group_id != 0x2a2a /* Skip GREASE */) {
if(ja.client.num_key_share_groups < MAX_NUM_JA)
ja.client.key_share_group[ja.client.num_key_share_groups++] = group_id;
}
extn_offset += key_extn_len + 4;
}
}
@ -3384,10 +3356,10 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
compute_ja4c:
if(ndpi_struct->cfg.tls_ja4c_fingerprint_enabled) {
ndpi_compute_ja4(ndpi_struct, flow, quic_version, &ja);
if(ndpi_struct->ja4_custom_protos != NULL) {
u_int64_t proto_id;
/* This protocol has been defined in protos.txt-like files */
if(ndpi_hash_find_entry(ndpi_struct->ja4_custom_protos,
flow->protos.tls_quic.ja4_client,
@ -3409,6 +3381,16 @@ compute_ja4c:
ndpi_set_risk(ndpi_struct, flow, NDPI_MALICIOUS_FINGERPRINT, flow->protos.tls_quic.ja4_client);
}
}
if(ndpi_struct->cfg.tls_ja_data_enabled) {
if(flow->protos.tls_quic.ja_client == NULL) {
flow->protos.tls_quic.ja_client = ndpi_malloc(sizeof(ndpi_tls_client_info));
if(flow->protos.tls_quic.ja_client != NULL)
memcpy(flow->protos.tls_quic.ja_client, &ja.client, sizeof(ndpi_tls_client_info));
}
}
/* End JA4 */
}

View file

@ -293,4 +293,8 @@ static inline u_int64_t get_u_int64_t(const u_int8_t* X, int O)
/* Maximum number of plugins supported by nDPI */
#define NDPI_MAX_NUM_PLUGINS 32
/* JA3/4 Information */
#define MAX_NUM_JA 128
#define MAX_JA_STRLEN 256
#endif /* __NDPI_DEFINE_INCLUDE_FILE__ */