Zeek 8.2.2 - Ja4 fingerprint calc for tcp inner packets of geneve decapsulated

Hi. I installed Zeek 8.2.2 in RH9 in order to strip geneve packets and extract metadata of inner packets, adding fields like geneve src and dst IPs and VNI for future searches in Opensearch.

The fields I could add and is working properly. The problem is that Ja4 fingerprints are not being calculated for those inner packets. In conn.log, the Ja4 fields are empty, although the module is loaded and enabled.

I really appreciate if someone can help me in this case.

Your exact setup isn’t really clear to me so I can only speculate, but I suspect this could be due to how JA4 handles (or does not handle) tunnels. This would be more about JA4 and less about Zeek, so you might be able to get more help with them. In any case, if you could come up with a small, isolated reproducer of the problem you are seeing people could more easily help you.

Hi Benjamin!

Sure! I’ll try to explain better the scenario. We are testing zeek 8.2.2 installed in RH9 and connected with a 25Gbps intf with a Nexus switch. In this port, we span geneve traffic used by NSX and 802.1q traffic as well.
In the case of 802.1q traffic, the ja4 fingerprints are calculated correctly for all sort of traffic.
In the case of geneve traffic, the ja4 can’t be calculated for tcp traffic. However, for tls traffic, it is possible to observe secure fingerprints in ssl.log.
It seems that ja4 scripts are ok, but it is not possible to calculate fingerprints that require state control for inner packets in the case of geneve decapsulation process. I don’t know if the problem is the internal order of the zeek mechanism for decap and scripts execution or just a config I’m missing.
The Ja4 scripts are the latest available in FoxIO github (Commited on Aug 14, 2026).
Below I pasted the configs and outputs in order to clarify what I tried to explain in the above text.


teste@teste:/usr/local/zeek/share/zeek/site $ cat local.zeek
redef digest_salt = “Please change this value.”;
@load misc/loaded-scripts
@load misc/capture-loss
@load misc/stats
@load frameworks/software/vulnerable
@load frameworks/software/version-changes
@load-sigs frameworks/signatures/detect-windows-shells
@load protocols/ftp/software
@load protocols/smtp/software
@load protocols/ssh/software
@load protocols/http/software
@load protocols/dns/detect-external-names
@load protocols/ftp/detect
@load protocols/conn/known-hosts
@load protocols/conn/known-services
@load protocols/ssl/known-certs
@load protocols/ssl/validate-certs
@load protocols/ssl/log-hostcerts-only
@load protocols/ssh/geo-data
@load protocols/ssh/detect-bruteforcing
@load protocols/ssh/interesting-hostnames
@load protocols/http/detect-sql-injection
@load frameworks/files/hash-all-files
@load frameworks/files/detect-MHR
@load policy/frameworks/notice/extend-email/hostnames
@load frameworks/telemetry/log
@load policy/protocols/conn/vlan-logging
@load policy/protocols/conn/mac-logging
@load ja4
@load packages
@load base/packet-protocols/geneve
@load policy/frameworks/conn_key/vlan_fivetuple
@load base/frameworks/tunnels


802.1q traffic (It strips dot1q and calculate properly all ja4 fingerprints)

teste@teste:/usr/local/zeek/logs/current $ awk -F’\t’ 'BEGIN{OFS=“\t”} /^#fields/ {print $4, $6, $24 ,$25 ,$26 ,$27 ,$28 ,$29 ; next} /^#/ {next} {print $3, $5, $23, $24, $25, $26, $27, $28 } ’ conn.log | grep -v empty | head -10
id.orig_h id.resp_h ja4t ja4ts ja4l ja4ls ja4l_delta ja4ls_delta
172.30.120.76 172.30.60.60 64240_2-4-8-1-3_1460_1 28960_2-4-8-1-3_1460_1 107_62_886 160_60_6374 8.3 39.7
172.30.120.76 172.30.60.73 64240_2-4-8-1-3_1460_1 28960_2-4-8-1-3_1460_1 74_62_888 176_60_6683 12.1 37.9
172.30.120.76 172.30.60.61 64240_2-4-8-1-3_1460_1 28960_2-4-8-1-3_1460_1 108_62_914 216_60_6941 8.5 32.1
172.30.120.76 172.30.60.134 64240_2-4-8-1-3_1460_1 65535_2-4-8-1-3_1460_1 86_62_852 182_60_6252 10.0 34.4
172.30.120.96 172.30.60.231 65535_2-4-8-1-3_1460_2 28960_2-4-8-1-3_1460_1 102_62_908 175_60_6425 8.9 36.7
172.28.216.69 172.28.204.44 64240_2-4-8-1-3_1460_1 28960_2-4-8-1-3_1460_1 68_62_3628 247_60_6086 53.3 24.6
172.30.120.96 172.30.60.60 65535_2-4-8-1-3_1460_2 28960_2-4-8-1-3_1460_1 84_62_968 230_60_6400 11.5 27.9
172.30.120.96 172.30.60.231 65535_2-4-8-1-3_1460_2 28960_2-4-8-1-3_1460_1 88_62_971 216_60_6400 11.0 29.7
172.30.120.96 172.30.60.60 65535_2-4-8-1-3_1460_2 28960_2-4-8-1-3_1460_1 88_62_908 280_60_6485 10.4 23.2


