From 0845f4896ac173bb2873c65d86300c2ac94d3892 Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Mon, 11 Apr 2022 16:51:35 +0200 Subject: [PATCH] Show HTTPS, IMAPS and SMTPS instead of TLS Such names are more user-friendly. Combine ALPN-based detection with guesses --- app/src/main/jni/core/CMakeLists.txt | 2 +- app/src/main/jni/core/jni_impl.c | 2 +- .../{ndpi_master_protos.c => ndpi_config.c} | 4 +- app/src/main/jni/core/pcapdroid.c | 56 ++++++++++++++++++- app/src/main/jni/core/pcapdroid.h | 6 +- 5 files changed, 62 insertions(+), 8 deletions(-) rename app/src/main/jni/core/{ndpi_master_protos.c => ndpi_config.c} (96%) diff --git a/app/src/main/jni/core/CMakeLists.txt b/app/src/main/jni/core/CMakeLists.txt index e83cbf96..54cdcb2b 100644 --- a/app/src/main/jni/core/CMakeLists.txt +++ b/app/src/main/jni/core/CMakeLists.txt @@ -5,7 +5,7 @@ add_library(capture SHARED capture_vpn.c capture_root.c ip_lru.c - ndpi_master_protos.c + ndpi_config.c crc32.c blacklist.c pcap_utils.c diff --git a/app/src/main/jni/core/jni_impl.c b/app/src/main/jni/core/jni_impl.c index 6872dd26..dd2a4597 100644 --- a/app/src/main/jni/core/jni_impl.c +++ b/app/src/main/jni/core/jni_impl.c @@ -159,7 +159,7 @@ static jobject getConnUpdate(pcapdroid_t *pd, const conn_and_tuple_t *conn) { if(data->update_type & CONN_UPDATE_INFO) { jobject info = (*env)->NewStringUTF(env, data->info ? data->info : ""); jobject url = (*env)->NewStringUTF(env, data->url ? data->url : ""); - jobject l7proto = (*env)->NewStringUTF(env, pd_get_proto_name(pd, data->l7proto, + jobject l7proto = (*env)->NewStringUTF(env, pd_get_proto_name(pd, data->l7proto, data->alpn, conn->tuple.ipproto)); int flags = data->encrypted_l7; diff --git a/app/src/main/jni/core/ndpi_master_protos.c b/app/src/main/jni/core/ndpi_config.c similarity index 96% rename from app/src/main/jni/core/ndpi_master_protos.c rename to app/src/main/jni/core/ndpi_config.c index 0c057484..e7235ae6 100644 --- a/app/src/main/jni/core/ndpi_master_protos.c +++ b/app/src/main/jni/core/ndpi_config.c @@ -20,8 +20,10 @@ #include "ndpi_api.h" #include "ndpi_protocol_ids.h" +/* ******************************************************* */ + // protocols which are not application protocols -void init_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b) { +void init_ndpi_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b) { NDPI_ZERO(b); // https://github.com/ntop/nDPI/blob/dev/src/include/ndpi_protocol_ids.h diff --git a/app/src/main/jni/core/pcapdroid.c b/app/src/main/jni/core/pcapdroid.c index 618e5664..e4542335 100644 --- a/app/src/main/jni/core/pcapdroid.c +++ b/app/src/main/jni/core/pcapdroid.c @@ -215,7 +215,7 @@ struct ndpi_detection_module_struct* init_ndpi() { return(NULL); // needed by pd_get_proto_name - init_protocols_bitmask(&masterProtos); + init_ndpi_protocols_bitmask(&masterProtos); #ifndef FUZZING // enable all the protocols @@ -231,6 +231,7 @@ struct ndpi_detection_module_struct* init_ndpi() { #endif ndpi_set_protocol_detection_bitmask2(ndpi, &protocols); + ndpi_finalize_initialization(ndpi); #ifdef FUZZING @@ -242,12 +243,26 @@ struct ndpi_detection_module_struct* init_ndpi() { /* ******************************************************* */ -const char* pd_get_proto_name(pcapdroid_t *pd, uint16_t proto, int ipproto) { +const char* pd_get_proto_name(pcapdroid_t *pd, uint16_t proto, uint16_t alpn, int ipproto) { if(proto == NDPI_PROTOCOL_UNKNOWN) { // Return the L3 protocol return zdtun_proto2str(ipproto); } + if(proto == NDPI_PROTOCOL_TLS) { + switch (alpn) { + case NDPI_PROTOCOL_HTTP: + return "HTTPS"; + case NDPI_PROTOCOL_MAIL_IMAP: + return "IMAPS"; + case NDPI_PROTOCOL_MAIL_SMTP: + return "SMTPS"; + default: + // go on + break; + } + } + return ndpi_get_proto_name(pd->ndpi, proto); } @@ -438,6 +453,23 @@ static void process_ndpi_data(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_c switch(data->l7proto) { case NDPI_PROTOCOL_TLS: + // ALPN extension in client hello (https://datatracker.ietf.org/doc/html/rfc7301) + if(!data->alpn && data->ndpi_flow->protos.tls_quic.alpn) { + if(strstr(data->ndpi_flow->protos.tls_quic.alpn, "http/")) { + data->alpn = NDPI_PROTOCOL_HTTP; + data->update_type |= CONN_UPDATE_INFO; + } else if(strstr(data->ndpi_flow->protos.tls_quic.alpn, "imap")) { + data->alpn = NDPI_PROTOCOL_MAIL_IMAP; + data->update_type |= CONN_UPDATE_INFO; + } else if(strstr(data->ndpi_flow->protos.tls_quic.alpn, "stmp")) { + data->alpn = NDPI_PROTOCOL_MAIL_SMTP; + data->update_type |= CONN_UPDATE_INFO; + } else { + log_d("Unknown ALPN: %s", data->ndpi_flow->protos.tls_quic.alpn); + data->alpn = NDPI_PROTOCOL_TLS; // mark to avoid port-based guessing + } + } + /* fallthrough */ case NDPI_PROTOCOL_DNS: if(data->ndpi_flow->host_server_name[0]) found_info = (char*)data->ndpi_flow->host_server_name; @@ -481,7 +513,8 @@ void pd_giveup_dpi(pcapdroid_t *pd, pd_conn_t *data, const zdtun_5tuple_t *tuple data->encrypted_l7 = is_encrypted_l7(pd->ndpi, data->l7proto); } - log_d("nDPI completed[ipver=%d, proto=%d] -> l7proto: %d", + log_d("nDPI completed[pkts=%d, ipver=%d, proto=%d] -> l7proto: %d", + data->sent_pkts + data->rcvd_pkts, tuple->ipver, tuple->ipproto, data->l7proto); process_ndpi_data(pd, tuple, data); @@ -639,6 +672,23 @@ static void perform_dpi(pcapdroid_t *pd, pkt_context_t *pctx) { } netd_resolve_waiting++; } + + if(!data->ndpi_flow) { + // nDPI detection complete + if((data->l7proto == NDPI_PROTOCOL_TLS) && (!data->alpn)) { + if(ntohs(pctx->tuple->dst_port) == 443) + data->alpn = NDPI_PROTOCOL_HTTP; // assume HTTPS + else if(data->info && !strncmp(data->info, "imap.", 5)) + data->alpn = NDPI_PROTOCOL_MAIL_IMAP; // assume IMAPS + else if(data->info && !strncmp(data->info, "smtp.", 5)) + data->alpn = NDPI_PROTOCOL_MAIL_SMTP; // assume SMTPS + + if(data->alpn) { + data->update_type |= CONN_UPDATE_INFO; + pd_notify_connection_update(pd, pctx->tuple, data); + } + } + } } /* ******************************************************* */ diff --git a/app/src/main/jni/core/pcapdroid.h b/app/src/main/jni/core/pcapdroid.h index f7846fda..86643e10 100644 --- a/app/src/main/jni/core/pcapdroid.h +++ b/app/src/main/jni/core/pcapdroid.h @@ -73,6 +73,7 @@ typedef struct { struct ndpi_flow_struct *ndpi_flow; struct ndpi_id_struct *src_id, *dst_id; uint16_t l7proto; + uint16_t alpn; union { struct { @@ -359,7 +360,7 @@ pd_conn_t* pd_new_connection(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, int u void pd_purge_connection(pcapdroid_t *pd, pd_conn_t *data); void pd_notify_connection_update(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn_t *data); void pd_giveup_dpi(pcapdroid_t *pd, pd_conn_t *data, const zdtun_5tuple_t *tuple); -const char* pd_get_proto_name(pcapdroid_t *pd, uint16_t proto, int ipproto); +const char* pd_get_proto_name(pcapdroid_t *pd, uint16_t proto, uint16_t alpn, int ipproto); // Utility const char* get_cache_path(pcapdroid_t *pd, const char *subpath); @@ -381,7 +382,8 @@ void getApplicationByUid(pcapdroid_t *pd, jint uid, char *buf, int bufsize); // Internals struct pcapdroid_trailer; void fill_custom_data(struct pcapdroid_trailer *cdata, pcapdroid_t *pd, pd_conn_t *conn); -void init_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b); +void init_ndpi_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b); +void load_ndpi_hosts(struct ndpi_detection_module_struct *ndpi); uint32_t crc32(u_char *buf, size_t len, uint32_t crc); #endif //__PCAPDROID_H__