zoraxy-waf/proxy.go

58 lines
1.5 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"time"
)
const maxBodySample = 4096
// inspect sends the request metadata + body sample to the WAF for inspection.
// Returns the WAF's HTTP status code or an error if unreachable.
func inspect(r *http.Request) (int, error) {
cfg := getConfig()
// Sample body.
var bodySample []byte
if r.Body != nil {
bodySample = make([]byte, maxBodySample)
n, _ := io.ReadFull(r.Body, bodySample)
bodySample = bodySample[:n]
// Restore body so downstream can read it.
r.Body = io.NopCloser(io.MultiReader(bytes.NewReader(bodySample), r.Body))
}
// Build inspection payload with the original URI.
originalPath := r.Header.Get("X-Zoraxy-Uri")
if originalPath == "" {
originalPath = r.URL.String()
}
payload, err := json.Marshal(map[string]interface{}{
"method": r.Method,
"url": originalPath,
"host": r.Host,
"remote_addr": r.RemoteAddr,
"content_type": r.Header.Get("Content-Type"),
"content_length": r.ContentLength,
"headers": r.Header,
"body_sample": bodySample,
})
if err != nil {
return 0, fmt.Errorf("marshal: %w", err)
}
client := &http.Client{Timeout: time.Duration(cfg.TimeoutMs) * time.Millisecond}
resp, err := client.Post(cfg.WAFURL+"/inspect", "application/json", bytes.NewReader(payload))
if err != nil {
return 0, fmt.Errorf("unreachable: %w", err)
}
defer resp.Body.Close()
log.Printf("Firewall: %s %s → status %d", r.Method, r.URL.Path, resp.StatusCode)
return resp.StatusCode, nil
}