Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS: add support for DTLS (over STUN) over TCP #2463

Merged
merged 1 commit into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 47 additions & 52 deletions src/lib/protocols/stun.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,65 +698,60 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct,
positives. In that case, the TLS dissector doesn't set the master protocol, so we
need to rollback to the current state */

if(packet->tcp) {
/* TODO: TLS code assumes that DTLS is only over UDP */
NDPI_LOG_DBG(ndpi_struct, "Ignoring DTLS over TCP\n");
if(flow->tls_quic.certificate_processed == 1) {
NDPI_LOG_DBG(ndpi_struct, "Interesting DTLS stuff already processed. Ignoring\n");
} else {
if(flow->tls_quic.certificate_processed == 1) {
NDPI_LOG_DBG(ndpi_struct, "Interesting DTLS stuff already processed. Ignoring\n");
} else {
NDPI_LOG_DBG(ndpi_struct, "Switch to DTLS (%d/%d)\n",
flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]);

if(flow->stun.maybe_dtls == 0) {
/* First DTLS packet of the flow */
first_dtls_pkt = 1;

/* We might need to rollback this change... */
old_proto_stack[0] = flow->detected_protocol_stack[0];
old_proto_stack[1] = flow->detected_protocol_stack[1];

/* TODO: right way? It is a bit scary... do we need to reset something else too? */
reset_detected_protocol(flow);
/* We keep the category related to STUN traffic */
/* STUN often triggers this risk; clear it. TODO: clear other risks? */
ndpi_unset_risk(flow, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT);

/* Give room for DTLS handshake, where we might have
retransmissions and fragments */
flow->max_extra_packets_to_check = ndpi_min(255, (int)flow->max_extra_packets_to_check + 10);
flow->stun.maybe_dtls = 1;
}

switch_to_tls(ndpi_struct, flow, first_dtls_pkt);
NDPI_LOG_DBG(ndpi_struct, "Switch to DTLS (%d/%d)\n",
flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]);

if(flow->stun.maybe_dtls == 0) {
/* First DTLS packet of the flow */
first_dtls_pkt = 1;

/* We might need to rollback this change... */
old_proto_stack[0] = flow->detected_protocol_stack[0];
old_proto_stack[1] = flow->detected_protocol_stack[1];

/* TODO: right way? It is a bit scary... do we need to reset something else too? */
reset_detected_protocol(flow);
/* We keep the category related to STUN traffic */
/* STUN often triggers this risk; clear it. TODO: clear other risks? */
ndpi_unset_risk(flow, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT);

/* Give room for DTLS handshake, where we might have
retransmissions and fragments */
flow->max_extra_packets_to_check = ndpi_min(255, (int)flow->max_extra_packets_to_check + 10);
flow->stun.maybe_dtls = 1;
}

if(first_dtls_pkt &&
flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DTLS &&
flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN &&
old_proto_stack[0] != NDPI_PROTOCOL_UNKNOWN &&
old_proto_stack[0] != NDPI_PROTOCOL_STUN) {
NDPI_LOG_DBG(ndpi_struct, "Keeping old subclassification %d\n", old_proto_stack[0]);
ndpi_int_stun_add_connection(ndpi_struct, flow,
old_proto_stack[0] == NDPI_PROTOCOL_RTP ? NDPI_PROTOCOL_SRTP : old_proto_stack[0],
__get_master(flow));
}
switch_to_tls(ndpi_struct, flow, first_dtls_pkt);

/* If this is not a real DTLS packet, we need to restore the old state */
if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN &&
first_dtls_pkt) {
NDPI_LOG_DBG(ndpi_struct, "Switch to TLS failed. Rollback to old classification\n");
if(first_dtls_pkt &&
flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DTLS &&
flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN &&
old_proto_stack[0] != NDPI_PROTOCOL_UNKNOWN &&
old_proto_stack[0] != NDPI_PROTOCOL_STUN) {
NDPI_LOG_DBG(ndpi_struct, "Keeping old subclassification %d\n", old_proto_stack[0]);
ndpi_int_stun_add_connection(ndpi_struct, flow,
old_proto_stack[0] == NDPI_PROTOCOL_RTP ? NDPI_PROTOCOL_SRTP : old_proto_stack[0],
__get_master(flow));
}

ndpi_set_detected_protocol(ndpi_struct, flow,
old_proto_stack[0], old_proto_stack[1],
NDPI_CONFIDENCE_DPI);
/* If this is not a real DTLS packet, we need to restore the old state */
if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN &&
first_dtls_pkt) {
NDPI_LOG_DBG(ndpi_struct, "Switch to TLS failed. Rollback to old classification\n");

flow->stun.maybe_dtls = 0;
flow->max_extra_packets_to_check -= 10;
}
ndpi_set_detected_protocol(ndpi_struct, flow,
old_proto_stack[0], old_proto_stack[1],
NDPI_CONFIDENCE_DPI);

