diff --git a/config.go b/config.go index c991a2f..477f3d4 100644 --- a/config.go +++ b/config.go @@ -12,6 +12,7 @@ import ( type Config struct { Enabled bool `json:"enabled"` WAFURL string `json:"waf_url"` + ReturnPort int `json:"return_port"` // port for WAF async callbacks HealthInterval int `json:"health_interval"` TimeoutMs int `json:"timeout_ms"` } diff --git a/main.go b/main.go index 6c83da5..424509f 100644 --- a/main.go +++ b/main.go @@ -41,6 +41,20 @@ func main() { // Start background health checker. startHealthCheck() + // Return port listener for WAF async callbacks. + cfg := getConfig() + if cfg.ReturnPort > 0 { + go func() { + rmux := http.NewServeMux() + rmux.HandleFunc("/verdict", handleReturnVerdict) + addr := fmt.Sprintf(":%d", cfg.ReturnPort) + log.Printf("Firewall: return listener on %s", addr) + if err := http.ListenAndServe(addr, rmux); err != nil { + log.Printf("Firewall: return listener error: %v", err) + } + }() + } + mux := http.NewServeMux() // Static capture handler — all proxied traffic hits this. @@ -85,6 +99,9 @@ func handleSaveConfig(w http.ResponseWriter, r *http.Request) { if u := r.FormValue("waf_url"); u != "" { cfg.WAFURL = u } + if v := r.FormValue("return_port"); v != "" { + fmt.Sscanf(v, "%d", &cfg.ReturnPort) + } if v := r.FormValue("health_interval"); v != "" { fmt.Sscanf(v, "%d", &cfg.HealthInterval) } @@ -105,6 +122,19 @@ func handleGetStats(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, metricsSnapshot()) } +func handleReturnVerdict(w http.ResponseWriter, r *http.Request) { + var v struct { + Verdict string `json:"verdict"` + Reason string `json:"reason"` + } + if err := json.NewDecoder(r.Body).Decode(&v); err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": "bad payload"}) + return + } + log.Printf("Firewall: async verdict %s (reason=%s)", v.Verdict, v.Reason) + writeJSON(w, http.StatusOK, map[string]string{"status": "ok"}) +} + // --- Helpers --- func writeJSON(w http.ResponseWriter, status int, v interface{}) { diff --git a/web/app.js b/web/app.js index 263946e..c30acb1 100644 --- a/web/app.js +++ b/web/app.js @@ -5,6 +5,7 @@ function loadConfig() { $('#fw-enabled').prop('checked', data.enabled); $('#enabled-label').text(data.enabled ? 'Firewall Enabled' : 'Firewall Disabled'); $('#waf-url').val(data.waf_url); + $('#return-port').val(data.return_port); $('#health-interval').val(data.health_interval); $('#timeout-ms').val(data.timeout_ms); }); @@ -31,6 +32,7 @@ function saveConfig() { data: { enabled: $('#fw-enabled').is(':checked'), waf_url: $('#waf-url').val().trim(), + return_port: $('#return-port').val(), health_interval: $('#health-interval').val(), timeout_ms: $('#timeout-ms').val() }, diff --git a/web/index.html b/web/index.html index 83d4520..70ebf18 100644 --- a/web/index.html +++ b/web/index.html @@ -31,6 +31,12 @@ The firewall service that inspects each request and returns a verdict. +