package app import ( "net/http" "strings" "time" ) // --------------------------------------------------------------------- // traffic audit (sanity checks / duplicates / nft consistency) // --------------------------------------------------------------------- // // EN: Provides a pragmatic sanity-check endpoint for troubleshooting. // EN: We check: // EN: - traffic mode health (evaluateTrafficMode) // EN: - runtime marks duplicates (target+app_key) // EN: - nft chain consistency (state <-> output_apps rules) // RU: Практичный sanity-check эндпоинт для диагностики. // RU: Проверяем: // RU: - health traffic mode (evaluateTrafficMode) // RU: - дубли runtime marks (target+app_key) // RU: - консистентность nft chain (state <-> output_apps rules) func handleTrafficAudit(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } now := time.Now().UTC().Format(time.RFC3339) // 1) Traffic mode status (includes route probe). traffic := evaluateTrafficMode(loadTrafficModeState()) // 2) Profiles (persistent) duplicates by (target, app_key). profiles := listTrafficAppProfiles() profDups := findProfileDuplicates(profiles) // 3) Runtime marks state + duplicates. _ = pruneExpiredAppMarks() appMarksMu.Lock() marksSt := loadAppMarksState() appMarksMu.Unlock() markDups := findMarkDuplicates(marksSt.Items) // 4) nft output_apps rules check (state <-> nft). nftIssues, nftSummary := auditNftAppMarks(marksSt.Items) issues := []string{} if !traffic.Healthy { issues = append(issues, "traffic_mode_unhealthy: "+strings.TrimSpace(traffic.Message)) } for _, d := range profDups { issues = append(issues, "profile_duplicate: "+d) } for _, d := range markDups { issues = append(issues, "mark_duplicate: "+d) } issues = append(issues, nftIssues...) ok := true for _, it := range issues { if strings.HasPrefix(it, "traffic_mode_unhealthy:") || strings.HasPrefix(it, "nft_error:") || strings.HasPrefix(it, "nft_missing_rule:") { ok = false break } } pretty := buildTrafficAuditPretty(now, traffic, profiles, marksSt.Items, issues, nftSummary) writeJSON(w, http.StatusOK, map[string]any{ "ok": ok, "now": now, "message": "ok", "pretty": pretty, "traffic": traffic, "counts": map[string]any{ "profiles": len(profiles), "marks": len(marksSt.Items), }, "issues": issues, "nft": nftSummary, }) }