mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-29 09:14:33 +00:00
fix(waf-ng): normalize wake host casing so mixed-case Host reaches the waker (ref #896)
The waker Director rebuilt the wake path from the raw req.Host without lowercasing, while OnDemand.Contains matches case-insensitively. A mixed-case Host (hand-typed URL, script caller) would pass the on-demand gate but the waker's exact-match lookup against the lowercase-stored portal_domain would miss, leaving the service permanently unwoken behind the splash. Normalize the same way (lowercase + trim) in the Director before building /_wake/<host>. Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
This commit is contained in:
parent
942ecbb3a6
commit
0770b52f79
|
|
@ -134,6 +134,53 @@ func TestOnDemandProxiesToWaker(t *testing.T) {
|
|||
// still gets 421 from this same handler code path.
|
||||
}
|
||||
|
||||
// TestOnDemandProxiesWithMixedCaseHost verifies that a mixed/upper-case Host
|
||||
// header — which OnDemand.Contains already matches case-insensitively — is
|
||||
// normalized to lowercase by the waker Director too, so the wake key sent to
|
||||
// the waker matches the lowercase portal_domain stored in on-demand-vhosts.json.
|
||||
// Without this normalization the waker's exact-match lookup on the mixed-case
|
||||
// path would miss and the wake would never fire (permanent splash).
|
||||
func TestOnDemandProxiesWithMixedCaseHost(t *testing.T) {
|
||||
sockPath := filepath.Join(t.TempDir(), "waker3.sock")
|
||||
ln, err := net.Listen("unix", sockPath)
|
||||
if err != nil {
|
||||
t.Fatalf("listen unix %s: %v", sockPath, err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
var gotPath string
|
||||
waker := &http.Server{
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotPath = r.URL.Path
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
_, _ = io.WriteString(w, "waking up…")
|
||||
}),
|
||||
}
|
||||
go waker.Serve(ln) //nolint:errcheck
|
||||
defer waker.Close()
|
||||
|
||||
srv := &Server{
|
||||
routeLookup: func(host string) (string, int, bool) { return "", 0, false },
|
||||
// Stored lowercase, exactly as the on-demand-vhosts.json generator emits it.
|
||||
onDemand: &OnDemand{entries: map[string]bool{"sleepy.example.com": true}},
|
||||
wakerSocket: sockPath,
|
||||
}
|
||||
|
||||
handler := srv.handler()
|
||||
// Mixed-case Host header — a hand-typed URL or script caller.
|
||||
req := httptest.NewRequest(http.MethodGet, "http://Sleepy.Example.COM/", nil)
|
||||
req.Host = "Sleepy.Example.COM"
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusServiceUnavailable {
|
||||
t.Fatalf("expected 503 from waker splash, got %d", rec.Code)
|
||||
}
|
||||
if gotPath != "/_wake/sleepy.example.com" {
|
||||
t.Fatalf("expected canonical lowercase waker path /_wake/sleepy.example.com, got %q", gotPath)
|
||||
}
|
||||
}
|
||||
|
||||
// TestOnDemandVisitsExcluded verifies that a request served by the waker
|
||||
// splash is NOT tallied into the legitimate visit-stats (mirrors the existing
|
||||
// 403/421 exclusion).
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// defaultWakerSocket is the production path to the waker's unix socket.
|
||||
|
|
@ -56,6 +57,14 @@ func (s *Server) wakerProxy() *httputil.ReverseProxy {
|
|||
if err != nil {
|
||||
host = req.Host
|
||||
}
|
||||
// Normalize exactly like OnDemand.Contains / Routes.Lookup
|
||||
// (lowercase + trim) so the wake key sent to the waker matches
|
||||
// the lowercase portal_domain stored in on-demand-vhosts.json
|
||||
// regardless of the casing a client sent in its Host header.
|
||||
// Without this, a mixed-case Host would pass the on-demand
|
||||
// gate (case-insensitive) but miss the waker's exact-match
|
||||
// lookup, leaving the service permanently unwoken.
|
||||
host = strings.ToLower(strings.TrimSpace(host))
|
||||
// Dummy scheme/host: the Transport ignores them and always
|
||||
// dials the unix socket above; only the rewritten path
|
||||
// carries the information the waker needs.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user