Nouveaux modules: - cmd/ja4sentinel/main.go : point d'entrée avec pipeline capture→parse→fingerprint→output - internal/config/loader.go : chargement YAML + env (JA4SENTINEL_*) + validation - internal/tlsparse/parser.go : extraction ClientHello avec suivi d'état de flux (NEW/WAIT_CLIENT_HELLO/JA4_DONE) - internal/fingerprint/engine.go : génération JA4/JA3 via psanford/tlsfingerprint - internal/output/writers.go : StdoutWriter, FileWriter, UnixSocketWriter, MultiWriter Infrastructure: - Dockerfile (multi-stage), Dockerfile.dev, Dockerfile.test-server - Makefile (build, test, lint, docker-build-*) - docker-compose.test.yml pour tests d'intégration - README.md (276 lignes) avec architecture, config, exemples API (api/types.go): - Ajout Close() aux interfaces Capture et Parser - Ajout FlowTimeoutSec dans Config (défaut: 30s, env: JA4SENTINEL_FLOW_TIMEOUT) - ServiceLog: +Timestamp, +TraceID, +ConnID - LogRecord: champs flatten (ip_meta_*, tcp_meta_*, ja4*) - Helper NewLogRecord() pour conversion TLSClientHello+Fingerprints→LogRecord Architecture (architecture.yml): - Documentation module logging + interfaces LoggerFactory/Logger - Section service.systemd complète (unit, security, capabilities) - Section logging.strategy (JSON lines, champs, règles) - api.Config: +FlowTimeoutSec documenté Fixes/cleanup: - Suppression internal/api/types.go (consolidé dans api/types.go) - Correction imports logging (ja4sentinel/api) - .dockerignore / .gitignore - config.yml.example Tests: - Tous les modules ont leurs tests (*_test.go) - Tests unitaires : capture, config, fingerprint, output, tlsparse - Tests d'intégration via docker-compose.test.yml Build: - Binaires dans dist/ (make build → dist/ja4sentinel) - Docker runtime avec COPY --from=builder /app/dist/ Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
277 lines
6.1 KiB
Markdown
277 lines
6.1 KiB
Markdown
# JA4Sentinel
|
|
|
|
Outil Go pour capturer le trafic réseau sur un serveur Linux, extraire les handshakes TLS côté client, générer les signatures JA4, enrichir avec des métadonnées IP/TCP, et loguer les résultats vers une ou plusieurs sorties configurables.
|
|
|
|
## Fonctionnalités
|
|
|
|
- **Capture réseau** : Écoute sur une interface réseau avec filtres BPF configurables
|
|
- **Parsing TLS** : Extraction des ClientHello TLS depuis les flux TCP
|
|
- **Fingerprinting** : Génération des empreintes JA4 et JA3 pour chaque client
|
|
- **Métadonnées** : Enrichissement avec IPMeta (TTL, IP ID, DF) et TCPMeta (window, MSS, options)
|
|
- **Sorties multiples** : stdout, fichier JSON, socket UNIX (combinables via MultiWriter)
|
|
- **Logging structuré** : Logs JSON sur stdout/stderr pour intégration avec systemd/journald
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
│ Capture │ ──▶ │ TLSParse │ ──▶ │ Fingerprint │ ──▶ │ Output │
|
|
│ (pcap) │ │ (ClientHello)│ │ (JA4) │ │ (JSON logs) │
|
|
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
|
│ │ │ │
|
|
▼ ▼ ▼ ▼
|
|
api.RawPacket api.TLSClientHello api.Fingerprints api.LogRecord
|
|
```
|
|
|
|
### Modules
|
|
|
|
| Module | Responsabilités |
|
|
|--------|-----------------|
|
|
| `config` | Chargement et validation de la configuration (YAML, env, CLI) |
|
|
| `capture` | Capture des paquets réseau via libpcap |
|
|
| `tlsparse` | Extraction des ClientHello TLS avec suivi d'état de flux |
|
|
| `fingerprint` | Génération JA4/JA3 via `psanford/tlsfingerprint` |
|
|
| `output` | Écriture des logs vers stdout, fichier, socket UNIX |
|
|
| `logging` | Logs structurés JSON pour le diagnostic du service |
|
|
|
|
## Installation
|
|
|
|
### Prérequis
|
|
|
|
- Go 1.24+
|
|
- libpcap-dev (pour la capture réseau)
|
|
- Docker (pour les tests et le déploiement)
|
|
|
|
### Build local
|
|
|
|
```bash
|
|
make build
|
|
```
|
|
|
|
### Build Docker
|
|
|
|
```bash
|
|
# Image de développement
|
|
make docker-build-dev
|
|
|
|
# Image runtime (production)
|
|
make docker-build-runtime
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Fichier de configuration (YAML)
|
|
|
|
```yaml
|
|
core:
|
|
interface: eth0
|
|
listen_ports: [443, 8443]
|
|
bpf_filter: ""
|
|
flow_timeout_sec: 30
|
|
|
|
outputs:
|
|
- type: stdout
|
|
enabled: true
|
|
- type: file
|
|
enabled: true
|
|
params:
|
|
path: /var/log/ja4sentinel/ja4.log
|
|
- type: unix_socket
|
|
enabled: true
|
|
params:
|
|
socket_path: /var/run/ja4sentinel.sock
|
|
```
|
|
|
|
### Variables d'environnement
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `JA4SENTINEL_INTERFACE` | Interface réseau (ex: `eth0`) |
|
|
| `JA4SENTINEL_PORTS` | Ports à surveiller (ex: `443,8443`) |
|
|
| `JA4SENTINEL_BPF_FILTER` | Filtre BPF personnalisé |
|
|
| `JA4SENTINEL_FLOW_TIMEOUT` | Timeout de flux en secondes (défaut: 30) |
|
|
|
|
### Ligne de commande
|
|
|
|
```bash
|
|
ja4sentinel --config /etc/ja4sentinel/config.yml
|
|
ja4sentinel --version
|
|
```
|
|
|
|
## Format des logs
|
|
|
|
### Logs de service (stdout/stderr)
|
|
|
|
```json
|
|
{
|
|
"timestamp": 1708876543210000000,
|
|
"level": "INFO",
|
|
"component": "capture",
|
|
"message": "Starting packet capture",
|
|
"interface": "eth0"
|
|
}
|
|
```
|
|
|
|
### Logs métier (JA4)
|
|
|
|
```json
|
|
{
|
|
"src_ip": "192.168.1.100",
|
|
"src_port": 54321,
|
|
"dst_ip": "10.0.0.1",
|
|
"dst_port": 443,
|
|
"ip_meta_ttl": 64,
|
|
"ip_meta_total_length": 512,
|
|
"ip_meta_id": 12345,
|
|
"ip_meta_df": true,
|
|
"tcp_meta_window_size": 65535,
|
|
"tcp_meta_mss": 1460,
|
|
"tcp_meta_window_scale": 7,
|
|
"tcp_meta_options": "MSS,WS,SACK,TS",
|
|
"ja4": "t13d1516h2_8daaf6152771_02cb136f2775",
|
|
"ja4_hash": "8daaf6152771_02cb136f2775",
|
|
"ja3": "771,4865-4866-4867,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0",
|
|
"ja3_hash": "a0e6f06c7a6d15e5e3f0f0e6f06c7a6d"
|
|
}
|
|
```
|
|
|
|
## Tests
|
|
|
|
### Tests unitaires
|
|
|
|
```bash
|
|
# En local
|
|
make test
|
|
|
|
# Dans Docker
|
|
make test-docker
|
|
|
|
# Avec détection de race conditions
|
|
make test-race
|
|
|
|
# Avec rapport de couverture
|
|
make test-coverage
|
|
```
|
|
|
|
### Tests d'intégration
|
|
|
|
```bash
|
|
# Lance les tests bout-à-bout dans Docker
|
|
make test-integration
|
|
|
|
# Nettoyage après tests
|
|
make test-integration-clean
|
|
```
|
|
|
|
## Déploiement systemd
|
|
|
|
Exemple de fichier de service `/etc/systemd/system/ja4sentinel.service` :
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=JA4 client fingerprinting daemon
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=ja4sentinel
|
|
Group=ja4sentinel
|
|
ExecStart=/usr/local/bin/ja4sentinel --config /etc/ja4sentinel/config.yml
|
|
Restart=on-failure
|
|
RestartSec=5
|
|
Environment=JA4SENTINEL_LOG_LEVEL=info
|
|
|
|
# Security
|
|
NoNewPrivileges=yes
|
|
ProtectSystem=full
|
|
ProtectHome=true
|
|
PrivateTmp=true
|
|
CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN
|
|
AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
## Exemples d'utilisation
|
|
|
|
### Surveillance du trafic HTTPS
|
|
|
|
```yaml
|
|
core:
|
|
interface: eth0
|
|
listen_ports: [443]
|
|
outputs:
|
|
- type: stdout
|
|
enabled: true
|
|
```
|
|
|
|
### Export vers socket UNIX pour traitement externe
|
|
|
|
```yaml
|
|
core:
|
|
interface: eth0
|
|
listen_ports: [443, 8443]
|
|
outputs:
|
|
- type: unix_socket
|
|
enabled: true
|
|
params:
|
|
socket_path: /var/run/ja4sentinel.sock
|
|
```
|
|
|
|
### Logging fichier + stdout
|
|
|
|
```yaml
|
|
core:
|
|
interface: ens192
|
|
listen_ports: [443]
|
|
flow_timeout_sec: 60
|
|
outputs:
|
|
- type: stdout
|
|
enabled: true
|
|
- type: file
|
|
enabled: true
|
|
params:
|
|
path: /var/log/ja4sentinel/ja4.json
|
|
```
|
|
|
|
## Développement
|
|
|
|
### Linting
|
|
|
|
```bash
|
|
make lint
|
|
```
|
|
|
|
### Formatage
|
|
|
|
```bash
|
|
make fmt
|
|
```
|
|
|
|
### Nettoyage
|
|
|
|
```bash
|
|
# Supprime les binaires et images Docker
|
|
make clean
|
|
|
|
# Supprime aussi les conteneurs et volumes
|
|
make clean-all
|
|
```
|
|
|
|
## Licence
|
|
|
|
À définir.
|
|
|
|
## Contribuer
|
|
|
|
1. Fork le projet
|
|
2. Créer une branche de feature (`git checkout -b feature/amélioration`)
|
|
3. Commit les changements (`git commit -am 'Ajout fonctionnalité'`)
|
|
4. Push (`git push origin feature/amélioration`)
|
|
5. Ouvrir une Pull Request
|
|
|
|
---
|
|
|
|
**Voir `architecture.yml` pour la documentation complète de l'architecture.**
|