package capture import ( "fmt" "net" "time" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "ja4sentinel/internal/api" ) // CaptureImpl implémente l'interface capture.Capture type CaptureImpl struct { handle *pcap.Handle } // New crée une nouvelle instance de capture func New() *CaptureImpl { return &CaptureImpl{} } // Run démarre la capture des paquets réseau selon la configuration func (c *CaptureImpl) Run(cfg api.Config, out chan<- api.RawPacket) error { var err error c.handle, err = pcap.OpenLive(cfg.Interface, 1600, true, pcap.BlockForever) if err != nil { return fmt.Errorf("failed to open interface %s: %w", cfg.Interface, err) } defer c.handle.Close() // Appliquer le filtre BPF s'il est fourni if cfg.BPFFilter != "" { err = c.handle.SetBPFFilter(cfg.BPFFilter) if err != nil { return fmt.Errorf("failed to set BPF filter: %w", err) } } else { // Créer un filtre par défaut pour les ports surveillés defaultFilter := buildBPFForPorts(cfg.ListenPorts) err = c.handle.SetBPFFilter(defaultFilter) if err != nil { return fmt.Errorf("failed to set default BPF filter: %w", err) } } packetSource := gopacket.NewPacketSource(c.handle, c.handle.LinkType()) for packet := range packetSource.Packets() { // Convertir le paquet en RawPacket rawPkt := packetToRawPacket(packet) if rawPkt != nil { select { case out <- *rawPkt: // Paquet envoyé avec succès default: // Canal plein, ignorer le paquet } } } return nil } // buildBPFForPorts construit un filtre BPF pour les ports TCP spécifiés func buildBPFForPorts(ports []uint16) string { if len(ports) == 0 { return "tcp" } filterParts := make([]string, len(ports)) for i, port := range ports { filterParts[i] = fmt.Sprintf("tcp port %d", port) } return "(" + joinString(filterParts, ") or (") + ")" } // joinString joint des chaînes avec un séparateur func joinString(parts []string, sep string) string { if len(parts) == 0 { return "" } result := parts[0] for _, part := range parts[1:] { result += sep + part } return result } // packetToRawPacket convertit un paquet gopacket en RawPacket func packetToRawPacket(packet gopacket.Packet) *api.RawPacket { data := packet.Data() if len(data) == 0 { return nil } return &api.RawPacket{ Data: data, Timestamp: packet.Metadata().Timestamp.UnixNano(), } } // Close ferme correctement la capture func (c *CaptureImpl) Close() error { if c.handle != nil { c.handle.Close() return nil } return nil }