feat: add return port listener for WAF async callbacks/alerts
This commit is contained in:
parent
32d60a3583
commit
6c8815749f
4 changed files with 39 additions and 0 deletions
|
|
@ -12,6 +12,7 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
WAFURL string `json:"waf_url"`
|
WAFURL string `json:"waf_url"`
|
||||||
|
ReturnPort int `json:"return_port"` // port for WAF async callbacks
|
||||||
HealthInterval int `json:"health_interval"`
|
HealthInterval int `json:"health_interval"`
|
||||||
TimeoutMs int `json:"timeout_ms"`
|
TimeoutMs int `json:"timeout_ms"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
main.go
30
main.go
|
|
@ -41,6 +41,20 @@ func main() {
|
||||||
// Start background health checker.
|
// Start background health checker.
|
||||||
startHealthCheck()
|
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()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
// Static capture handler — all proxied traffic hits this.
|
// 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 != "" {
|
if u := r.FormValue("waf_url"); u != "" {
|
||||||
cfg.WAFURL = u
|
cfg.WAFURL = u
|
||||||
}
|
}
|
||||||
|
if v := r.FormValue("return_port"); v != "" {
|
||||||
|
fmt.Sscanf(v, "%d", &cfg.ReturnPort)
|
||||||
|
}
|
||||||
if v := r.FormValue("health_interval"); v != "" {
|
if v := r.FormValue("health_interval"); v != "" {
|
||||||
fmt.Sscanf(v, "%d", &cfg.HealthInterval)
|
fmt.Sscanf(v, "%d", &cfg.HealthInterval)
|
||||||
}
|
}
|
||||||
|
|
@ -105,6 +122,19 @@ func handleGetStats(w http.ResponseWriter, r *http.Request) {
|
||||||
writeJSON(w, http.StatusOK, metricsSnapshot())
|
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 ---
|
// --- Helpers ---
|
||||||
|
|
||||||
func writeJSON(w http.ResponseWriter, status int, v interface{}) {
|
func writeJSON(w http.ResponseWriter, status int, v interface{}) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ function loadConfig() {
|
||||||
$('#fw-enabled').prop('checked', data.enabled);
|
$('#fw-enabled').prop('checked', data.enabled);
|
||||||
$('#enabled-label').text(data.enabled ? 'Firewall Enabled' : 'Firewall Disabled');
|
$('#enabled-label').text(data.enabled ? 'Firewall Enabled' : 'Firewall Disabled');
|
||||||
$('#waf-url').val(data.waf_url);
|
$('#waf-url').val(data.waf_url);
|
||||||
|
$('#return-port').val(data.return_port);
|
||||||
$('#health-interval').val(data.health_interval);
|
$('#health-interval').val(data.health_interval);
|
||||||
$('#timeout-ms').val(data.timeout_ms);
|
$('#timeout-ms').val(data.timeout_ms);
|
||||||
});
|
});
|
||||||
|
|
@ -31,6 +32,7 @@ function saveConfig() {
|
||||||
data: {
|
data: {
|
||||||
enabled: $('#fw-enabled').is(':checked'),
|
enabled: $('#fw-enabled').is(':checked'),
|
||||||
waf_url: $('#waf-url').val().trim(),
|
waf_url: $('#waf-url').val().trim(),
|
||||||
|
return_port: $('#return-port').val(),
|
||||||
health_interval: $('#health-interval').val(),
|
health_interval: $('#health-interval').val(),
|
||||||
timeout_ms: $('#timeout-ms').val()
|
timeout_ms: $('#timeout-ms').val()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,12 @@
|
||||||
<small>The firewall service that inspects each request and returns a verdict.</small>
|
<small>The firewall service that inspects each request and returns a verdict.</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="return-port">Return Port (async callbacks)</label>
|
||||||
|
<input type="number" id="return-port" placeholder="9090" min="1" max="65535">
|
||||||
|
<small>WAF sends async verdicts/alerts to this port.</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="health-interval">Health Check Interval (s)</label>
|
<label for="health-interval">Health Check Interval (s)</label>
|
||||||
<input type="number" id="health-interval" placeholder="5" min="1" max="60">
|
<input type="number" id="health-interval" placeholder="5" min="1" max="60">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue