diff options
author | Nardi Ivan <nardi.ivan@gmail.com> | 2024-06-25 12:16:09 +0200 |
---|---|---|
committer | Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> | 2024-06-25 16:39:45 +0200 |
commit | 556f892a56d57e1afadb91fd5a12078cb3e2e5dc (patch) | |
tree | 20300d0fc76394bc9dd3a4d6b0d472751c9fb3a5 /example/ndpiReader.c | |
parent | f44832cc51400f7ede9343cb1847f4c242c5ddc9 (diff) |
wireshark: lua: export some metadata
Export some metadata (for the moment, SNI and TLS fingerprints) to
Wireshark/tshark via extcap.
Note that:
* metadata are exported only once per flow
* metadata are exported (all together) when nDPI stopped processing
the flow
Still room for a lot of improvements!
In particular:
* we need to add some boundary checks (if we are going to export other
attributes)
* we should try to have a variable length trailer
Diffstat (limited to 'example/ndpiReader.c')
-rw-r--r-- | example/ndpiReader.c | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index ed6ed79e8..fca7e3e94 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -216,6 +216,18 @@ struct receiver { struct receiver *receivers = NULL, *topReceivers = NULL; #define WIRESHARK_NTOP_MAGIC 0x19680924 +#define WIRESHARK_METADATA_SIZE 256 + +#define WIRESHARK_METADATA_SERVERNAME 0x01 +#define WIRESHARK_METADATA_JA3C 0x02 +#define WIRESHARK_METADATA_JA3S 0x03 +#define WIRESHARK_METADATA_JA4C 0x04 + +struct ndpi_packet_tlv { + u_int16_t type; + u_int16_t length; + unsigned char data[]; +}; PACK_ON struct ndpi_packet_trailer { @@ -224,6 +236,9 @@ struct ndpi_packet_trailer { ndpi_risk flow_risk; u_int16_t flow_score; char name[16]; + /* TLV of attributes. Having a max and fixed size for all the metadata + is not efficient but greatly improves detection of the trailer by Wireshark */ + unsigned char metadata[WIRESHARK_METADATA_SIZE]; } PACK_OFF; static pcap_dumper_t *extcap_dumper = NULL; @@ -4424,6 +4439,7 @@ static void ndpi_process_packet(u_char *args, const u_char *packet) { struct ndpi_proto p; ndpi_risk flow_risk; + struct ndpi_flow_info *flow; u_int16_t thread_id = *((u_int16_t*)args); /* allocate an exact size buffer to check overflows */ @@ -4434,7 +4450,7 @@ static void ndpi_process_packet(u_char *args, } memcpy(packet_checked, packet, header->caplen); - p = ndpi_workflow_process_packet(ndpi_thread_info[thread_id].workflow, header, packet_checked, &flow_risk); + p = ndpi_workflow_process_packet(ndpi_thread_info[thread_id].workflow, header, packet_checked, &flow_risk, &flow); if(!pcap_start.tv_sec) pcap_start.tv_sec = header->ts.tv_sec, pcap_start.tv_usec = header->ts.tv_usec; pcap_end.tv_sec = header->ts.tv_sec, pcap_end.tv_usec = header->ts.tv_usec; @@ -4495,6 +4511,57 @@ static void ndpi_process_packet(u_char *args, trailer->flow_score = htons(ndpi_risk2score(flow_risk, &cli_score, &srv_score)); trailer->master_protocol = htons(p.master_protocol), trailer->app_protocol = htons(p.app_protocol); ndpi_protocol2name(ndpi_thread_info[thread_id].workflow->ndpi_struct, p, trailer->name, sizeof(trailer->name)); + + /* Metadata */ + /* Metadata are (all) available in `flow` only after nDPI completed its work! + We export them only once */ + /* TODO: boundary check. Right now there is always enough room, but we should check it if we are + going to extend the list of the metadata exported */ + struct ndpi_packet_tlv *tlv = (struct ndpi_packet_tlv *)trailer->metadata; + int tot_len = 0; + if(flow && flow->detection_completed == 1) { + if(flow->host_server_name[0] != '\0') { + tlv->type = ntohs(WIRESHARK_METADATA_SERVERNAME); + tlv->length = ntohs(sizeof(flow->host_server_name)); + memcpy(tlv->data, flow->host_server_name, sizeof(flow->host_server_name)); + /* TODO: boundary check */ + tot_len += 4 + htons(tlv->length); + tlv = (struct ndpi_packet_tlv *)&trailer->metadata[tot_len]; + } + if(flow->ssh_tls.ja3_client[0] != '\0') { + tlv->type = ntohs(WIRESHARK_METADATA_JA3C); + tlv->length = ntohs(sizeof(flow->ssh_tls.ja3_client)); + memcpy(tlv->data, flow->ssh_tls.ja3_client, sizeof(flow->ssh_tls.ja3_client)); + /* TODO: boundary check */ + tot_len += 4 + htons(tlv->length); + tlv = (struct ndpi_packet_tlv *)&trailer->metadata[tot_len]; + } + if(flow->ssh_tls.ja3_server[0] != '\0') { + tlv->type = ntohs(WIRESHARK_METADATA_JA3S); + tlv->length = ntohs(sizeof(flow->ssh_tls.ja3_server)); + memcpy(tlv->data, flow->ssh_tls.ja3_server, sizeof(flow->ssh_tls.ja3_server)); + /* TODO: boundary check */ + tot_len += 4 + htons(tlv->length); + tlv = (struct ndpi_packet_tlv *)&trailer->metadata[tot_len]; + } + if(flow->ssh_tls.ja4_client[0] != '\0') { + tlv->type = ntohs(WIRESHARK_METADATA_JA4C); + tlv->length = ntohs(sizeof(flow->ssh_tls.ja4_client)); + memcpy(tlv->data, flow->ssh_tls.ja4_client, sizeof(flow->ssh_tls.ja4_client)); + /* TODO: boundary check */ + tot_len += 4 + htons(tlv->length); + tlv = (struct ndpi_packet_tlv *)&trailer->metadata[tot_len]; + } + + flow->detection_completed = 2; /* Avoid exporting metadata again. + If we really want to have the metadata on Wireshark for *all* + the future packets of this flow, simply remove that assignment */ + } + /* Last: padding */ + tlv->type = 0; + tlv->length = ntohs(WIRESHARK_METADATA_SIZE - tot_len - 4); + /* The remaining bytes are already set to 0 */ + crc = (uint32_t*)&extcap_buf[h.caplen+sizeof(struct ndpi_packet_trailer)]; *crc = ndpi_crc32((const void*)extcap_buf, h.caplen+sizeof(struct ndpi_packet_trailer)); h.caplen += delta, h.len += delta; |