Geneve traffic (It strips properly geneve header and analyze inner packets. You can observe decapsulated traffic in conn.log and other logs. However, ja4 fingerprints don’t work for inner packets, except to tls traffic, where is possible to realize ja4 tls fingerprints calculated in ssl.log, probably due to the simple code used to calculate secure fingreprints.)

#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path conn
#open 2026-09-15-11-00-01
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytesresp_pkts resp_ip_bytes tunnel_parents ip_proto ja4t ja4ts ja4l ja4ls ja4l_delta ja4ls_delta
#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string] count string string string string string string
T T 0 ShADdf 4 817 4 2380 CMiyKVdQsjopYGwke,CQb6JG3OiH8uQib0Ib 6(empty) (empty) (empty) (empty) (empty) (empty)
b051f705@sbcdf1a1:/usr/local/zeek/logs/current $ tail -10 conn.log
1789481892.765193 Cbm3344ghs79zpSyK5 192.168.29.135 51123 192.168.29.154 6081 udp geneve 0.000343 336 0 S0 T T 0 D 4 448 0 0 - 17 (empty) (empty) (empty) (empty) (empty) (empty)
1789481892.765199 CyPMji4dHNCihkvTI4 192.168.29.136 61366 192.168.29.154 6081 udp geneve 0.000430 336 0 S0 T T 0 D 4 448 0 0 - 17 (empty) (empty) (empty) (empty) (empty) (empty)
1789481892.767353 CMUzw7FmRwEgx0CKf 192.168.29.136 53059 192.168.29.154 6081 udp geneve 0.000415 3268 0 S0 T T 0 D 7 3464 0 0 - 17 (empty) (empty) (empty) (empty) (empty) (empty)
1789481892.767424 CKvViM2l4ZcRFVpUk8 192.168.29.154 54781 192.168.29.136 6081 udp geneve 0.000293 336 0 S0 T T 0 D 4 448 0 0 - 17 (empty) (empty) (empty) (empty) (empty) (empty)
1789481892.767895 CQFdde3uYpDDYHMG93 192.168.29.154 55499 192.168.29.151 6081 udp geneve 0.000294 336 0 S0 T T 0 D 4 448 0 0 - 17 (empty) (empty) (empty) (empty) (empty) (empty)
1789481892.767806 ChCMa7rmjK6v5BRN3 192.168.29.151 56888 192.168.29.154 6081 udp geneve 0.000493 3268 0 S0 T T 0 D 7 3464 0 0 - 17 (empty) (empty) (empty) (empty) (empty) (empty)
1789481947.767921 COx4P32FcuSLqL1Pk6 10.253.59.70 45946 10.253.59.59 7946 tcp - 0.000457 2686 0 SF T T 0 ShADFaf 7 3058 4 216 C3lHnD4NyPo5nGs9Yf,CoZQvBfnlD12XRDv1 6(empty) (empty) (empty) (empty) (empty) (empty)
1789481947.768964 C88X3FHRJb5dZqJuk 10.253.59.15 45750 10.253.59.59 7946 tcp - 0.000362 2854 0 SF T T 0 ShADFaf 7 3226 4 216 CaztpX2s4BlRCKyJdg,CUGnyF40smM2nSOM2h6(empty) (empty) (empty) (empty) (empty) (empty)
1789481947.769027 CtnipL23EjS6vAkxql 10.253.59.15 45758 10.253.59.59 7946 tcp - 0.000407 2686 0 SF T T 0 ShADFaf 7 3058 4 216 CCC9W71ehm56Hs63Nd,CS6ygS1UhSDRbR9oWh6(empty) (empty) (empty) (empty) (empty) (empty)
1789481947.769494 C5znfM1J02xYuaku5d 10.253.59.59 34090 10.253.59.15 7946 tcp - 0.000339 2709 0 SF T T 0 ShADFaf 7 3081 4 216 CgDcuRUeEE72YL27h,CY4h792Ba4GtcsGZUd 6(empty) (empty) (empty) (empty) (empty) (empty)


version

teste@teste:/usr/local/zeek/bin $ ./zeek --version
./zeek version 8.2.2


cat /usr/local/zeek/etc/node.cfg

manager

type=manager
host=localhost

proxy-1

type=proxy
host=localhost

worker-1

type=worker
host=localhost
interface=ens4f0np0


10: ens4f0np0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 9000 qdisc mq state UP group default qlen 1000
link/ether b0:26:28:ca:e5:00 brd ff:ff:ff:ff:ff:ff
altname enp69s0f0np0

Like I wrote previously, this seems to be an issue in the ja4 plugin, so not directly related to Zeek. You are more likely to get help from them. I created an upstream issue.