diff --git a/services/ja4ebpf/cmd/ja4ebpf/main.go b/services/ja4ebpf/cmd/ja4ebpf/main.go index 5d54571..638084b 100644 --- a/services/ja4ebpf/cmd/ja4ebpf/main.go +++ b/services/ja4ebpf/cmd/ja4ebpf/main.go @@ -309,9 +309,9 @@ func consumeSynEvents(ctx context.Context, rd *perf.Reader, mgr *correlation.Man // src_ip(4)+dst_ip(4)+src_port(2)+dst_port(2)+ttl(1)+df_bit(1)+ip_id(2)+ // ip_total_length(2)+window_size(2)+window_scale(1)+mss(2)+tcp_options_raw[40]+ // tcp_options_len(1)+timestamp_ns(8) - // offsets: 0 4 8 10 12 13 14 16 18 19 21 61 - // total = 62 + 8 = 70 - if len(record.RawSample) < 70 { + // offsets: 0 4 8 10 12 13 14 16 18 20 21 23 63 + // total = 64 + 8 = 72 + if len(record.RawSample) < 72 { continue } data := record.RawSample @@ -342,12 +342,12 @@ func consumeSynEvents(ctx context.Context, rd *perf.Reader, mgr *correlation.Man ipTotalLength := binary.LittleEndian.Uint16(data[16:18]) windowSize := binary.LittleEndian.Uint16(data[18:20]) - optLen := int(data[61]) + optLen := int(data[63]) if optLen > 40 { optLen = 40 } tcpOpts := make([]byte, optLen) - copy(tcpOpts, data[21:21+optLen]) + copy(tcpOpts, data[23:23+optLen]) // Analyser les options TCP brutes pour extraire MSS et Window Scale mss, windowScale := parseTCPOptions(tcpOpts) @@ -499,12 +499,13 @@ func consumeSSLEvents(ctx context.Context, rd *perf.Reader, mgr *correlation.Man srcIPRaw := binary.LittleEndian.Uint32(data[12:16]) srcPort := binary.LittleEndian.Uint16(data[16:18]) - // data[4096] commence à offset 18, data_len à offset 4114, direction à offset 4118 - if len(data) < 4119 { + // data[4096] commence à offset 18, data_len à offset 4114, + // timestamp_ns à offset 4118, direction à offset 4126 + if len(data) < 4127 { continue } dataLen := binary.LittleEndian.Uint32(data[4114:4118]) - direction := data[4118] // 0 = SSL_read (client→serveur), 1 = SSL_write (serveur→client) + direction := data[4126] // 0 = SSL_read (client→serveur), 1 = SSL_write (serveur→client) if dataLen > 4096 { dataLen = 4096 } diff --git a/services/ja4ebpf/internal/loader/ja4ssl_x86_bpfel.go b/services/ja4ebpf/internal/loader/ja4ssl_x86_bpfel.go index 929470c..ba159b8 100644 --- a/services/ja4ebpf/internal/loader/ja4ssl_x86_bpfel.go +++ b/services/ja4ebpf/internal/loader/ja4ssl_x86_bpfel.go @@ -107,11 +107,13 @@ type Ja4SslSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type Ja4SslProgramSpecs struct { - KprobeAccept4Entry *ebpf.ProgramSpec `ebpf:"kprobe_accept4_entry"` - KretprobeAccept4Exit *ebpf.ProgramSpec `ebpf:"kretprobe_accept4_exit"` - UprobeSslReadEntry *ebpf.ProgramSpec `ebpf:"uprobe_ssl_read_entry"` - UprobeSslSetFd *ebpf.ProgramSpec `ebpf:"uprobe_ssl_set_fd"` - UretprobeSslReadExit *ebpf.ProgramSpec `ebpf:"uretprobe_ssl_read_exit"` + KprobeAccept4Entry *ebpf.ProgramSpec `ebpf:"kprobe_accept4_entry"` + KretprobeAccept4Exit *ebpf.ProgramSpec `ebpf:"kretprobe_accept4_exit"` + UprobeSslReadEntry *ebpf.ProgramSpec `ebpf:"uprobe_ssl_read_entry"` + UprobeSslSetFd *ebpf.ProgramSpec `ebpf:"uprobe_ssl_set_fd"` + UprobeSslWriteEntry *ebpf.ProgramSpec `ebpf:"uprobe_ssl_write_entry"` + UretprobeSslReadExit *ebpf.ProgramSpec `ebpf:"uretprobe_ssl_read_exit"` + UretprobeSslWriteExit *ebpf.ProgramSpec `ebpf:"uretprobe_ssl_write_exit"` } // Ja4SslMapSpecs contains maps before they are loaded into the kernel. @@ -189,11 +191,13 @@ func (m *Ja4SslMaps) Close() error { // // It can be passed to LoadJa4SslObjects or ebpf.CollectionSpec.LoadAndAssign. type Ja4SslPrograms struct { - KprobeAccept4Entry *ebpf.Program `ebpf:"kprobe_accept4_entry"` - KretprobeAccept4Exit *ebpf.Program `ebpf:"kretprobe_accept4_exit"` - UprobeSslReadEntry *ebpf.Program `ebpf:"uprobe_ssl_read_entry"` - UprobeSslSetFd *ebpf.Program `ebpf:"uprobe_ssl_set_fd"` - UretprobeSslReadExit *ebpf.Program `ebpf:"uretprobe_ssl_read_exit"` + KprobeAccept4Entry *ebpf.Program `ebpf:"kprobe_accept4_entry"` + KretprobeAccept4Exit *ebpf.Program `ebpf:"kretprobe_accept4_exit"` + UprobeSslReadEntry *ebpf.Program `ebpf:"uprobe_ssl_read_entry"` + UprobeSslSetFd *ebpf.Program `ebpf:"uprobe_ssl_set_fd"` + UprobeSslWriteEntry *ebpf.Program `ebpf:"uprobe_ssl_write_entry"` + UretprobeSslReadExit *ebpf.Program `ebpf:"uretprobe_ssl_read_exit"` + UretprobeSslWriteExit *ebpf.Program `ebpf:"uretprobe_ssl_write_exit"` } func (p *Ja4SslPrograms) Close() error { @@ -202,7 +206,9 @@ func (p *Ja4SslPrograms) Close() error { p.KretprobeAccept4Exit, p.UprobeSslReadEntry, p.UprobeSslSetFd, + p.UprobeSslWriteEntry, p.UretprobeSslReadExit, + p.UretprobeSslWriteExit, ) } diff --git a/services/ja4ebpf/internal/loader/loader.go b/services/ja4ebpf/internal/loader/loader.go index 0a94fa7..157614e 100644 --- a/services/ja4ebpf/internal/loader/loader.go +++ b/services/ja4ebpf/internal/loader/loader.go @@ -266,10 +266,9 @@ 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) + if err := l.attachSSLWrite(ex); err != nil { + return fmt.Errorf("attachement SSL_write: %w", err) + } return nil } @@ -293,43 +292,17 @@ 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. +// attachSSLWrite attache les uprobes SSL_write pour capturer +// les réponses HTTP du serveur (direction=1). func (l *Loader) attachSSLWrite(ex *link.Executable) error { - // Charger la collection spec embarquée pour vérifier si SSL_write existe - spec, err := LoadJa4Ssl() + entryLink, err := ex.Uprobe("SSL_write", l.sslObjs.UprobeSslWriteEntry, nil) 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) + exitLink, err := ex.Uretprobe("SSL_write", l.sslObjs.UretprobeSslWriteExit, nil) if err != nil { - writeExit.Close() return fmt.Errorf("attachement uretprobe SSL_write (exit): %w", err) } l.uprobeLinks = append(l.uprobeLinks, exitLink)