feat(pr3): canonical wire-order header capture for h1/h2 + H3App for SETTINGS

- Renames caddy.listeners.decnet_h2fp → decnet_fp; adds h1 raw-byte
  header capture (plainTappingConn) and h2 continuous HPACK decode loop
  (parseH2HeadersLoop) so headers_ordered reflects actual wire order, not
  Go map iteration order.
- Adds H3App Caddy module (decnet_h3) that owns UDP/443 via quic-go,
  wraps accepted QUIC connections with h3SettingsTappingConn to intercept
  the h3 control stream and extract RFC 9114 SETTINGS in wire order.
- Wires access_log emission from FPHandler.ServeHTTP via responseCapture.
- Updates syslog_bridge.py (canonical + per-service copies) with inline
  _compute_ja4h and new fp socket record branches: http_request_headers,
  h3_settings, access_log.
- Fixes ingester proto field alias (bridge emits 'proto', ingester expected
  'protocol') and exposes _process_fingerprint_bounties test alias.
- Go tests: h1/h2/h3 golden-byte tests all green; h3_tracer_test covers
  varint parser, GREASE detection, truncated-stream safety.
- Python tests: 15/15 green across bridge JA4H hash parity, ingester
  compat (old + new event shapes), and Caddyfile h3 template assertions.
This commit is contained in:
2026-05-10 03:29:00 -04:00
parent 8d1f26c0c7
commit 5675dd8ebc
33 changed files with 7240 additions and 124 deletions

View File

@@ -29,7 +29,8 @@ if [ ! -f "$CERT" ] || [ ! -f "$KEY" ]; then
2>/dev/null
fi
# Parse HTTP_VERSIONS JSON → Caddy protocol tokens (h1 / h2 / h3)
# Parse HTTP_VERSIONS JSON → Caddy protocol tokens (h1 / h2 only).
# h3 is handled by decnet_h3 Caddy app (H3App owns UDP/443); never goes to Caddy native h3.
CADDY_PROTOCOLS=$(python3 -c "
import json, os
versions = json.loads(os.environ.get('HTTP_VERSIONS', '[\"http/1.1\"]'))
@@ -38,11 +39,17 @@ if 'http/1.1' in versions:
tokens.append('h1')
if 'http/2' in versions:
tokens.append('h2')
if 'http/3' in versions:
tokens.append('h3')
print(' '.join(tokens) if tokens else 'h1')
")
# When http/3 is selected, activate the decnet_h3 Caddy app (global block).
DECNET_H3_GLOBAL=$(python3 -c "
import json, os
versions = json.loads(os.environ.get('HTTP_VERSIONS', '[\"http/1.1\"]'))
if 'http/3' in versions:
print(' decnet_h3')
")
DECNET_FP_SOCK="${DECNET_FP_SOCK:-/run/decnet/fp.sock}"
# Remove stale socket from a previous run
rm -f "$DECNET_FP_SOCK"
@@ -50,10 +57,11 @@ rm -f "$DECNET_FP_SOCK"
cat > /etc/caddy/Caddyfile <<EOF
{
admin off
${DECNET_H3_GLOBAL}
servers :443 {
protocols ${CADDY_PROTOCOLS}
listener_wrappers {
decnet_h2fp
decnet_fp
}
}
}