Skip to content

Commit e9751ce

Browse files
authored
Added TLS Block Analysis (#3016)
* Enabled TLS block analysis via --cfg=tls,blocks_analysis,1 * Added comment and optimization * Updated output format * Code cleanup
1 parent 71033e0 commit e9751ce

File tree

7 files changed

+78
-47
lines changed

7 files changed

+78
-47
lines changed

example/ndpiReader.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2513,9 +2513,8 @@ static void printFlow(u_int32_t id, struct ndpi_flow_info *flow, u_int16_t threa
25132513

25142514
char unknown_cipher[8];
25152515
if(flow->ssh_tls.server_cipher != '\0')
2516-
{
2517-
fprintf(out, "[Cipher: %s]", ndpi_cipher2str(flow->ssh_tls.server_cipher, unknown_cipher));
2518-
}
2516+
fprintf(out, "[Cipher: %s]", ndpi_cipher2str(flow->ssh_tls.server_cipher, unknown_cipher));
2517+
25192518
if(flow->bittorent_hash != NULL) fprintf(out, "[BT Hash: %s]", flow->bittorent_hash);
25202519
if(flow->dhcp_fingerprint != NULL) fprintf(out, "[DHCP Fingerprint: %s]", flow->dhcp_fingerprint);
25212520
if(flow->dhcp_class_ident) fprintf(out, "[DHCP Class Ident: %s]",
@@ -2531,6 +2530,17 @@ static void printFlow(u_int32_t id, struct ndpi_flow_info *flow, u_int16_t threa
25312530
print_bin(out, "Plen Bins", &flow->payload_len_bin);
25322531
#endif
25332532

2533+
if(flow->ssh_tls.num_blocks > 0) {
2534+
int i;
2535+
2536+
fprintf(out, "[TLS blocks: ");
2537+
2538+
for(i=0; i<flow->ssh_tls.num_blocks; i++)
2539+
fprintf(out, "%s%u/%d", (i > 0) ? "," : "", flow->ssh_tls.blocks[i].block_type, flow->ssh_tls.blocks[i].len);
2540+
2541+
fprintf(out, "]");
2542+
}
2543+
25342544
if(flow->flow_payload && (flow->flow_payload_len > 0)) {
25352545
u_int i;
25362546

example/reader_util.c

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ struct ndpi_workflow* ndpi_workflow_init(const struct ndpi_workflow_prefs * pref
420420
LOG(NDPI_LOG_ERROR, "global structure initialization failed\n");
421421
return NULL;
422422
}
423-
423+
424424
workflow = ndpi_calloc(1, sizeof(struct ndpi_workflow));
425425
if(workflow == NULL) {
426426
LOG(NDPI_LOG_ERROR, "global structure initialization failed\n");
@@ -1539,7 +1539,7 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
15391539

15401540
if(flow->ndpi_flow->ndpi.fingerprint)
15411541
flow->ndpi_fingerprint = ndpi_strdup(flow->ndpi_flow->ndpi.fingerprint);
1542-
1542+
15431543
if(flow->ndpi_flow->protos.tls_quic.ja4_client_raw)
15441544
flow->ssh_tls.ja4_client_raw = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.ja4_client_raw);
15451545

@@ -1579,16 +1579,21 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
15791579
correct_csv_data_field(flow->ssh_tls.negotiated_alpn);
15801580
}
15811581

1582-
if(enable_doh_dot_detection) {
1583-
/* For TLS we use TLS block lenght instead of payload lenght */
1584-
ndpi_reset_bin(&flow->payload_len_bin);
1585-
1586-
for(i=0; i<flow->ndpi_flow->l4.tcp.tls.num_tls_blocks; i++) {
1587-
u_int16_t len = abs(flow->ndpi_flow->l4.tcp.tls.tls_application_blocks_len[i]);
1588-
1589-
/* printf("[TLS_LEN] %u\n", len); */
1590-
ndpi_inc_bin(&flow->payload_len_bin, plen2slot(len), 1);
1582+
if(flow->protocol == IPPROTO_TCP) {
1583+
if(enable_doh_dot_detection) {
1584+
/* For TLS we use TLS block lenght instead of payload lenght */
1585+
ndpi_reset_bin(&flow->payload_len_bin);
1586+
1587+
for(i=0; i<flow->ndpi_flow->l4.tcp.tls.num_tls_blocks; i++) {
1588+
u_int16_t len = abs(flow->ndpi_flow->l4.tcp.tls.tls_blocks[i].len);
1589+
1590+
/* printf("[TLS_LEN] %u\n", len); */
1591+
ndpi_inc_bin(&flow->payload_len_bin, plen2slot(len), 1);
1592+
}
15911593
}
1594+
1595+
flow->ssh_tls.num_blocks = flow->ndpi_flow->l4.tcp.tls.num_tls_blocks;
1596+
memcpy(flow->ssh_tls.blocks, flow->ndpi_flow->l4.tcp.tls.tls_blocks, sizeof(flow->ndpi_flow->l4.tcp.tls.tls_blocks));
15921597
}
15931598
}
15941599
/* FASTCGI */
@@ -1616,14 +1621,14 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
16161621
ndpi_print_os_hint(flow->ndpi_flow->tcp.os_hint));
16171622
flow->tcp_fingerprint = ndpi_strdup(buf);
16181623
}
1619-
1624+
16201625
/* HTTP metadata are "global" not in `flow->ndpi_flow->protos` union; for example, we can have
16211626
HTTP/BitTorrent and in that case we want to export also HTTP attributes */
16221627
if(ndpi_stack_is_http_like(&flow->detected_protocol.protocol_stack)) { /* HTTP, HTTP_PROXY, HTTP_CONNECT */
16231628
if(flow->ndpi_flow->http.url != NULL) {
16241629
ndpi_snprintf(flow->http.url, sizeof(flow->http.url), "%s", flow->ndpi_flow->http.url);
16251630
}
1626-
1631+
16271632
flow->http.response_status_code = flow->ndpi_flow->http.response_status_code;
16281633
ndpi_snprintf(flow->http.content_type, sizeof(flow->http.content_type), "%s", flow->ndpi_flow->http.content_type ? flow->ndpi_flow->http.content_type : "");
16291634
ndpi_snprintf(flow->http.server, sizeof(flow->http.server), "%s", flow->ndpi_flow->http.server ? flow->ndpi_flow->http.server : "");
@@ -1636,7 +1641,7 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
16361641

16371642
if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_RTP))
16381643
memcpy(&flow->rtp, &flow->ndpi_flow->rtp, sizeof(flow->rtp));
1639-
1644+
16401645
ndpi_snprintf(flow->http.user_agent,
16411646
sizeof(flow->http.user_agent),
16421647
"%s", (flow->ndpi_flow->http.user_agent ? flow->ndpi_flow->http.user_agent : ""));

example/reader_util.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ typedef struct ndpi_flow_info {
318318
ndpi_cipher_weakness client_unsafe_cipher, server_unsafe_cipher;
319319

320320
u_int32_t quic_version;
321+
322+
u_int8_t num_blocks;
323+
struct ndpi_tls_block blocks[NDPI_MAX_NUM_TLS_APPL_BLOCKS];
321324
} ssh_tls;
322325

323326
struct {
@@ -357,7 +360,7 @@ typedef struct ndpi_flow_info {
357360
#else
358361
struct ndpi_bin payload_len_bin;
359362
#endif
360-
363+
361364
/* Flow payload */
362365
u_int16_t flow_payload_len;
363366
char *flow_payload;

src/include/ndpi_private.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ struct ndpi_detection_module_config_struct {
299299
int tls_ja4c_fingerprint_enabled;
300300
int tls_ja4r_fingerprint_enabled;
301301
int tls_subclassification_enabled;
302-
302+
int tls_blocks_analysis_enabled;
303303
int quic_subclassification_enabled;
304304

305305
int smtp_opportunistic_tls_enabled;

src/include/ndpi_typedefs.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -830,9 +830,13 @@ struct ndpi_lru_cache {
830830
#define NDPI_HEURISTICS_TLS_OBFUSCATED_TLS 0x02 /* Enable heuristic to detect proxied/obfuscated TLS flows over TLS tunnels, i.e. TLS over TLS */
831831
#define NDPI_HEURISTICS_TLS_OBFUSCATED_HTTP 0x04 /* Enable heuristic to detect proxied/obfuscated TLS flows over HTTP/WebSocket */
832832

833-
834833
/* ************************************************** */
835834

835+
struct ndpi_tls_block {
836+
u_int8_t block_type; /* + = src->dst, - = dst->src */
837+
int16_t len;
838+
};
839+
836840
struct ndpi_flow_tcp_struct {
837841
/* TCP sequence number */
838842
u_int32_t next_tcp_seq_nr[2];
@@ -854,12 +858,10 @@ struct ndpi_flow_tcp_struct {
854858
struct {
855859
/* NDPI_PROTOCOL_TLS */
856860
u_int8_t app_data_seen[2];
857-
u_int8_t num_tls_blocks;
858-
int16_t tls_application_blocks_len[NDPI_MAX_NUM_TLS_APPL_BLOCKS]; /* + = src->dst, - = dst->src */
861+
u_int8_t num_tls_blocks, num_processed_tls_blocks /* used internally for dissection */;
862+
struct ndpi_tls_block tls_blocks[NDPI_MAX_NUM_TLS_APPL_BLOCKS];
859863
} tls;
860864

861-
862-
863865
/* NDPI_PROTOCOL_MAIL_SMTP */
864866
u_int16_t smtp_command_bitmask;
865867

src/lib/ndpi_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13433,6 +13433,7 @@ static const struct cfg_param {
1343313433
{ "tls", "metadata.ja4c_fingerprint", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_ja4c_fingerprint_enabled), NULL },
1343413434
{ "tls", "metadata.ja4r_fingerprint", "disable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_ja4r_fingerprint_enabled), NULL },
1343513435
{ "tls", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_subclassification_enabled), NULL },
13436+
{ "tls", "blocks_analysis", "disable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_blocks_analysis_enabled), NULL },
1343613437

1343713438
{ "quic", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(quic_subclassification_enabled), NULL },
1343813439

src/lib/protocols/tls.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,10 @@ static bool str_contains_digit(char *str) {
123123

124124
/* TODO: rename */
125125
static int keep_extra_dissection_tcp(struct ndpi_detection_module_struct *ndpi_struct,
126-
struct ndpi_flow_struct *flow)
127-
{
126+
struct ndpi_flow_struct *flow) {
127+
if(ndpi_struct->cfg.tls_blocks_analysis_enabled)
128+
return(1); /* Process as much TLS blocks as the max packet number */
129+
128130
/* Common path: found handshake on both directions */
129131
if(
130132
(flow->tls_quic.certificate_processed == 1 && flow->protos.tls_quic.client_hello_processed)
@@ -1245,7 +1247,7 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
12451247
}
12461248

12471249
if((ndpi_struct->num_tls_blocks_to_follow != 0)
1248-
&& (flow->l4.tcp.tls.num_tls_blocks >= ndpi_struct->num_tls_blocks_to_follow)) {
1250+
&& (flow->l4.tcp.tls.num_processed_tls_blocks >= ndpi_struct->num_tls_blocks_to_follow)) {
12491251
#ifdef DEBUG_TLS_BLOCKS
12501252
printf("*** [TLS Block] Enough blocks dissected\n");
12511253
#endif
@@ -1412,6 +1414,23 @@ int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
14121414

14131415
content_type = message->buffer[0];
14141416

1417+
if(ndpi_struct->cfg.tls_blocks_analysis_enabled) {
1418+
if(flow->l4.tcp.tls.num_tls_blocks < NDPI_MAX_NUM_TLS_APPL_BLOCKS) {
1419+
int16_t blen = len-5;
1420+
1421+
/* Use positive values for c->s and negative for s->c */
1422+
if(packet->packet_direction != 0) blen = -blen;
1423+
1424+
flow->l4.tcp.tls.tls_blocks[flow->l4.tcp.tls.num_tls_blocks].len = blen;
1425+
flow->l4.tcp.tls.tls_blocks[flow->l4.tcp.tls.num_tls_blocks++].block_type = content_type;
1426+
1427+
#ifdef DEBUG_TLS_BLOCKS
1428+
printf("*** [TLS Block] [len: %u][num_tls_blocks: %u/%u]\n",
1429+
len-5, flow->l4.tcp.tls.num_tls_blocks, ndpi_struct->num_tls_blocks_to_follow);
1430+
#endif
1431+
}
1432+
}
1433+
14151434
/* Overwriting packet payload */
14161435
p = packet->payload;
14171436
p_len = packet->payload_packet_len; /* Backup */
@@ -1423,7 +1442,7 @@ int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
14231442
so in this case we reset the number of observed
14241443
TLS blocks
14251444
*/
1426-
flow->l4.tcp.tls.num_tls_blocks = 0;
1445+
flow->l4.tcp.tls.num_processed_tls_blocks = 0;
14271446
}
14281447
if(len == 6 &&
14291448
message->buffer[1] == 0x03 && /* TLS >= 1.0 */
@@ -1439,8 +1458,15 @@ int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
14391458
ndpi_int_tls_add_connection(ndpi_struct, flow);
14401459
flow->l4.tcp.tls.app_data_seen[packet->packet_direction] = 1;
14411460
/* Further data is encrypted so we are not able to parse it without
1442-
erros and without setting `something_went_wrong` variable */
1443-
break;
1461+
errors and without setting `something_went_wrong` variable */
1462+
1463+
if(!ndpi_struct->cfg.tls_blocks_analysis_enabled) {
1464+
/*
1465+
In case of TLS blocks analysis we want to analize all the blocks
1466+
whereas in "standard" mode we can use this shortcut and break
1467+
*/
1468+
break;
1469+
}
14441470
}
14451471
} else if(content_type == 0x15 /* Alert */) {
14461472
/* https://techcommunity.microsoft.com/t5/iis-support-blog/ssl-tls-alert-protocol-and-the-alert-codes/ba-p/377132 */
@@ -1513,22 +1539,6 @@ int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
15131539
flow->l4.tcp.tls.app_data_seen[packet->packet_direction] = 1;
15141540
if(flow->l4.tcp.tls.app_data_seen[!packet->packet_direction] == 1)
15151541
flow->tls_quic.certificate_processed = 1;
1516-
1517-
if(flow->tls_quic.certificate_processed) {
1518-
if(flow->l4.tcp.tls.num_tls_blocks < ndpi_struct->num_tls_blocks_to_follow) {
1519-
int16_t blen = len-5;
1520-
1521-
/* Use positive values for c->s e negative for s->c */
1522-
if(packet->packet_direction != 0) blen = -blen;
1523-
1524-
flow->l4.tcp.tls.tls_application_blocks_len[flow->l4.tcp.tls.num_tls_blocks++] = blen;
1525-
}
1526-
1527-
#ifdef DEBUG_TLS_BLOCKS
1528-
printf("*** [TLS Block] [len: %u][num_tls_blocks: %u/%u]\n",
1529-
len-5, flow->l4.tcp.tls.num_tls_blocks, ndpi_struct->num_tls_blocks_to_follow);
1530-
#endif
1531-
}
15321542
}
15331543
}
15341544

@@ -1552,7 +1562,7 @@ int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
15521562

15531563
if(something_went_wrong
15541564
|| ((ndpi_struct->num_tls_blocks_to_follow > 0)
1555-
&& (flow->l4.tcp.tls.num_tls_blocks == ndpi_struct->num_tls_blocks_to_follow))
1565+
&& (flow->l4.tcp.tls.num_processed_tls_blocks == ndpi_struct->num_tls_blocks_to_follow))
15561566
|| ((ndpi_struct->num_tls_blocks_to_follow == 0)
15571567
&& (!keep_extra_dissection_tcp(ndpi_struct, flow)))
15581568
) {

0 commit comments

Comments
 (0)