Skip to content

Commit 6b6dad4

Browse files
committed
Implemented nDPI TCP fingerprint
1 parent ff14b36 commit 6b6dad4

File tree

7 files changed

+414
-96
lines changed

7 files changed

+414
-96
lines changed

example/ndpiReader.c

+3
Original file line numberDiff line numberDiff line change
@@ -2056,6 +2056,9 @@ static void printFlow(u_int32_t id, struct ndpi_flow_info *flow, u_int16_t threa
20562056
fprintf(out, "[Risk Info: %s]", flow->risk_str);
20572057
}
20582058

2059+
if(flow->tcp_fingerprint)
2060+
fprintf(out, "[TCP Fingerprint: %s]", flow->tcp_fingerprint);
2061+
20592062
if(flow->ssh_tls.ssl_version != 0) fprintf(out, "[%s]", ndpi_ssl_version2str(buf_ver, sizeof(buf_ver),
20602063
flow->ssh_tls.ssl_version, &known_tls));
20612064

example/reader_util.c

+18-14
Original file line numberDiff line numberDiff line change
@@ -609,8 +609,9 @@ void ndpi_flow_info_free_data(struct ndpi_flow_info *flow) {
609609
ndpi_free_bin(&flow->payload_len_bin);
610610
#endif
611611

612-
if(flow->risk_str) ndpi_free(flow->risk_str);
613-
if(flow->flow_payload) ndpi_free(flow->flow_payload);
612+
if(flow->tcp_fingerprint) ndpi_free(flow->tcp_fingerprint);
613+
if(flow->risk_str) ndpi_free(flow->risk_str);
614+
if(flow->flow_payload) ndpi_free(flow->flow_payload);
614615
}
615616

616617
/* ***************************************************** */
@@ -623,7 +624,7 @@ void ndpi_workflow_free(struct ndpi_workflow * workflow) {
623624

624625
if(addr_dump_path != NULL)
625626
ndpi_cache_address_dump(workflow->ndpi_struct, addr_dump_path, 0);
626-
627+
627628
ndpi_exit_detection_module(workflow->ndpi_struct);
628629
ndpi_free(workflow->ndpi_flows_root);
629630
ndpi_free(workflow);
@@ -1131,7 +1132,7 @@ static void dump_flow_fingerprint(struct ndpi_workflow * workflow,
11311132

11321133
if(flow->server_hostname)
11331134
ndpi_serialize_string_string(&serializer, "server_hostname", flow->server_hostname);
1134-
1135+
11351136
buffer = ndpi_serializer_get_buffer(&serializer, &buffer_len);
11361137
fprintf(fingerprint_fp, "%s\n", buffer);
11371138
}
@@ -1408,24 +1409,24 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
14081409
/* For consistency across platforms replace :0: with :: */
14091410
ndpi_patchIPv6Address(flow->info);
14101411
}
1411-
1412+
14121413
if(flow->ndpi_flow->protos.dns.geolocation_iata_code[0] != '\0')
14131414
strcpy(flow->dns.geolocation_iata_code, flow->ndpi_flow->protos.dns.geolocation_iata_code);
14141415

14151416
if(0) {
14161417
u_int8_t i;
1417-
1418+
14181419
for(i=0; i<flow->ndpi_flow->protos.dns.num_rsp_addr; i++) {
14191420
char buf[64];
1420-
1421+
14211422
if(flow->ndpi_flow->protos.dns.is_rsp_addr_ipv6[i] == 0) {
14221423
inet_ntop(AF_INET, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv4, buf, sizeof(buf));
14231424
} else {
1424-
inet_ntop(AF_INET6, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv6, buf, sizeof(buf));
1425+
inet_ntop(AF_INET6, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv6, buf, sizeof(buf));
14251426
}
14261427

14271428
printf("(%s) %s [ttl: %u]\n", flow->host_server_name, buf, flow->ndpi_flow->protos.dns.rsp_addr_ttl[i]);
1428-
}
1429+
}
14291430
}
14301431
}
14311432
/* MDNS */
@@ -1520,7 +1521,7 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
15201521

