// SPDX-License-Identifier: GPL-3.0-or-later package detectors import ( "fmt" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/config" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/netutil" ) // Egress ports interpreter-to-public-IP detection (SID 100016). func Egress(state model.State, cfg config.Config) []model.Alert { alerts := make([]model.Alert, 0) for _, socket := range state.Sockets { // Only established interpreter-owned sockets qualify. Listeners and // connection setup states are handled by other detector families. if socket.State != "ESTAB" || !cfg.Interpreters[socket.Comm] { continue } host, port := netutil.SplitHostPort(socket.Peer) // Private/special addresses and explicit trusted CIDRs are intentionally // silent so routine local services and operator infrastructure stay quiet. if !netutil.IsPublicIP(host) || netutil.IPInCIDRs(host, cfg.EgressAllowCIDRs) { continue } alerts = append(alerts, model.Alert{ SID: 100016, Severity: "HIGH", Signature: "egress", Classtype: "c2-exfil", Key: fmt.Sprintf("egr:%s:%s", optionalPythonInt(socket.PID), host), Detail: fmt.Sprintf( "pid=%s comm=%s -> %s:%s (interpreter to public IP)", optionalPythonInt(socket.PID), socket.Comm, host, port), PIDs: alertPIDs(socket.PID), }) } return alerts }