package main import ( "fmt" "net" "strings" ) // Domain/path restrictions describe HTTP probes only. An IP-only rule also // matches conntrack initiators; a destination match never hides other clients. type MonitoringRule struct { IP string `json:"ip"` Domain string `json:"domain,omitempty"` PathPrefix string `json:"pathPrefix,omitempty"` } func validateMonitoringRules(rules []MonitoringRule) ([]MonitoringRule, error) { if len(rules) > 32 { return nil, fmt.Errorf("Не более 32 правил мониторинга") } result := make([]MonitoringRule, 0, len(rules)) for i, r := range rules { ip := net.ParseIP(strings.TrimSpace(r.IP)) if ip == nil { return nil, fmt.Errorf("Правило %d: нужен точный IPv4/IPv6-адрес", i+1) } r.IP = ip.String() r.Domain = strings.ToLower(strings.TrimSpace(r.Domain)) r.PathPrefix = strings.TrimSpace(r.PathPrefix) if len(r.Domain) > 253 || strings.ContainsAny(r.Domain, " /|\t\r\n") || len(r.PathPrefix) > 256 || strings.ContainsAny(r.PathPrefix, "|\r\n") || (r.PathPrefix != "" && !strings.HasPrefix(r.PathPrefix, "/")) { return nil, fmt.Errorf("Правило %d: проверьте домен и префикс пути (начинается с /)", i+1) } result = append(result, r) } return result, nil } func isMonitoringRequest(e TrafficEvent, rules []MonitoringRule) bool { if e.Kind != "request" { return false } for _, r := range rules { if e.IP == r.IP && (r.Domain == "" || strings.EqualFold(e.Domain, r.Domain)) && strings.HasPrefix(e.Path, r.PathPrefix) { return true } } return false } func isMonitoringFlow(f NetworkFlow, rules []MonitoringRule) bool { for _, r := range rules { if net.ParseIP(f.Source).Equal(net.ParseIP(r.IP)) && r.Domain == "" && r.PathPrefix == "" { return true } } return false } func monitoringSQL(rules []MonitoringRule) (string, []any) { var parts []string var args []any for _, r := range rules { p := "(ip=?" args = append(args, r.IP) if r.Domain != "" { p += " AND lower(domain)=?" args = append(args, r.Domain) } if r.PathPrefix != "" { p += " AND substr(path,1,length(?))=?" args = append(args, r.PathPrefix, r.PathPrefix) } parts = append(parts, p+")") } if len(parts) == 0 { return "", nil } return " AND NOT (kind='request' AND (" + strings.Join(parts, " OR ") + "))", args }