package api // 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"` Timestamp int64 `json:"timestamp,omitempty"` // Unix nanoseconds (auto-set by logger) TraceID string `json:"trace_id,omitempty"` // Optional distributed tracing ID ConnID string `json:"conn_id,omitempty"` // Optional TCP flow identifier } // 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"` FlowTimeoutSec int `json:"flow_timeout_sec,omitempty"` // Timeout for TLS handshake extraction (default: 30) } // 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 Close() error } // Parser converts RawPacket to TLSClientHello type Parser interface { Process(pkt RawPacket) (*TLSClientHello, error) Close() 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) } // Logger interface for service logging type Logger interface { Debug(component, message string, details map[string]string) Info(component, message string, details map[string]string) Warn(component, message string, details map[string]string) Error(component, message string, details map[string]string) } // 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, ",") } // Helper to create pointer from value for optional fields var mssPtr *uint16 if ch.TCPMeta.MSS != 0 { mssPtr = &ch.TCPMeta.MSS } var wScalePtr *uint8 if ch.TCPMeta.WindowScale != 0 { wScalePtr = &ch.TCPMeta.WindowScale } 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: mssPtr, TCPWScale: wScalePtr, 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 = "" DefaultFlowTimeout = 30 // seconds // Logging levels LogLevelDebug = "DEBUG" LogLevelInfo = "INFO" LogLevelWarn = "WARN" LogLevelError = "ERROR" ) // DefaultConfig returns a configuration with sensible defaults func DefaultConfig() AppConfig { return AppConfig{ Core: Config{ Interface: DefaultInterface, ListenPorts: []uint16{DefaultPort}, BPFFilter: DefaultBPFFilter, FlowTimeoutSec: DefaultFlowTimeout, }, Outputs: []OutputConfig{}, } }