@@ -67,9 +67,9 @@ static int hf_ja4h_raw_original = -1;
6767static int hf_ja4l = -1 ;
6868static int hf_ja4ls = -1 ;
6969static int hf_ja4ssh = -1 ;
70-
7170static int hf_ja4t = -1 ;
7271static int hf_ja4ts = -1 ;
72+ static int hf_ja4d = -1 ;
7373
7474static int dissect_ja4 (tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * dummy );
7575
@@ -90,7 +90,7 @@ const value_string ssl_versions[] = {
9090 {0x00 , NULL }
9191};
9292
93- #define HFIDS 53
93+ #define HFIDS 61
9494const char * interesting_hfids [HFIDS ] = {
9595 "tls.handshake.type" ,
9696 "dtls.handshake.type" ,
@@ -144,7 +144,15 @@ const char *interesting_hfids[HFIDS] = {
144144 "frame.time_epoch" ,
145145 "frame.time_delta_displayed" ,
146146 "ssh.direction" ,
147- "quic.long.packet_type"
147+ "quic.long.packet_type" ,
148+ "dhcp.option.dhcp" ,
149+ "dhcp.option.dhcp_max_message_size" ,
150+ "dhcp.option.type" ,
151+ "dhcp.option.request_list_item" ,
152+ "dhcpv6.msgtype" ,
153+ "dhcpv6.duid.bytes" ,
154+ "dhcpv6.option.type" ,
155+ "dhcpv6.requested_option_code" ,
148156};
149157
150158typedef struct {
@@ -189,6 +197,14 @@ typedef struct {
189197 int window_size ;
190198} ja4t_info_t ;
191199
200+ typedef struct {
201+ gchar proto ;
202+ guint32 type ;
203+ wmem_strbuf_t * size ;
204+ wmem_strbuf_t * options ;
205+ wmem_strbuf_t * request_list ;
206+ } ja4d_info_t ;
207+
192208typedef struct {
193209 int stream ;
194210
@@ -589,6 +605,25 @@ char *ja4t(ja4t_info_t *data, conn_info_t *conn) {
589605 return (char * )wmem_strbuf_get_str (display );
590606}
591607
608+ char * ja4d (ja4d_info_t * data ) {
609+ wmem_strbuf_t * display = wmem_strbuf_new (wmem_file_scope (), "" );
610+ if (wmem_strbuf_get_len (data -> size ) == 0 )
611+ wmem_strbuf_append_printf (data -> size , "00" );
612+ if (wmem_strbuf_get_len (data -> options ) == 0 )
613+ wmem_strbuf_append_printf (data -> options , "00" );
614+ if (wmem_strbuf_get_len (data -> request_list ) == 0 )
615+ wmem_strbuf_append_printf (data -> request_list , "00" );
616+ wmem_strbuf_append_printf (
617+ display , "%c-%d-%s_%s_%s" ,
618+ data -> proto ,
619+ data -> type ,
620+ wmem_strbuf_get_str (data -> size ),
621+ wmem_strbuf_get_str (data -> options ),
622+ wmem_strbuf_get_str (data -> request_list )
623+ );
624+ return (char * )wmem_strbuf_get_str (display );
625+ }
626+
592627static void init_ja4_data (packet_info * pinfo , ja4_info_t * ja4_data ) {
593628 ja4_data -> version = 0 ;
594629 ja4_data -> ext_len = 0 ;
@@ -672,6 +707,7 @@ static void set_ja4_ciphers(proto_tree *tree, ja4_info_t *data) {
672707static int dissect_ja4 (tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * dummy _U_ ) {
673708 guint32 handshake_type = 0 ;
674709 gboolean alpn_visited = false;
710+ gboolean dhcpv6_option_type_1_exists = false;
675711 proto_tree * ja4_tree = NULL ;
676712
677713 // For JA4C/S, record signature algorithms only when extension type == 13
@@ -704,18 +740,9 @@ static int dissect_ja4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
704740 return tvb_captured_length (tvb );
705741
706742 ja4_info_t ja4_data ;
707- ja4h_info_t ja4h_data ;
708-
709743 init_ja4_data (pinfo , & ja4_data );
710744
711- // JA4T data
712- ja4t_info_t ja4t_data ;
713- ja4t_data .tcp_options = wmem_strbuf_new (wmem_file_scope (), "" );
714- ja4t_data .mss_val = 0 ;
715- ja4t_data .window_scale = 0 ;
716- ja4t_data .window_size = 0 ;
717- // End of JA4T data
718-
745+ ja4h_info_t ja4h_data ;
719746 ja4h_data .version = wmem_strbuf_new (pinfo -> pool , "" );
720747 ja4h_data .headers = wmem_strbuf_new (pinfo -> pool , "" );
721748 ja4h_data .lang = wmem_strbuf_new (pinfo -> pool , "" );
@@ -730,6 +757,19 @@ static int dissect_ja4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
730757 ja4h_data .sorted_cookie_fields = wmem_strbuf_new (pinfo -> pool , "" );
731758 ja4h_data .sorted_cookie_values = wmem_strbuf_new (pinfo -> pool , "" );
732759
760+ ja4t_info_t ja4t_data ;
761+ ja4t_data .tcp_options = wmem_strbuf_new (wmem_file_scope (), "" );
762+ ja4t_data .mss_val = 0 ;
763+ ja4t_data .window_scale = 0 ;
764+ ja4t_data .window_size = 0 ;
765+
766+ ja4d_info_t ja4d_data ;
767+ ja4d_data .proto = 0 ;
768+ ja4d_data .type = 0 ;
769+ ja4d_data .size = wmem_strbuf_new (pinfo -> pool , "" );
770+ ja4d_data .options = wmem_strbuf_new (pinfo -> pool , "" );
771+ ja4d_data .request_list = wmem_strbuf_new (pinfo -> pool , "" );
772+
733773 char * proto = "tls" ;
734774 switch (ja4_data .proto ) {
735775 case 'q' : {
@@ -1267,6 +1307,56 @@ static int dissect_ja4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
12671307 wmem_map_new (wmem_file_scope (), g_direct_hash , g_direct_equal );
12681308 }
12691309 }
1310+
1311+ // JA4D processing
1312+
1313+ // DHCPv4
1314+ if (strcmp (field -> hfinfo -> abbrev , "dhcp.option.dhcp" ) == 0 ) {
1315+ ja4d_data .proto = '4' ;
1316+ ja4d_data .type = fvalue_get_uinteger (get_value_ptr (field ));
1317+ }
1318+ if (strcmp (field -> hfinfo -> abbrev , "dhcp.option.dhcp_max_message_size" ) == 0 ) {
1319+ wmem_strbuf_append_printf (
1320+ ja4d_data .size , "%d" , fvalue_get_uinteger (get_value_ptr (field ))
1321+ );
1322+ }
1323+ if (strcmp (field -> hfinfo -> abbrev , "dhcp.option.type" ) == 0 ) {
1324+ guint val = fvalue_get_uinteger (get_value_ptr (field ));
1325+ if (val != 0 && val != 53 ) {
1326+ wmem_strbuf_append_printf (ja4d_data .options , "%d-" , val );
1327+ }
1328+ }
1329+ if (strcmp (field -> hfinfo -> abbrev , "dhcp.option.request_list_item" ) == 0 ) {
1330+ wmem_strbuf_append_printf (
1331+ ja4d_data .request_list , "%d-" , fvalue_get_uinteger (get_value_ptr (field ))
1332+ );
1333+ }
1334+
1335+ // DHCPv6
1336+ if (strcmp (field -> hfinfo -> abbrev , "dhcpv6.msgtype" ) == 0 ) {
1337+ ja4d_data .proto = '6' ;
1338+ ja4d_data .type = fvalue_get_uinteger (get_value_ptr (field ));
1339+ }
1340+ if (strcmp (field -> hfinfo -> abbrev , "dhcpv6.duid.bytes" ) == 0 &&
1341+ wmem_strbuf_get_len (ja4d_data .size ) == 0 &&
1342+ dhcpv6_option_type_1_exists == true) {
1343+ wmem_strbuf_append_printf (
1344+ ja4d_data .size , "%d" , field -> length
1345+ );
1346+ }
1347+ if (strcmp (field -> hfinfo -> abbrev , "dhcpv6.option.type" ) == 0 ) {
1348+ guint val = fvalue_get_uinteger (get_value_ptr (field ));
1349+ if (val == 1 )
1350+ dhcpv6_option_type_1_exists = true;
1351+ wmem_strbuf_append_printf (
1352+ ja4d_data .options , "%d-" , val
1353+ );
1354+ }
1355+ if (strcmp (field -> hfinfo -> abbrev , "dhcpv6.requested_option_code" ) == 0 ) {
1356+ wmem_strbuf_append_printf (
1357+ ja4d_data .request_list , "%d-" , fvalue_get_uinteger (get_value_ptr (field ))
1358+ );
1359+ }
12701360 }
12711361 g_ptr_array_free (items , TRUE);
12721362 }
@@ -1351,6 +1441,18 @@ static int dissect_ja4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
13511441 );
13521442 }
13531443
1444+ if (ja4d_data .proto != 0 ) {
1445+ wmem_strbuf_truncate (ja4d_data .options , wmem_strbuf_get_len (ja4d_data .options ) - 1 );
1446+ wmem_strbuf_truncate (ja4d_data .request_list , wmem_strbuf_get_len (ja4d_data .request_list ) - 1 );
1447+
1448+ char * dhcp_proto = "dhcp" ;
1449+ if (ja4d_data .proto == '6' ) {
1450+ dhcp_proto = "dhcpv6" ;
1451+ }
1452+
1453+ update_tree_item (tvb , tree , & ja4_tree , hf_ja4d , ja4d (& ja4d_data ), dhcp_proto );
1454+ }
1455+
13541456 return tvb_reported_length (tvb );
13551457}
13561458
@@ -1361,7 +1463,11 @@ static void init_globals(void) {
13611463 GArray * wanted_hfids = g_array_new (FALSE, FALSE, (guint )sizeof (int ));
13621464 for (int i = 0 ; i < HFIDS ; i ++ ) {
13631465 int id = proto_registrar_get_id_byname (interesting_hfids [i ]);
1364- g_array_append_val (wanted_hfids , id );
1466+ if (id != -1 ) {
1467+ g_array_append_val (wanted_hfids , id );
1468+ } else {
1469+ g_warning ("JA4: Unknown field: %s" , interesting_hfids [i ]);
1470+ }
13651471 }
13661472
13671473 set_postdissector_wanted_hfids (ja4_handle , wanted_hfids );
@@ -1390,7 +1496,8 @@ void proto_register_ja4(void) {
13901496 {& hf_ja4ls , {"JA4LS" , "ja4.ja4ls" , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } },
13911497 {& hf_ja4ssh , {"JA4SSH" , "ja4.ja4ssh" , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } },
13921498 {& hf_ja4t , {"JA4T" , "ja4.ja4t" , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } },
1393- {& hf_ja4ts , {"JA4T-S" , "ja4.ja4ts" , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } }
1499+ {& hf_ja4ts , {"JA4T-S" , "ja4.ja4ts" , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } },
1500+ {& hf_ja4d , {"JA4D" , "ja4.ja4d" , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } }
13941501 };
13951502
13961503 static gint * ett [] = {
0 commit comments