feat(ja4ebpf): add SSL_write uprobe, HPACK decoder, and AcceptCache for session correlation
Add uprobe_ssl_write_entry/uretprobe_ssl_write_exit to capture server HTTP
responses via SSL_write with direction=1. Implement full HPACK decoder
(RFC 7541 static table, multi-byte integers, literal representations) for
HTTP/2 header extraction. Add AcceptCache mapping {tgid,fd}→SessionKey
from accept4 events as authoritative source for SSL correlation when BPF
ssl_conn_map has src_ip=0. Add ip_total_length to tcp_syn_event BPF struct.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
142
tests/vm/generate-traffic.sh
Executable file
142
tests/vm/generate-traffic.sh
Executable file
@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# generate-traffic.sh — Generate HTTPS/HTTP traffic from a VM endpoint
|
||||
#
|
||||
# Called by run-e2e-test.sh via:
|
||||
# vagrant ssh $vm -- "source /tmp/e2e-traffic.env && bash /ja4-platform/tests/vm/generate-traffic.sh"
|
||||
#
|
||||
# Environment variables (from /tmp/e2e-traffic.env):
|
||||
# HITS — Number of HTTPS requests (required)
|
||||
# HITS_HTTP — Number of HTTP requests (default: 0)
|
||||
# TARGET_IPS — Space-separated list of endpoint IPs (required)
|
||||
# SNI_HOSTS — Space-separated list of SNI hostnames (required)
|
||||
# TLS_FLAGS — curl TLS flags e.g. "--tlsv1.2 --tlsv1.3" (required)
|
||||
# SRC_IP_COUNT — Number of source IPs to rotate (default: 1)
|
||||
# =============================================================================
|
||||
set -uo pipefail
|
||||
|
||||
HITS="${HITS:-0}"
|
||||
HITS_HTTP="${HITS_HTTP:-0}"
|
||||
TARGET_IPS=(${TARGET_IPS:-})
|
||||
SNI_HOSTS=(${SNI_HOSTS:-platform.test})
|
||||
TLS_FLAGS="${TLS_FLAGS:---tlsv1.2 --tlsv1.3}"
|
||||
SRC_IP_COUNT="${SRC_IP_COUNT:-1}"
|
||||
|
||||
if [ "$HITS" -eq 0 ] && [ "$HITS_HTTP" -eq 0 ]; then
|
||||
echo "0/0"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── Collect source IPs from eth0 ──
|
||||
SRC_IPS=($(ip -4 addr show eth0 2>/dev/null | awk '/inet / {sub(/\/.*/, "", $2); print $2}'))
|
||||
if [ ${#SRC_IPS[@]} -eq 0 ]; then
|
||||
echo "0/${HITS}" > /dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── User-Agent pools ──
|
||||
UA_BROWSER=(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/131.0.0.0 Safari/537.36"
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1.15"
|
||||
"Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0"
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0"
|
||||
)
|
||||
UA_BOT=(
|
||||
"python-requests/2.32.3"
|
||||
"curl/8.9.1"
|
||||
"Go-http-client/2.0"
|
||||
"python-httpx/0.28.1"
|
||||
"Googlebot/2.1"
|
||||
)
|
||||
PATHS=("/" "/health" "/data" "/api/users" "/api/v1/status" "/api/v1/metrics" \
|
||||
"/login" "/logout" "/api/search" "/static/main.js" "/static/style.css" \
|
||||
"/favicon.ico" "/robots.txt" "/sitemap.xml" "/api/v2/data" "/admin")
|
||||
|
||||
ok=0
|
||||
err=0
|
||||
|
||||
# ── HTTPS traffic ──
|
||||
if [ "$HITS" -gt 0 ]; then
|
||||
for i in $(seq 1 "$HITS"); do
|
||||
idx=$((i - 1))
|
||||
target_ip="${TARGET_IPS[$((idx % ${#TARGET_IPS[@]}))]}"
|
||||
sni_host="${SNI_HOSTS[$((idx % ${#SNI_HOSTS[@]}))]}"
|
||||
path="${PATHS[$((idx % ${#PATHS[@]}))]}"
|
||||
|
||||
# Rotate methods: GET(50%), POST(20%), PUT(10%), DELETE(10%), HEAD(10%)
|
||||
case $((i % 10)) in
|
||||
0|1|2|3|4) method="GET" ;;
|
||||
5|6) method="POST" ;;
|
||||
7) method="PUT" ;;
|
||||
8) method="DELETE" ;;
|
||||
9) method="HEAD" ;;
|
||||
esac
|
||||
|
||||
# 70% browser UA, 30% bot UA
|
||||
if [ $((i % 10)) -lt 7 ]; then
|
||||
ua="${UA_BROWSER[$((idx % ${#UA_BROWSER[@]}))]}"
|
||||
else
|
||||
ua="${UA_BOT[$((idx % ${#UA_BOT[@]}))]}"
|
||||
fi
|
||||
|
||||
# Build curl flags
|
||||
resolve_flag="--resolve ${sni_host}:443:${target_ip}"
|
||||
extra_flags="${resolve_flag} ${TLS_FLAGS}"
|
||||
|
||||
# Rotate source IPs if multiple are available
|
||||
if [ ${#SRC_IPS[@]} -gt 1 ] && [ "$SRC_IP_COUNT" -gt 1 ]; then
|
||||
src_ip="${SRC_IPS[$((idx % SRC_IP_COUNT))]}"
|
||||
if [ -n "$src_ip" ]; then
|
||||
extra_flags="${extra_flags} --interface ${src_ip}"
|
||||
fi
|
||||
fi
|
||||
|
||||
case $method in
|
||||
POST)
|
||||
curl -sf -k ${extra_flags} -X POST "https://${sni_host}${path}" \
|
||||
-H "User-Agent: ${ua}" -H "Content-Type: application/json" \
|
||||
-d '{"test":1,"seq":'$i'}' \
|
||||
--connect-timeout 5 --max-time 10 \
|
||||
>/dev/null 2>&1 && ok=$((ok + 1)) || err=$((err + 1)) ;;
|
||||
PUT)
|
||||
curl -sf -k ${extra_flags} -X PUT "https://${sni_host}${path}" \
|
||||
-H "User-Agent: ${ua}" \
|
||||
--connect-timeout 5 --max-time 10 \
|
||||
>/dev/null 2>&1 && ok=$((ok + 1)) || err=$((err + 1)) ;;
|
||||
DELETE)
|
||||
curl -sf -k ${extra_flags} -X DELETE "https://${sni_host}${path}" \
|
||||
-H "User-Agent: ${ua}" \
|
||||
--connect-timeout 5 --max-time 10 \
|
||||
>/dev/null 2>&1 && ok=$((ok + 1)) || err=$((err + 1)) ;;
|
||||
HEAD)
|
||||
curl -sf -k ${extra_flags} -I "https://${sni_host}${path}" \
|
||||
-H "User-Agent: ${ua}" \
|
||||
--connect-timeout 5 --max-time 10 \
|
||||
>/dev/null 2>&1 && ok=$((ok + 1)) || err=$((err + 1)) ;;
|
||||
*)
|
||||
curl -sf -k ${extra_flags} "https://${sni_host}${path}" \
|
||||
-H "User-Agent: ${ua}" \
|
||||
--connect-timeout 5 --max-time 10 \
|
||||
>/dev/null 2>&1 && ok=$((ok + 1)) || err=$((err + 1)) ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# ── HTTP traffic (port 80) ──
|
||||
ok_http=0
|
||||
if [ "$HITS_HTTP" -gt 0 ]; then
|
||||
for i in $(seq 1 "$HITS_HTTP"); do
|
||||
idx=$((i - 1))
|
||||
# Round-robin across target IPs for HTTP too
|
||||
target_ip="${TARGET_IPS[$((idx % ${#TARGET_IPS[@]}))]}"
|
||||
path="${PATHS[$((idx % ${#PATHS[@]}))]}"
|
||||
|
||||
# HTTP: use target_ip directly (no --resolve needed for HTTP)
|
||||
curl -sf "http://${target_ip}${path}" \
|
||||
--connect-timeout 5 --max-time 10 \
|
||||
>/dev/null 2>&1 && ok_http=$((ok_http + 1)) || true
|
||||
done
|
||||
fi
|
||||
|
||||
# Output: HTTPS_ok/HTTPS_total HTTP_ok/HTTP_total
|
||||
echo "${ok}/${HITS} ${ok_http}/${HITS_HTTP}"
|
||||
Reference in New Issue
Block a user