15211522
if(flow->ndpi_flow->protos.tls_quic.ja4_client_raw)
15221523
flow->ssh_tls.ja4_client_raw = strdup(flow->ndpi_flow->protos.tls_quic.ja4_client_raw);
1523-
1524+
15241525
ndpi_snprintf(flow->ssh_tls.ja3_server, sizeof(flow->ssh_tls.ja3_server), "%s",
15251526
flow->ndpi_flow->protos.tls_quic.ja3_server);
15261527
flow->ssh_tls.server_unsafe_cipher = flow->ndpi_flow->protos.tls_quic.server_unsafe_cipher;
@@ -1585,6 +1586,9 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
15851586

15861587
flow->multimedia_flow_type = flow->ndpi_flow->flow_multimedia_type;
15871588

1589+
if(flow->ndpi_flow->tcp.fingerprint)
1590+
flow->tcp_fingerprint = ndpi_strdup(flow->ndpi_flow->tcp.fingerprint);
1591+
15881592
/* HTTP metadata are "global" not in `flow->ndpi_flow->protos` union; for example, we can have
15891593
HTTP/BitTorrent and in that case we want to export also HTTP attributes */
15901594
if(is_ndpi_proto(flow, NDPI_PROTOCOL_HTTP)
@@ -1608,16 +1612,16 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
16081612
{
16091613
ndpi_ip_addr_t ip_addr;
16101614
struct ndpi_address_cache_item *c;
1611-
1615+
16121616
memset(&ip_addr, 0, sizeof(ip_addr));
1613-
1617+
16141618
if(flow->ip_version == 4)
16151619
ip_addr.ipv4 = flow->dst_ip;
16161620
else
16171621
memcpy(&ip_addr.ipv6, &flow->dst_ip6, sizeof(struct ndpi_in6_addr));
16181622

16191623
c = ndpi_cache_address_find(workflow->ndpi_struct, ip_addr);
1620-
1624+
16211625
if(c) {
16221626
flow->server_hostname = ndpi_strdup(c->hostname);
16231627
}
@@ -2205,7 +2209,7 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow,
22052209
/* At the first packet flush expired cached addresses */
22062210
ndpi_cache_address_flush_expired(workflow->ndpi_struct, header->ts.tv_sec);
22072211
}
2208-
2212+
22092213
/* Increment raw packet counter */
22102214
workflow->stats.raw_packet_count++;
22112215

example/reader_util.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ typedef struct ndpi_flow_info {
324324
ndpi_multimedia_flow_type multimedia_flow_type;
325325

326326
void *src_id, *dst_id;
327-
327+
char *tcp_fingerprint;
328328
struct ndpi_entropy *entropy;
329329
struct ndpi_entropy *last_entropy;
330330

src/include/ndpi_typedefs.h

+4
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,10 @@ struct ndpi_flow_struct {
13121312
ndpi_risk risk, risk_shadow; /* Issues found with this flow [bitmask of ndpi_risk] */
13131313
struct ndpi_risk_information risk_infos[MAX_NUM_RISK_INFOS]; /* String that contains information about the risks found */
13141314
u_int8_t num_risk_infos;
1315+
1316+
struct {
1317+
char *fingerprint;
1318+
} tcp;
13151319

13161320
/*
13171321
This structure below will not not stay inside the protos

src/lib/ndpi_main.c

+86-10
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
#define TH_PUSH 0x08
6161
#define TH_ACK 0x10
6262
#define TH_URG 0x20
63+
#define TH_ECE 0x40
64+
#define TH_CWR 0x80
6365
#endif
6466

6567
#if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
@@ -4400,7 +4402,7 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) {
44004402

44014403
if(ndpi_str->address_cache)
44024404
ndpi_term_address_cache(ndpi_str->address_cache);
4403-
4405+
44044406
ndpi_free(ndpi_str);
44054407
}
44064408

@@ -4794,7 +4796,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str,
47944796
def = NULL;
47954797
else
47964798
def = &ndpi_str->proto_defaults[subprotocol_id];
4797-
4799+
47984800
if(def == NULL) {
47994801
ndpi_port_range ports_a[MAX_DEFAULT_PORTS], ports_b[MAX_DEFAULT_PORTS];
48004802
char *equal = strchr(proto, '=');
@@ -6724,6 +6726,9 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) {
67246726
ndpi_free(flow->risk_infos[i].info);
67256727
}
67266728

6729+
if(flow->tcp.fingerprint)
6730+
ndpi_free(flow->tcp.fingerprint);
6731+
67276732
if(flow->http.url)
67286733
ndpi_free(flow->http.url);
67296734

@@ -6904,14 +6909,86 @@ static int ndpi_init_packet(struct ndpi_detection_module_struct *ndpi_str,
69046909

69056910
/* TCP / UDP detection */
69066911
if(l4protocol == IPPROTO_TCP) {
6912+
u_int16_t header_len;
6913+
69076914
if(l4_packet_len < 20 /* min size of tcp */)
69086915
return(1);
69096916

69106917
/* tcp */
69116918
packet->tcp = (struct ndpi_tcphdr *) l4ptr;
6912-
if(l4_packet_len >= packet->tcp->doff * 4) {
6913-
packet->payload_packet_len = l4_packet_len - packet->tcp->doff * 4;
6914-
packet->payload = ((u_int8_t *) packet->tcp) + (packet->tcp->doff * 4);
6919+
header_len = packet->tcp->doff * 4;
6920+
6921+
if(l4_packet_len >= header_len) {
6922+
if(flow->tcp.fingerprint == NULL) {
6923+
u_int8_t *t = (u_int8_t*)packet->tcp;
6924+
u_int16_t flags = ntohs(*((u_int16_t*)&t[12]));
6925+
6926+
if((flags & (TH_SYN | TH_ECE | TH_CWR)) == TH_SYN) {
6927+
u_int8_t *options = (u_int8_t*)(&t[sizeof(struct ndpi_tcphdr)]);
6928+
char fingerprint[128], options_fp[128];
6929+
u_int8_t i, fp_idx = 0, options_fp_idx = 0;
6930+
u_int8_t options_len = header_len - sizeof(struct ndpi_tcphdr);
6931+
u_int16_t tcp_win = ntohs(packet->tcp->window);
6932+
u_int8_t ip_ttl;
6933+
u_int8_t sha_hash[NDPI_SHA256_BLOCK_SIZE];
6934+
6935+
if(packet->iph)
6936+
ip_ttl = packet->iph->ttl;
6937+
else
6938+
ip_ttl = packet->iphv6->ip6_hdr.ip6_un1_hlim;
6939+
6940+
if(ip_ttl <= 32) ip_ttl = 32;
6941+
else if(ip_ttl <= 64) ip_ttl = 64;
6942+
else if(ip_ttl <= 128) ip_ttl = 128;
6943+
else if(ip_ttl <= 192) ip_ttl = 192;
6944+
else ip_ttl = 255;
6945+
6946+
fp_idx = snprintf(fingerprint, sizeof(fingerprint), "%u_%u_", ip_ttl, tcp_win);
6947+
6948+
for(i=0; i<options_len; ) {
6949+
u_int8_t kind = options[i];
6950+
int rc;
6951+
6952+
rc = snprintf(&options_fp[options_fp_idx], sizeof(options_fp)-options_fp_idx, "%02x", kind);
6953+
options_fp_idx += rc;
6954+
6955+
if(kind == 0) /* EOF */
6956+
break;
6957+
else if(kind == 1) /* NOP */
6958+
i++;
6959+
else {
6960+
u_int8_t len = options[i+1];
6961+
6962+
if(len == 0)
6963+
break;
6964+
else if(kind == 8) {
6965+
/* Timestamp: ignore it */
6966+
} else {
6967+
int j = i+2;
6968+
u_int8_t opt_len = len - 2;
6969+
6970+
while(opt_len > 0) {
6971+
rc = snprintf(&options_fp[options_fp_idx], sizeof(options_fp)-options_fp_idx, "%02x", options[j]);
6972+
options_fp_idx += rc;
6973+
j++, opt_len--;
6974+
}
6975+
}
6976+
6977+
i += len;
6978+
}
6979+
} /* for */
6980+
6981+
ndpi_sha256((const u_char*)options_fp, options_fp_idx, sha_hash);
6982+
snprintf(&fingerprint[fp_idx], sizeof(fingerprint)-fp_idx, "%02x%02x%02x%02x%02x%02x",
6983+
sha_hash[0], sha_hash[1], sha_hash[2],
6984+
sha_hash[3], sha_hash[4], sha_hash[5]);
6985+
6986+
flow->tcp.fingerprint = ndpi_strdup(fingerprint);
6987+
}
6988+
}
6989+
6990+
packet->payload_packet_len = l4_packet_len - header_len;
6991+
packet->payload = ((u_int8_t *) packet->tcp) + header_len;
69156992
} else {
69166993
/* tcp header not complete */
69176994
return(1);
@@ -7546,7 +7623,7 @@ static void ndpi_reconcile_msteams_udp(struct ndpi_detection_module_struct *ndpi
75467623
struct ndpi_flow_struct *flow,
75477624
u_int16_t master) {
75487625
/* This function can NOT access &ndpi_str->packet since it is called also from ndpi_detection_giveup(), via ndpi_reconcile_protocols() */
7549-
7626+
75507627
if(flow->l4_proto == IPPROTO_UDP) {
75517628
u_int16_t sport = ntohs(flow->c_port);
75527629
u_int16_t dport = ntohs(flow->s_port);
@@ -7694,7 +7771,7 @@ static void ndpi_reconcile_protocols(struct ndpi_detection_module_struct *ndpi_s
76947771
NDPI_CONFIDENCE_DPI_PARTIAL);
76957772
}
76967773
break;
7697-
7774+
76987775
case NDPI_PROTOCOL_SKYPE_TEAMS:
76997776
case NDPI_PROTOCOL_SKYPE_TEAMS_CALL:
77007777
if(flow->l4_proto == IPPROTO_UDP && ndpi_str->msteams_cache) {
@@ -9066,8 +9143,7 @@ struct header_line {
90669143
struct ndpi_int_one_line_struct *line;
90679144
};
90689145

9069-
static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_str)
9070-
{
9146+
static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_str) {
90719147
struct ndpi_packet_struct *packet = &ndpi_str->packet;
90729148
struct ndpi_int_one_line_struct *line;
90739149
size_t length;
@@ -11366,7 +11442,7 @@ static const struct cfg_param {
1136611442
{ "tls", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_subclassification_enabled), NULL },
1136711443

1136811444
{ "quic", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(quic_subclassification_enabled), NULL },
11369-
11445+
1137011446
{ "smtp", "tls_dissection", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(smtp_opportunistic_tls_enabled), NULL },
1137111447

1137211448
{ "imap", "tls_dissection", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(imap_opportunistic_tls_enabled), NULL },

src/lib/ndpi_utils.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -1651,7 +1651,11 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
16511651

16521652
ndpi_serialize_string_uint32(serializer, "ip", ip_version);
16531653

1654-
ndpi_serialize_string_string(serializer, "proto", ndpi_get_ip_proto_name(l4_protocol, l4_proto_name, sizeof(l4_proto_name)));
1654+
if(flow->tcp.fingerprint)
1655+
ndpi_serialize_string_string(serializer, "tcp_fingerprint", flow->tcp.fingerprint);
1656+
1657+
ndpi_serialize_string_string(serializer, "proto",
1658+
ndpi_get_ip_proto_name(l4_protocol, l4_proto_name, sizeof(l4_proto_name)));
16551659

16561660
return(ndpi_dpi2json(ndpi_struct, flow, l7_protocol, serializer));
16571661
}

0 commit comments

Comments
 (0)