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:
@ -265,6 +265,12 @@ func (l *Loader) AttachUprobes(sslLibPath string) error {
|
||||
}
|
||||
l.uprobeLinks = append(l.uprobeLinks, readExitLink)
|
||||
|
||||
// SSL_write — capture les réponses HTTP du serveur (direction=1)
|
||||
// Les programmes BPF uprobe/SSL_write et uretprobe/SSL_write sont
|
||||
// chargés depuis les objets Ja4Ssl. Si les objets BPF n'ont pas été
|
||||
// régénérés (pas de clang sur le host), ces programmes sont absents.
|
||||
_ = l.attachSSLWrite(ex)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -287,6 +293,50 @@ func (l *Loader) AttachAcceptProbe() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// attachSSLWrite tente d'attacher les uprobes SSL_write pour capturer
|
||||
// les réponses HTTP du serveur. Si les programmes BPF SSL_write ne sont
|
||||
// pas disponibles (objets non régénérés), retourne nil sans bloquer.
|
||||
func (l *Loader) attachSSLWrite(ex *link.Executable) error {
|
||||
// Charger la collection spec embarquée pour vérifier si SSL_write existe
|
||||
spec, err := LoadJa4Ssl()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
entrySpec, hasEntry := spec.Programs["uprobe_ssl_write_entry"]
|
||||
exitSpec, hasExit := spec.Programs["uretprobe_ssl_write_exit"]
|
||||
if !hasEntry || !hasExit {
|
||||
return nil // programmes SSL_write absents — BPF non régénéré
|
||||
}
|
||||
|
||||
writeEntry, err := ebpf.NewProgram(entrySpec)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
writeExit, err := ebpf.NewProgram(exitSpec)
|
||||
if err != nil {
|
||||
writeEntry.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
entryLink, err := ex.Uprobe("SSL_write", writeEntry, nil)
|
||||
if err != nil {
|
||||
writeEntry.Close()
|
||||
writeExit.Close()
|
||||
return fmt.Errorf("attachement uprobe SSL_write (entry): %w", err)
|
||||
}
|
||||
l.uprobeLinks = append(l.uprobeLinks, entryLink)
|
||||
|
||||
exitLink, err := ex.Uretprobe("SSL_write", writeExit, nil)
|
||||
if err != nil {
|
||||
writeExit.Close()
|
||||
return fmt.Errorf("attachement uretprobe SSL_write (exit): %w", err)
|
||||
}
|
||||
l.uprobeLinks = append(l.uprobeLinks, exitLink)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close détache tous les hooks eBPF et libère toutes les ressources associées.
|
||||
func (l *Loader) Close() error {
|
||||
if l.HTTPPlainReader != nil {
|
||||
|
||||
Reference in New Issue
Block a user