// Package dispatcher fournit le routeur Magic Bytes qui unifie les événements // issus des RingBuffers SSL (trafic chiffré déchiffré par uprobe) et HTTP plain // (trafic clair capturé par TC ingress), et les route vers le bon parser L7. package dispatcher import ( "bytes" ) // --- Marqueurs Magic Bytes ----------------------------------------------- // h2MagicBytes est la préface HTTP/2 client sous forme de []byte. var h2MagicBytes = []byte("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") // Préfixes de méthodes HTTP/1.x courants (liste non exhaustive). var http1Prefixes = [][]byte{ []byte("GET "), []byte("POST "), []byte("PUT "), []byte("DELETE "), []byte("HEAD "), []byte("OPTIONS "), []byte("PATCH "), []byte("CONNECT "), []byte("TRACE "), } // Protocol identifie le protocole applicatif détecté à partir des premiers octets. type Protocol uint8 const ( ProtoUnknown Protocol = iota ProtoHTTP1 // HTTP/1.0 ou HTTP/1.1 ProtoHTTP2 // HTTP/2 (préface "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") ) // RawEvent représente un buffer brut reçu depuis un RingBuffer eBPF // (SSL_read déchiffré OU payload TCP HTTP en clair). type RawEvent struct { SrcIP uint32 SrcPort uint16 PID uint32 // 0 pour les événements TC (HTTP plain, pas de PID) FD uint32 // 0 pour les événements TC Data []byte EOF bool // connexion terminée (uprobe SSL uniquement) Cleartext bool // true = provient de rb_http_plain (TC), false = uprobe SSL } // Classify inspecte les premiers octets du buffer et retourne le Protocol détecté. // La détection est purement basée sur les octets de début (pas de parsing complet). func Classify(data []byte) Protocol { if len(data) == 0 { return ProtoUnknown } // Détection HTTP/2 : préface exacte de 24 octets if bytes.HasPrefix(data, h2MagicBytes) { return ProtoHTTP2 } // Détection HTTP/1.x : commence par une méthode connue suivie d'un espace for _, pfx := range http1Prefixes { if bytes.HasPrefix(data, pfx) { return ProtoHTTP1 } } // Détection HTTP/2 partiel : peut arriver si le magic est fragmenté // sur plusieurs lectures. Dans ce cas on laisse l'appelant accumuler. n := minInt(len(data), len(h2MagicBytes)) if bytes.HasPrefix(h2MagicBytes, data[:n]) && len(data) < len(h2MagicBytes) { return ProtoHTTP2 // préface partielle — traiter comme H2 en cours } return ProtoUnknown } // minInt retourne le minimum de deux entiers (helper interne). func minInt(a, b int) int { if a < b { return a } return b }