NDPI_LOG_DBG(ndpi_struct, "(%d/%d)\n",
flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]);
flow->stun.maybe_dtls = 0;
flow->max_extra_packets_to_check -= 10;
}

NDPI_LOG_DBG(ndpi_struct, "(%d/%d)\n",
flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]);
}
}
} else if(first_byte <= 79) {
Expand Down
17 changes: 10 additions & 7 deletions src/lib/protocols/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ static u_int32_t ndpi_tls_refine_master_protocol(struct ndpi_detection_module_st
u_int16_t sport = ntohs(packet->tcp->source);
u_int16_t dport = ntohs(packet->tcp->dest);

if((sport == 465) || (dport == 465) || (sport == 587) || (dport == 587))
if(flow->stun.maybe_dtls)
protocol = NDPI_PROTOCOL_DTLS;
else if((sport == 465) || (dport == 465) || (sport == 587) || (dport == 587))
protocol = NDPI_PROTOCOL_MAIL_SMTPS;
else if((sport == 993) || (dport == 993) || (flow->l4.tcp.mail_imap_starttls))
protocol = NDPI_PROTOCOL_MAIL_IMAPS;
Expand Down Expand Up @@ -770,7 +772,7 @@ void processCertificateElements(struct ndpi_detection_module_struct *ndpi_struct
int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
int is_dtls = packet->udp ? 1 : 0;
int is_dtls = packet->udp || flow->stun.maybe_dtls; /* No certificate with QUIC */
u_int32_t certificates_length, length = (packet->payload[1] << 16) + (packet->payload[2] << 8) + packet->payload[3];
u_int32_t certificates_offset = 7 + (is_dtls ? 8 : 0);
u_int8_t num_certificates_found = 0;
Expand Down Expand Up @@ -899,6 +901,7 @@ static int processTLSBlock(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
int ret;
int is_dtls = packet->udp || flow->stun.maybe_dtls;

#ifdef DEBUG_TLS
printf("[TLS] Processing block %u\n", packet->payload[0]);
Expand All @@ -918,11 +921,11 @@ static int processTLSBlock(struct ndpi_detection_module_struct *ndpi_struct,
(packet->payload[0] == 0x01) ? "Client" : "Server");
#endif

if((packet->tcp && flow->protos.tls_quic.ssl_version >= 0x0304 /* TLS 1.3 */)
if((!is_dtls && flow->protos.tls_quic.ssl_version >= 0x0304 /* TLS 1.3 */)
&& (packet->payload[0] == 0x02 /* Server Hello */)) {
flow->tls_quic.certificate_processed = 1; /* No Certificate with TLS 1.3+ */
}
if((packet->udp && flow->protos.tls_quic.ssl_version == 0xFEFC /* DTLS 1.3 */)
if((is_dtls && flow->protos.tls_quic.ssl_version == 0xFEFC /* DTLS 1.3 */)
&& (packet->payload[0] == 0x02 /* Server Hello */)) {
flow->tls_quic.certificate_processed = 1; /* No Certificate with DTLS 1.3+ */
}
Expand Down Expand Up @@ -1655,7 +1658,7 @@ static void ndpi_compute_ja4(struct ndpi_flow_struct *flow,
u_int16_t tls_handshake_version = ja->client.tls_handshake_version;
char * const ja_str = &flow->protos.tls_quic.ja4_client[0];
const u_int16_t ja_max_len = sizeof(flow->protos.tls_quic.ja4_client);
bool is_dtls = (flow->l4_proto == IPPROTO_UDP) && (quic_version == 0);
bool is_dtls = ((flow->l4_proto == IPPROTO_UDP) && (quic_version == 0)) || flow->stun.maybe_dtls;
/*
Compute JA4 TLS/QUIC client

Expand Down Expand Up @@ -1815,7 +1818,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t total_len;
u_int8_t handshake_type;
bool is_quic = (quic_version != 0);
bool is_dtls = packet->udp && (!is_quic);
bool is_dtls = (packet->udp && !is_quic) || flow->stun.maybe_dtls;

#ifdef DEBUG_TLS
printf("TLS %s() called\n", __FUNCTION__);
Expand Down Expand Up @@ -2964,7 +2967,7 @@ static void ndpi_search_tls_wrapper(struct ndpi_detection_module_struct *ndpi_st
flow->protos.tls_quic.ssl_version);
#endif

if(packet->udp != NULL)
if(packet->udp != NULL || flow->stun.maybe_dtls)
ndpi_search_tls_udp(ndpi_struct, flow);
else
ndpi_search_tls_tcp(ndpi_struct, flow);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Num dissector calls: 13 (6.50 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/0/0 (insert/search/found)
LRU cache stun: 42/0/0 (insert/search/found)
LRU cache tls_cert: 0/1/0 (insert/search/found)
LRU cache tls_cert: 0/2/0 (insert/search/found)
LRU cache mining: 0/0/0 (insert/search/found)
LRU cache msteams: 0/0/0 (insert/search/found)
LRU cache stun_zoom: 0/0/0 (insert/search/found)
Expand All @@ -28,7 +28,8 @@ Acceptable 102 26347 2
JA3 Host Stats:
IP Address # JA3C
1 192.168.12.156 1
2 192.168.12.182 1


1 TCP 192.168.12.182:50221 <-> 142.250.82.249:3478 [proto: 338.404/SRTP.GoogleCall][IP: 126/Google][Stream Content: Audio][Encrypted][Confidence: DPI][DPI packets: 63][cat: VoIP/10][28 pkts/3492 bytes <-> 35 pkts/14442 bytes][Goodput ratio: 56/87][0.89 sec][Hostname/SNI: turn.l.google.com][bytes ratio: -0.611 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 11/13 55/55 17/18][Pkt Len c2s/s2c min/avg/max/stddev: 54/54 125/413 250/1162 71/442][Mapped IP/Port: 10.13.0.62:15530][Peer IP/Port: 10.13.0.50:1259][Relayed IP/Port: 10.13.0.62:15530][PLAIN TEXT (Lvsrdelc)][Plen Bins: 2,2,12,15,21,10,2,0,0,0,5,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0]
1 TCP 192.168.12.182:50221 <-> 142.250.82.249:3478 [proto: 30.404/DTLS.GoogleCall][IP: 126/Google][Stream Content: Audio][Encrypted][Confidence: DPI][DPI packets: 63][cat: VoIP/10][28 pkts/3492 bytes <-> 35 pkts/14442 bytes][Goodput ratio: 56/87][0.89 sec][Hostname/SNI: turn.l.google.com][bytes ratio: -0.611 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 11/13 55/55 17/18][Pkt Len c2s/s2c min/avg/max/stddev: 54/54 125/413 250/1162 71/442][Mapped IP/Port: 10.13.0.62:15530][Peer IP/Port: 10.13.0.50:1259][Relayed IP/Port: 10.13.0.62:15530][Risk: ** TLS Cert About To Expire **][Risk Score: 50][Risk Info: 16/Mar/2024 12:47:23 - 16/Apr/2024 12:47:23][DTLSv1.2][JA3C: c14667d7da3e6f7a7ab5519ef78c2452][JA4: dd2d110700_c45550529adf_d9dd6182da81][JA3S: 717ecda0d920dc848680e6da69fb0468][Issuer: CN=WebRTC][Subject: CN=WebRTC][Certificate SHA-1: 33:D9:F2:88:62:62:B0:C4:A1:20:72:CA:BF:CF:E7:69:A0:9E:0F:94][Validity: 2024-03-16 12:47:23 - 2024-04-16 12:47:23][Cipher: TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256][PLAIN TEXT (Lvsrdelc)][Plen Bins: 2,2,12,15,21,10,2,0,0,0,5,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0]
2 UDP 192.168.12.156:37967 <-> 142.250.82.76:19305 [proto: 30.404/DTLS.GoogleCall][IP: 126/Google][Stream Content: Audio][Encrypted][Confidence: DPI][DPI packets: 39][cat: VoIP/10][25 pkts/4202 bytes <-> 14 pkts/4211 bytes][Goodput ratio: 75/86][0.88 sec][bytes ratio: -0.001 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 37/35 203/107 47/36][Pkt Len c2s/s2c min/avg/max/stddev: 103/82 168/301 587/1245 125/320][Mapped IP/Port: 93.35.171.3:61536][DTLSv1.2][JA3C: c14667d7da3e6f7a7ab5519ef78c2452][JA4: dd2d110700_c45550529adf_d9dd6182da81][JA3S: 1f5d6a6d0bc5d514dd84d13e6283d309][Issuer: CN=hangouts][Subject: CN=hangouts][Certificate SHA-1: AF:DD:BF:F5:59:23:0C:D1:B0:9F:B1:04:2E:89:DF:4C:1B:AB:BE:CC][Validity: 2022-11-30 17:35:18 - 2023-12-01 17:35:18][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256][PLAIN TEXT (ShSURJhNF)][Plen Bins: 0,5,47,30,2,0,0,0,0,0,0,0,0,2,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0]
Loading