# Version macro must be defined BEFORE it's used in Version: field # Override from command line: rpmbuild --define "build_version X.Y.Z" %if %{defined build_version} %define spec_version %{build_version} %else %define spec_version 1.1.18 %endif Name: ja4sentinel Version: %{spec_version} Release: 1%{?dist} Summary: JA4 TLS fingerprinting daemon for network monitoring License: MIT URL: https://github.com/your-repo/ja4sentinel BuildArch: x86_64 # Distribution-agnostic dependencies # systemd is available on all target distros (Rocky 8/9/10, AlmaLinux) Requires: systemd # libpcap is required for packet capture (dynamically linked) # Version varies by distro: Rocky 8/9/10 (1.9.0+) Requires: libpcap >= 1.9.0 %description JA4Sentinel is a Go-based tool for capturing network traffic on Linux servers, extracting client-side TLS handshakes, generating JA4 signatures, enriching with IP/TCP metadata, and logging results to configurable outputs. Features: - Network packet capture with BPF filters - TLS ClientHello extraction - JA4/JA3 fingerprint generation - IP/TCP metadata enrichment - Multiple output formats (UNIX socket by default, stdout, file) - Structured JSON logging for systemd/journald - Compatible with Rocky Linux 8/9/10, RHEL, AlmaLinux %prep # No source to unpack, binary is pre-built %build # No build needed, binary is pre-built %install mkdir -p %{buildroot}/usr/bin mkdir -p %{buildroot}/etc/ja4sentinel mkdir -p %{buildroot}/etc/logrotate.d mkdir -p %{buildroot}/var/lib/ja4sentinel mkdir -p %{buildroot}/var/log/ja4sentinel mkdir -p %{buildroot}/var/run/logcorrelator mkdir -p %{buildroot}/usr/lib/systemd/system mkdir -p %{buildroot}/usr/share/ja4sentinel # Install binary install -m 755 %{_sourcedir}/ja4sentinel %{buildroot}/usr/bin/ja4sentinel # Install systemd service install -m 644 %{_sourcedir}/ja4sentinel.service %{buildroot}/usr/lib/systemd/system/ja4sentinel.service # Install logrotate configuration install -m 644 %{_sourcedir}/logrotate/ja4sentinel %{buildroot}/etc/logrotate.d/ja4sentinel # Install default config install -m 640 %{_sourcedir}/config.yml %{buildroot}/etc/ja4sentinel/config.yml.default install -m 640 %{_sourcedir}/config.yml %{buildroot}/usr/share/ja4sentinel/config.yml %pre # No user creation needed - service runs as root for packet capture exit 0 %post # Set proper ownership (root:root for packet capture) chown -R root:root /var/lib/ja4sentinel 2>/dev/null || true chown -R root:root /var/run/logcorrelator 2>/dev/null || true chown -R root:root /var/log/ja4sentinel 2>/dev/null || true chown -R root:root /etc/ja4sentinel 2>/dev/null || true # Set proper permissions chmod 750 /var/lib/ja4sentinel 2>/dev/null || true chmod 750 /var/log/ja4sentinel 2>/dev/null || true chmod 750 /etc/ja4sentinel 2>/dev/null || true # Install config if not exists if [ ! -f /etc/ja4sentinel/config.yml ]; then cp /usr/share/ja4sentinel/config.yml /etc/ja4sentinel/config.yml chmod 640 /etc/ja4sentinel/config.yml fi # Reload systemd and enable service (only if systemd is running) if [ -x /bin/systemctl ] && [ -d /run/systemd/system ]; then /bin/systemctl daemon-reload /bin/systemctl enable ja4sentinel.service 2>/dev/null || : /bin/systemctl start ja4sentinel.service 2>/dev/null || : fi %preun if [ $1 -eq 0 ]; then # Package removal, stop and disable service if [ -x /bin/systemctl ]; then /bin/systemctl stop ja4sentinel.service >/dev/null 2>&1 || : /bin/systemctl disable ja4sentinel.service >/dev/null 2>&1 || : fi fi %postun if [ $1 -eq 0 ]; then # Package removal, reload systemd if [ -x /bin/systemctl ]; then /bin/systemctl daemon-reload fi fi %files /usr/bin/ja4sentinel /usr/lib/systemd/system/ja4sentinel.service /etc/logrotate.d/ja4sentinel /usr/share/ja4sentinel/config.yml %config(noreplace) /etc/ja4sentinel/config.yml.default %dir /etc/ja4sentinel %dir /var/lib/ja4sentinel %dir /var/log/ja4sentinel %dir /var/run/logcorrelator %changelog * Mon Mar 09 2026 Jacquin Antoine - 1.1.18-1 - FEATURE: Add comprehensive metrics for capture and TLS parser monitoring - Capture metrics: packets_received, packets_sent, packets_dropped (atomic counters) - Parser metrics: retransmit_count, gap_detected_count, buffer_exceeded_count, segment_exceeded_count - New GetStats() method on Capture interface for capture statistics - New GetMetrics() method on Parser interface for parser statistics - Add DefaultMaxHelloSegments constant (100) to prevent memory leaks from fragmented handshakes - Add Segments field to ConnectionFlow for per-flow segment tracking - Increase DefaultMaxTrackedFlows from 50000 to 100000 for high-traffic scenarios - Improve TCP reassembly: better handling of retransmissions and sequence gaps - Memory leak prevention: limit segments per flow and buffer size - Aggressive flow cleanup: clean up JA4_DONE flows when approaching flow limit - Lock ordering fix: release flow.mu before acquiring p.mu to avoid deadlocks - Exclude IPv6 link-local addresses (fe80::) from local IP detection - Improve error logging with detailed connection and TLS extension information - Add capture diagnostics logging (interface, link_type, local_ips, bpf_filter) - Fix false positive retransmission counter when SYN packet is missed - Fix gap handling: reset sequence tracking instead of dropping flow - Fix extractTLSExtensions: return error details with basic TLS info for debugging * Mon Mar 09 2026 Jacquin Antoine - 1.1.17-1 - FEATURE: Default network interface set to "any" for automatic multi-interface capture - No manual configuration required - captures on all interfaces out of the box - Supports physical (ens18, eth0), virtual, Docker, VPN interfaces automatically - Linux SLL (cooked capture) used for interface "any" - already implemented and tested * Mon Mar 09 2026 Jacquin Antoine - 1.1.16-1 - FEATURE: Add comprehensive metrics for capture and TLS parser monitoring - Capture: packets_received, packets_sent, packets_dropped counters (atomic) - Parser: retransmit_count, gap_detected_count, buffer_exceeded_count, segment_exceeded_count - New GetStats() method on Capture interface for capture statistics - New GetMetrics() method on Parser interface for parser statistics - Add DefaultMaxHelloSegments constant (100) to prevent memory leaks from fragmented handshakes - Add Segments field to ConnectionFlow for per-flow segment tracking - Improve TCP reassembly: better handling of retransmissions and sequence gaps - Memory leak prevention: limit segments per flow and buffer size - All counters use sync/atomic for thread-safe access without locks - Metrics designed for monitoring/debugging (can be exposed via future endpoints) * Thu Mar 05 2026 Jacquin Antoine - 1.1.15-1 - FIX: ALPN not appearing in logs for packets with truncated/malformed TLS extensions - Add sanitization fallback in extractTLSExtensions (same as fingerprint engine) - ALPN (tls_alpn) now correctly extracted even when ParseClientHello fails on raw payload * Thu Mar 05 2026 Jacquin Antoine - 1.1.14-1 - FIX: Handle ClientHellos with truncated extension data (extension data truncated) - Sanitize malformed extensions by trimming to last complete extension before retry - Fingerprints (JA4/JA3) now generated even for slightly malformed ClientHellos - Added unit tests for extension sanitization and truncated extension handling * Thu Mar 05 2026 Jacquin Antoine - 1.1.13-1 - FIX: BPF filter uses 'tcp dst port' instead of 'tcp port' to capture client-to-server traffic only - FIX: SYN packet handling — detect SYN before payload-length check, create flow with IP/TCP metadata - FIX: SynToCHMs timing now uses SYN timestamp instead of first data packet timestamp - FIX: Fragmented ClientHello uses flow metadata from SYN instead of last fragment's packet metadata - FIX: TCP reassembly sequence tracking — detect retransmissions (skip) and gaps (drop flow) - Added TLS 1.3 supported_versions test coverage (verified library already handles it correctly) - 9 new unit tests for SYN handling, TCP reassembly, TLS 1.3, and fragmentation metadata * Thu Mar 05 2026 Jacquin Antoine - 1.1.12-1 - FIX: Remove JA4SENTINEL_LOG_LEVEL env override (architecture violation, log_level YAML-only) - FIX: Add yaml struct tags to Config/AppConfig/OutputConfig (yaml.v3 does not fall back to json tags) - FIX: SLL packet parsing rewritten to use protoType from SLL header for IPv4/IPv6 selection - FIX: Replace isValidIP/isValidCIDR with net.ParseIP/net.ParseCIDR for proper validation - FIX: Various pre-existing unit test bugs (TestLoadFromFile_ExcludeSourceIPs, TestFromClientHello_NilPayload, TestValidate_ExcludeSourceIPs) * Wed Mar 04 2026 Jacquin Antoine - 1.1.11-1 - FIX: Remove JA4SENTINEL_LOG_LEVEL environment variable from systemd service - Config file log_level now respected (no env var override) - FIX: Add exclude_source_ips to config merge function (mergeConfigs) - FIX: Add validation for exclude_source_ips entries (IP/CIDR) - New isValidIP() and isValidCIDR() helper functions - Config file exclude_source_ips now properly loaded and validated - DEBUG: Add IP filter debug logging for troubleshooting - Log filter entries at startup in debug mode - Track filtered packet count with atomic counter - Display filter statistics at shutdown - New GetFilterStats() method on parser for monitoring - Added unit tests for exclude_source_ips and log_level config loading * Wed Mar 04 2026 Jacquin Antoine - 1.1.10-1 - DEBUG: Add IP filter debug logging for troubleshooting - Log filter entries at startup in debug mode - Track filtered packet count with atomic counter - Display filter statistics at shutdown - New GetFilterStats() method on parser for monitoring - FIX: Add exclude_source_ips to config merge function - FIX: Add validation for exclude_source_ips entries (IP/CIDR) - Helps diagnose exclude_source_ips filtering issues * Wed Mar 04 2026 Jacquin Antoine - 1.1.9-1 - FEATURE: Add source IP exclusion with CIDR support - New exclude_source_ips configuration option - Support single IPs (192.168.1.1) and CIDR ranges (10.0.0.0/8) - Filter packets before TLS processing to reduce load - IPv4 and IPv6 support - New ipfilter package with unit tests - Log exclusion configuration at startup * Wed Mar 04 2026 Jacquin Antoine - 1.1.8-1 - CRITICAL FIX: Resolve crash in TLS parser with nil decode context - Use gopacket.NewPacket with LinkTypeIPv4/IPv6 instead of DecodeFromBytes - Fixes panic: runtime error: invalid memory address or nil pointer dereference - Properly handles raw IP packets after SLL header stripping * Wed Mar 04 2026 Jacquin Antoine - 1.1.7-1 - FIX: Improve error logging with source/destination details - Add src_ip, src_port, dst_ip, dst_port to tlsparse error logs - Add connection details to fingerprint error logs (conn_id, payload_len) - Include 'unknown' placeholders for packets that fail before parsing - Helps debug truncated ClientHello payloads and identify problematic connections * Wed Mar 04 2026 Jacquin Antoine - 1.1.6-1 - FEATURE: Add support for capturing traffic to local machine IPs only - Add local_ips configuration option (auto-detect or manual list) - Auto-detection excludes loopback addresses (127.x.x.x, ::1) - Support interface "any" for capturing on all network interfaces - Add Linux SLL (cooked capture) support for interface "any" - Generate BPF filter with "dst host" for local IP filtering - Add LinkType field to RawPacket for proper packet parsing - Add unit tests for local IP detection and SLL packet parsing - Update version to 1.1.6 * Mon Mar 02 2026 Jacquin Antoine - 1.1.5-1 - Fix: Use unixgram (DGRAM) instead of unix (STREAM) for socket output - Fixes "protocol wrong type for socket" error - DGRAM sockets are connectionless, better suited for log shipping * Mon Mar 02 2026 Jacquin Antoine - 1.1.4-1 - Add error callback for file output writer - File write errors (permission, disk space, rotation) now logged - Same error reporting mechanism as UNIX socket writer * Mon Mar 02 2026 Jacquin Antoine - 1.1.2-1 - Add error callback mechanism for UNIX socket connection failures - Add ErrorCallback type and WithErrorCallback option for UnixSocketWriter - Add BuilderImpl.WithErrorCallback() for propagating error callbacks - Add processQueue error reporting with consecutive failure tracking - Add 50+ new unit tests across all modules (capture, config, fingerprint, tlsparse, output, cmd) - Add integration tests for full pipeline (TLS ClientHello -> fingerprint -> output) - Add tests for FileWriter.rotate() and FileWriter.Reopen() log rotation - Add tests for cleanupExpiredFlows() and cleanupLoop() in TLS parser - Add tests for extractSNIFromPayload() and extractJA4Hash() helpers - Add tests for config load error paths (invalid YAML, permission denied) - Update architecture.yml with new fields (LogLevel, TLSClientHello extensions) - Update architecture.yml with Close() methods for Capture and Parser interfaces - Remove empty internal/api/ directory * Mon Mar 02 2026 Jacquin Antoine - 1.1.0-1 - Add logrotate configuration for automatic log file rotation - Add SIGHUP signal handling for log file reopening (systemctl reload) - Add ExecReload to systemd service for graceful log rotation - Add Reopenable interface for output writers supporting log rotation - Add FileWriter.Reopen() method for log file rotation support - Add MultiWriter.Reopen() method to propagate rotation to all writers - Update main.go to handle SIGHUP signal for log rotation - Add packaging/logrotate/ja4sentinel configuration file - Update architecture.yml with logrotate and reload documentation - Update Dockerfile.package to include logrotate file in RPM build * Mon Mar 02 2026 Jacquin Antoine - 1.0.9-1 - Add SNI (Server Name Indication) extraction from TLS ClientHello - Add ALPN (Application-Layer Protocol Negotiation) extraction - Add TLS version detection from ClientHello - Add ConnID field for flow correlation - Add SensorID field for multi-sensor deployments - Add SynToCHMs timing field for behavioral detection - Add AsyncBuffer configuration for output queue sizing - Remove JA4Hash from LogRecord (JA4 format includes its own hash) - Use tlsfingerprint library for ALPN and TLS version parsing - Update architecture.yml compliance for all new fields - Add unit tests for TLS extension extraction * Sun Mar 01 2026 Jacquin Antoine - 1.0.8-1 - Add configurable log level (debug, info, warn, error) via config.yml - Add JA4SENTINEL_LOG_LEVEL environment variable support - Set TimeoutStopSec=2 for immediate service stop on restart/stop - Consolidate config files into single example (config.yml.example) * Sat Feb 28 2026 Jacquin Antoine - 1.0.4-1 - Add systemd sdnotify support (READY, WATCHDOG, STOPPING signals) - Enable systemd watchdog with 30s timeout - Update service unit to Type=notify - Document sdnotify integration in architecture.yml * Sat Feb 28 2026 JA4Sentinel Team - 1.0.2-1 - BREAKING: Drop CentOS 7 support (EOL June 2024), minimum Rocky Linux 8 - Fix race condition in TLS parser with per-ConnectionFlow mutex - Fix memory leak in fragmented ClientHello buffer accumulation - Add log file rotation (100MB, 3 backups) - Improve UNIX socket reconnection with async queue and exponential backoff - Add BPF filter validation (characters, length, balanced parentheses) - Secure file permissions (0600 instead of 0644) - Add 46 unit tests (capture, output, logging) - Enable race detection in test pipeline (go test -race) - Increase pcap snaplen from 1600 to 65535 bytes for large TLS handshakes - Increase socket timeouts (2s to 5s) with configurable backoff - Add named constants for configuration values * Sat Feb 28 2026 JA4Sentinel Team - 1.0.1-1 - Add configurable packet channel buffer size for high-throughput capture - Add timestamp field to LogRecord for precise event tracking - Fix race condition: close packetChan after capture goroutine finishes - Strengthen TLS limits and socket timeouts for robustness - Improve configuration validation with stricter checks - Include systemd service file in RPM packages - Unified Docker-based packaging for CentOS 7, Rocky Linux 8/9/10 - Add comprehensive unit tests for API and cmd packages - Add Godoc documentation for all public interfaces * Wed Feb 25 2026 JA4Sentinel Team - 1.0.0-1 - Initial package release for CentOS 7, Rocky Linux 8/9/10