feat: Ajouter les types Go pour l'API et les interfaces du système
Co-authored-by: aider (openrouter/qwen/qwen3-coder-plus) <aider@aider.chat>
This commit is contained in:
209
internal/api/types.go
Normal file
209
internal/api/types.go
Normal file
@ -0,0 +1,209 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ServiceLog represents internal service logging for diagnostics
|
||||
type ServiceLog struct {
|
||||
Level string `json:"level"`
|
||||
Component string `json:"component"`
|
||||
Message string `json:"message"`
|
||||
Details map[string]string `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// Config holds basic network and TLS configuration
|
||||
type Config struct {
|
||||
Interface string `json:"interface"`
|
||||
ListenPorts []uint16 `json:"listen_ports"`
|
||||
BPFFilter string `json:"bpf_filter,omitempty"`
|
||||
}
|
||||
|
||||
// IPMeta contains IP metadata for stack fingerprinting
|
||||
type IPMeta struct {
|
||||
TTL uint8 `json:"ttl"`
|
||||
TotalLength uint16 `json:"total_length"`
|
||||
IPID uint16 `json:"id"`
|
||||
DF bool `json:"df"`
|
||||
}
|
||||
|
||||
// TCPMeta contains TCP metadata for stack fingerprinting
|
||||
type TCPMeta struct {
|
||||
WindowSize uint16 `json:"window_size"`
|
||||
MSS uint16 `json:"mss,omitempty"`
|
||||
WindowScale uint8 `json:"window_scale,omitempty"`
|
||||
Options []string `json:"options"`
|
||||
}
|
||||
|
||||
// RawPacket represents a raw packet captured from the network
|
||||
type RawPacket struct {
|
||||
Data []byte `json:"-"` // Not serialized
|
||||
Timestamp int64 `json:"timestamp"` // nanoseconds since epoch
|
||||
}
|
||||
|
||||
// TLSClientHello represents a client-side TLS ClientHello with IP/TCP metadata
|
||||
type TLSClientHello struct {
|
||||
SrcIP string `json:"src_ip"`
|
||||
SrcPort uint16 `json:"src_port"`
|
||||
DstIP string `json:"dst_ip"`
|
||||
DstPort uint16 `json:"dst_port"`
|
||||
Payload []byte `json:"-"` // Not serialized
|
||||
IPMeta IPMeta `json:"ip_meta"`
|
||||
TCPMeta TCPMeta `json:"tcp_meta"`
|
||||
}
|
||||
|
||||
// Fingerprints contains TLS fingerprints for a client flow
|
||||
type Fingerprints struct {
|
||||
JA4 string `json:"ja4"`
|
||||
JA4Hash string `json:"ja4_hash"`
|
||||
JA3 string `json:"ja3,omitempty"`
|
||||
JA3Hash string `json:"ja3_hash,omitempty"`
|
||||
}
|
||||
|
||||
// LogRecord is the final log record, serialized as a flat JSON object
|
||||
type LogRecord struct {
|
||||
SrcIP string `json:"src_ip"`
|
||||
SrcPort uint16 `json:"src_port"`
|
||||
DstIP string `json:"dst_ip"`
|
||||
DstPort uint16 `json:"dst_port"`
|
||||
|
||||
// Flattened IPMeta fields
|
||||
IPTTL uint8 `json:"ip_meta_ttl"`
|
||||
IPTotalLen uint16 `json:"ip_meta_total_length"`
|
||||
IPID uint16 `json:"ip_meta_id"`
|
||||
IPDF bool `json:"ip_meta_df"`
|
||||
|
||||
// Flattened TCPMeta fields
|
||||
TCPWindow uint16 `json:"tcp_meta_window_size"`
|
||||
TCPMSS uint16 `json:"tcp_meta_mss,omitempty"`
|
||||
TCPWScale uint8 `json:"tcp_meta_window_scale,omitempty"`
|
||||
TCPOptions string `json:"tcp_meta_options"` // comma-separated list
|
||||
|
||||
// Fingerprints
|
||||
JA4 string `json:"ja4"`
|
||||
JA4Hash string `json:"ja4_hash"`
|
||||
JA3 string `json:"ja3,omitempty"`
|
||||
JA3Hash string `json:"ja3_hash,omitempty"`
|
||||
}
|
||||
|
||||
// OutputConfig defines configuration for a single log output
|
||||
type OutputConfig struct {
|
||||
Type string `json:"type"` // unix_socket, stdout, file, etc.
|
||||
Enabled bool `json:"enabled"` // whether this output is active
|
||||
Params map[string]string `json:"params"` // specific parameters like socket_path, path, etc.
|
||||
}
|
||||
|
||||
// AppConfig is the complete ja4sentinel configuration
|
||||
type AppConfig struct {
|
||||
Core Config `json:"core"`
|
||||
Outputs []OutputConfig `json:"outputs"`
|
||||
}
|
||||
|
||||
// Loader interface loads configuration from file/env/CLI
|
||||
type Loader interface {
|
||||
Load() (AppConfig, error)
|
||||
}
|
||||
|
||||
// Capture interface provides raw network packets
|
||||
type Capture interface {
|
||||
Run(cfg Config, out chan<- RawPacket) error
|
||||
}
|
||||
|
||||
// Parser converts RawPacket to TLSClientHello
|
||||
type Parser interface {
|
||||
Process(pkt RawPacket) (*TLSClientHello, error)
|
||||
}
|
||||
|
||||
// Engine generates JA4 fingerprints from TLS ClientHello
|
||||
type Engine interface {
|
||||
FromClientHello(ch TLSClientHello) (*Fingerprints, error)
|
||||
}
|
||||
|
||||
// Writer is the generic interface for writing results
|
||||
type Writer interface {
|
||||
Write(rec LogRecord) error
|
||||
}
|
||||
|
||||
// UnixSocketWriter implements Writer sending logs to a UNIX socket
|
||||
type UnixSocketWriter interface {
|
||||
Writer
|
||||
Close() error
|
||||
}
|
||||
|
||||
// MultiWriter combines multiple Writers
|
||||
type MultiWriter interface {
|
||||
Writer
|
||||
Add(writer Writer)
|
||||
CloseAll() error
|
||||
}
|
||||
|
||||
// Builder constructs Writers from AppConfig
|
||||
type Builder interface {
|
||||
NewFromConfig(cfg AppConfig) (Writer, error)
|
||||
}
|
||||
|
||||
// Helper functions for creating and converting records
|
||||
|
||||
// NewLogRecord creates a LogRecord from TLSClientHello and Fingerprints
|
||||
func NewLogRecord(ch TLSClientHello, fp *Fingerprints) LogRecord {
|
||||
opts := ""
|
||||
if len(ch.TCPMeta.Options) > 0 {
|
||||
opts = joinStringSlice(ch.TCPMeta.Options, ",")
|
||||
}
|
||||
|
||||
rec := LogRecord{
|
||||
SrcIP: ch.SrcIP,
|
||||
SrcPort: ch.SrcPort,
|
||||
DstIP: ch.DstIP,
|
||||
DstPort: ch.DstPort,
|
||||
IPTTL: ch.IPMeta.TTL,
|
||||
IPTotalLen: ch.IPMeta.TotalLength,
|
||||
IPID: ch.IPMeta.IPID,
|
||||
IPDF: ch.IPMeta.DF,
|
||||
TCPWindow: ch.TCPMeta.WindowSize,
|
||||
TCPMSS: ch.TCPMeta.MSS,
|
||||
TCPWScale: ch.TCPMeta.WindowScale,
|
||||
TCPOptions: opts,
|
||||
}
|
||||
|
||||
if fp != nil {
|
||||
rec.JA4 = fp.JA4
|
||||
rec.JA4Hash = fp.JA4Hash
|
||||
rec.JA3 = fp.JA3
|
||||
rec.JA3Hash = fp.JA3Hash
|
||||
}
|
||||
|
||||
return rec
|
||||
}
|
||||
|
||||
// Helper to join string slice with separator
|
||||
func joinStringSlice(slice []string, sep string) string {
|
||||
if len(slice) == 0 {
|
||||
return ""
|
||||
}
|
||||
result := slice[0]
|
||||
for _, s := range slice[1:] {
|
||||
result += sep + s
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Default values and constants
|
||||
|
||||
const (
|
||||
DefaultInterface = "eth0"
|
||||
DefaultPort = 443
|
||||
DefaultBPFFilter = ""
|
||||
)
|
||||
|
||||
// DefaultConfig returns a configuration with sensible defaults
|
||||
func DefaultConfig() AppConfig {
|
||||
return AppConfig{
|
||||
Core: Config{
|
||||
Interface: DefaultInterface,
|
||||
ListenPorts: []uint16{DefaultPort},
|
||||
BPFFilter: DefaultBPFFilter,
|
||||
},
|
||||
Outputs: []OutputConfig{},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user