fix(ja4ebpf): split bpf2go generate into Ja4Tc + Ja4Ssl, fix RPM systemd-rpm-macros

- Use two separate //go:generate directives (Ja4Tc for tc_capture.c, Ja4Ssl
  for uprobe_ssl.c) to avoid duplicate LICENSE symbol and multi-file clang issue
- Update loader.go to hold tcObjs/sslObjs separately with correct field names:
  UprobeSslSetFd, UprobeSslReadEntry, UretprobeSslReadExit,
  KprobeAccept4Entry, KretprobeAccept4Exit
- Add systemd-rpm-macros to all three RPM build stages (el8/el9/el10)
  so that %{_unitdir} macro resolves correctly
- RPMs now build successfully for el8, el9, el10

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
toto
2026-04-11 23:21:11 +02:00
parent a1e4c1dad5
commit 3b047b680a
155 changed files with 197011 additions and 599 deletions

View File

@ -16,12 +16,14 @@ import (
"github.com/cilium/ebpf/rlimit"
)
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -target amd64 -cflags "-O2 -g -Wall -Werror -D__TARGET_ARCH_x86" Ja4eBPF ../../bpf/tc_capture.c ../../bpf/uprobe_ssl.c -- -I../../bpf/headers
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -target amd64 -cflags "-O2 -g -Wall -D__TARGET_ARCH_x86 -Wno-pass-failed" Ja4Tc ../../bpf/tc_capture.c -- -I../../bpf/headers
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -target amd64 -cflags "-O2 -g -Wall -D__TARGET_ARCH_x86 -Wno-pass-failed" Ja4Ssl ../../bpf/uprobe_ssl.c -- -I../../bpf/headers
// Loader encapsule les objets eBPF compilés, les liens vers les hooks,
// et les readers RingBuffer exposés au pipeline de traitement.
type Loader struct {
objs *Ja4eBPFObjects // généré par bpf2go
tcObjs *Ja4TcObjects // généré par bpf2go (tc_capture.c)
sslObjs *Ja4SslObjects // généré par bpf2go (uprobe_ssl.c)
tcLink link.Link
uprobeLinks []link.Link
@ -50,56 +52,68 @@ func New() (*Loader, error) {
return nil, fmt.Errorf("suppression RLIMIT_MEMLOCK: %w", err)
}
objs := &Ja4eBPFObjects{}
// Charger le bytecode eBPF compilé (embarqué par bpf2go).
// nil = cilium/ebpf résout le BTF kernel natif automatiquement.
if err := LoadJa4eBPFObjects(objs, nil); err != nil {
return nil, fmt.Errorf("chargement objets eBPF: %w", err)
// Charger les objets TC (tc_capture.c)
tcObjs := &Ja4TcObjects{}
if err := LoadJa4TcObjects(tcObjs, nil); err != nil {
return nil, fmt.Errorf("chargement objets TC eBPF: %w", err)
}
// Charger les objets SSL/uprobe (uprobe_ssl.c)
sslObjs := &Ja4SslObjects{}
if err := LoadJa4SslObjects(sslObjs, nil); err != nil {
tcObjs.Close()
return nil, fmt.Errorf("chargement objets SSL eBPF: %w", err)
}
// Initialiser les readers pour chaque ring buffer
synReader, err := ringbuf.NewReader(objs.RbTcpSyn)
synReader, err := ringbuf.NewReader(tcObjs.RbTcpSyn)
if err != nil {
objs.Close()
sslObjs.Close()
tcObjs.Close()
return nil, fmt.Errorf("création reader rb_tcp_syn: %w", err)
}
tlsReader, err := ringbuf.NewReader(objs.RbTlsHello)
tlsReader, err := ringbuf.NewReader(tcObjs.RbTlsHello)
if err != nil {
synReader.Close()
objs.Close()
sslObjs.Close()
tcObjs.Close()
return nil, fmt.Errorf("création reader rb_tls_hello: %w", err)
}
sslReader, err := ringbuf.NewReader(objs.RbSslData)
httpPlainReader, err := ringbuf.NewReader(tcObjs.RbHttpPlain)
if err != nil {
tlsReader.Close()
synReader.Close()
objs.Close()
return nil, fmt.Errorf("création reader rb_ssl_data: %w", err)
}
acceptReader, err := ringbuf.NewReader(objs.RbAccept)
if err != nil {
sslReader.Close()
tlsReader.Close()
synReader.Close()
objs.Close()
return nil, fmt.Errorf("création reader rb_accept: %w", err)
}
httpPlainReader, err := ringbuf.NewReader(objs.RbHttpPlain)
if err != nil {
acceptReader.Close()
sslReader.Close()
tlsReader.Close()
synReader.Close()
objs.Close()
sslObjs.Close()
tcObjs.Close()
return nil, fmt.Errorf("création reader rb_http_plain: %w", err)
}
sslReader, err := ringbuf.NewReader(sslObjs.RbSslData)
if err != nil {
httpPlainReader.Close()
tlsReader.Close()
synReader.Close()
sslObjs.Close()
tcObjs.Close()
return nil, fmt.Errorf("création reader rb_ssl_data: %w", err)
}
acceptReader, err := ringbuf.NewReader(sslObjs.RbAccept)
if err != nil {
sslReader.Close()
httpPlainReader.Close()
tlsReader.Close()
synReader.Close()
sslObjs.Close()
tcObjs.Close()
return nil, fmt.Errorf("création reader rb_accept: %w", err)
}
return &Loader{
objs: objs,
tcObjs: tcObjs,
sslObjs: sslObjs,
SynReader: synReader,
TLSReader: tlsReader,
SSLReader: sslReader,
@ -120,7 +134,7 @@ func (l *Loader) AttachTC(iface string) error {
// Attacher le programme TC en ingress via TCX
lnk, err := link.AttachTCX(link.TCXOptions{
Interface: netIface.Index,
Program: l.objs.CaptureTcIngress,
Program: l.tcObjs.CaptureTcIngress,
Attach: ebpf.AttachTCXIngress,
})
if err != nil {
@ -146,21 +160,21 @@ func (l *Loader) AttachUprobes(sslLibPath string) error {
}
// Uprobe sur SSL_set_fd (entry)
setFdLink, err := ex.Uprobe("SSL_set_fd", l.objs.UprobeSSLSetFd, nil)
setFdLink, err := ex.Uprobe("SSL_set_fd", l.sslObjs.UprobeSslSetFd, nil)
if err != nil {
return fmt.Errorf("attachement uprobe SSL_set_fd: %w", err)
}
l.uprobeLinks = append(l.uprobeLinks, setFdLink)
// Uprobe sur SSL_read (entry)
readEntryLink, err := ex.Uprobe("SSL_read", l.objs.UprobeSSLReadEntry, nil)
readEntryLink, err := ex.Uprobe("SSL_read", l.sslObjs.UprobeSslReadEntry, nil)
if err != nil {
return fmt.Errorf("attachement uprobe SSL_read (entry): %w", err)
}
l.uprobeLinks = append(l.uprobeLinks, readEntryLink)
// Uretprobe sur SSL_read (exit)
readExitLink, err := ex.Uretprobe("SSL_read", l.objs.UretprobeSSLReadExit, nil)
readExitLink, err := ex.Uretprobe("SSL_read", l.sslObjs.UretprobeSslReadExit, nil)
if err != nil {
return fmt.Errorf("attachement uretprobe SSL_read (exit): %w", err)
}
@ -172,14 +186,14 @@ func (l *Loader) AttachUprobes(sslLibPath string) error {
// AttachAcceptProbe attache les kprobes sur l'appel système accept4.
func (l *Loader) AttachAcceptProbe() error {
// Kprobe à l'entrée d'accept4
kpEntry, err := link.Kprobe("accept4", l.objs.KprobeAccept4Entry, nil)
kpEntry, err := link.Kprobe("accept4", l.sslObjs.KprobeAccept4Entry, nil)
if err != nil {
return fmt.Errorf("attachement kprobe accept4 (entry): %w", err)
}
l.uprobeLinks = append(l.uprobeLinks, kpEntry)
// Kretprobe à la sortie d'accept4
kpExit, err := link.Kretprobe("accept4", l.objs.KretprobeAccept4Exit, nil)
kpExit, err := link.Kretprobe("accept4", l.sslObjs.KretprobeAccept4Exit, nil)
if err != nil {
return fmt.Errorf("attachement kretprobe accept4 (exit): %w", err)
}
@ -220,8 +234,11 @@ func (l *Loader) Close() error {
}
// Libérer les objets eBPF (maps, programmes)
if l.objs != nil {
l.objs.Close()
if l.sslObjs != nil {
l.sslObjs.Close()
}
if l.tcObjs != nil {
l.tcObjs.Close()
}
return nil