Compare commits
2
Commits
08b05907a5
...
1740ac6061
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1740ac6061 | ||
|
|
6e370b346b |
No files matched your search
@@ -2326,7 +2326,8 @@ but for these headers:
|
|||||||
claims and are replaced. `X-Forwarded-For` names the peer, `X-Forwarded-Host`
|
claims and are replaced. `X-Forwarded-For` names the peer, `X-Forwarded-Host`
|
||||||
the host it asked for, and `X-Forwarded-Proto` plain `http`. Every other
|
the host it asked for, and `X-Forwarded-Proto` plain `http`. Every other
|
||||||
header whose name starts with `X-Forwarded-` is removed, and so are
|
header whose name starts with `X-Forwarded-` is removed, and so are
|
||||||
`Forwarded` and `X-Real-IP`.
|
`Forwarded` and `X-Real-IP`. A name spelt with `_` for `-`, such as
|
||||||
|
`X_Forwarded_Ssl`, counts as the same name.
|
||||||
- `X-Request-ID`, which carries the fresh id.
|
- `X-Request-ID`, which carries the fresh id.
|
||||||
- `X-Client-ASN` and `X-Client-Country`, which carry what `waf` answered. A
|
- `X-Client-ASN` and `X-Client-Country`, which carry what `waf` answered. A
|
||||||
header it did not give is left out. Any of the two the visitor sent is
|
header it did not give is left out. Any of the two the visitor sent is
|
||||||
|
|||||||
@@ -105,17 +105,16 @@ func setForwardedHeaders(in, out *http.Request, peer netip.Addr, trusted bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReverseProxy has removed Forwarded and the three set below. Go's server
|
// An app behind CGI or FastCGI reads X_Forwarded_Ssl as X-Forwarded-Ssl, so
|
||||||
// gives header names in canonical form, so the prefix matches the name in
|
// a name is matched with each _ read as - and in any letter case.
|
||||||
// any letter case.
|
|
||||||
for name := range out.Header {
|
for name := range out.Header {
|
||||||
if strings.HasPrefix(name, "X-Forwarded-") {
|
spelt := strings.ToLower(strings.ReplaceAll(name, "_", "-"))
|
||||||
|
if strings.HasPrefix(spelt, "x-forwarded-") ||
|
||||||
|
spelt == "forwarded" || spelt == "x-real-ip" {
|
||||||
delete(out.Header, name)
|
delete(out.Header, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Header.Del("X-Real-IP")
|
|
||||||
|
|
||||||
out.Header.Set("X-Forwarded-For", forwardedFor)
|
out.Header.Set("X-Forwarded-For", forwardedFor)
|
||||||
out.Header.Set("X-Forwarded-Host", in.Host)
|
out.Header.Set("X-Forwarded-Host", in.Host)
|
||||||
out.Header.Set("X-Forwarded-Proto", "http")
|
out.Header.Set("X-Forwarded-Proto", "http")
|
||||||
|
|||||||
@@ -561,6 +561,7 @@ func TestAPeerNotTrustedHasItsForwardedHeadersReplaced(t *testing.T) {
|
|||||||
"X-Forwarded-Tls-Client-Cert-Info", "X-Real-Ip",
|
"X-Forwarded-Tls-Client-Cert-Info", "X-Real-Ip",
|
||||||
"X-Forwarded-Scheme", "X-Forwarded-Ssl", "X-Forwarded-Protocol",
|
"X-Forwarded-Scheme", "X-Forwarded-Ssl", "X-Forwarded-Protocol",
|
||||||
"X-Forwarded-Path", "X-Forwarded-Client-Cert",
|
"X-Forwarded-Path", "X-Forwarded-Client-Cert",
|
||||||
|
"X_Forwarded_Ssl", "X_Forwarded_Proto", "X_Real_IP",
|
||||||
}
|
}
|
||||||
|
|
||||||
standIn := startWAF(t, allow)
|
standIn := startWAF(t, allow)
|
||||||
@@ -628,6 +629,7 @@ func TestATrustedProxysForwardedHeadersPassOn(t *testing.T) {
|
|||||||
forwardedProtoHeader: "https",
|
forwardedProtoHeader: "https",
|
||||||
"X-Real-Ip": "198.51.100.1",
|
"X-Real-Ip": "198.51.100.1",
|
||||||
"X-Forwarded-Ssl": "on",
|
"X-Forwarded-Ssl": "on",
|
||||||
|
"X_Forwarded_Ssl": "on",
|
||||||
}
|
}
|
||||||
|
|
||||||
req := newRequest(t, http.MethodGet, addr, "/", http.NoBody)
|
req := newRequest(t, http.MethodGet, addr, "/", http.NoBody)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func TestHealthCheckInWAFsContainer(t *testing.T) {
|
|||||||
exited <- run(ctx, settings, out)
|
exited <- run(ctx, settings, out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
addr, _ := out.line(t, "msg", "starting")["address"].(string)
|
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
|
||||||
_, port, _ := net.SplitHostPort(addr)
|
_, port, _ := net.SplitHostPort(addr)
|
||||||
|
|
||||||
// The container's settings: an address to listen on with an empty
|
// The container's settings: an address to listen on with an empty
|
||||||
|
|||||||
+31
-35
@@ -71,6 +71,8 @@ func startRProxy(t *testing.T, backend, appURL string) (string, *output) {
|
|||||||
}, out)
|
}, out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
|
||||||
|
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
stop()
|
stop()
|
||||||
|
|
||||||
@@ -86,8 +88,6 @@ func startRProxy(t *testing.T, backend, appURL string) (string, *output) {
|
|||||||
out.line(t, "msg", "stopped")
|
out.line(t, "msg", "stopped")
|
||||||
})
|
})
|
||||||
|
|
||||||
addr, _ := out.line(t, "msg", "starting")["address"].(string)
|
|
||||||
|
|
||||||
return "http://" + addr, out
|
return "http://" + addr, out
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ func startWAF(t *testing.T, env map[string]string) (string, *output, func()) {
|
|||||||
exited <- run(ctx, env, out)
|
exited <- run(ctx, env, out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
addr, _ := out.line(t, "msg", "starting")["address"].(string)
|
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
|
||||||
|
|
||||||
return addr, out, func() {
|
return addr, out, func() {
|
||||||
stop()
|
stop()
|
||||||
@@ -507,9 +507,10 @@ func TestAStatusWAFDoesNotTakeIsReportedAs599(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// startRProxyProcess runs `sww rproxy` in a process of its own, with the
|
// startRProxyProcess runs `sww rproxy` in a process of its own, with the
|
||||||
// settings in env, each as NAME=value. It returns where rproxy listens, the
|
// settings in env, each as NAME=value. It returns where rproxy listens and a
|
||||||
// process, and what rproxy writes.
|
// function that sends rproxy SIGTERM and fails the test unless it exits with
|
||||||
func startRProxyProcess(t *testing.T, env ...string) (string, *exec.Cmd, *output) {
|
// status 0 within waitLimit.
|
||||||
|
func startRProxyProcess(t *testing.T, env ...string) (string, func()) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
binary, err := os.Executable()
|
binary, err := os.Executable()
|
||||||
@@ -517,11 +518,8 @@ func startRProxyProcess(t *testing.T, env ...string) (string, *exec.Cmd, *output
|
|||||||
t.Fatalf("find the test binary: %v", err)
|
t.Fatalf("find the test binary: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(t.Context(), 3*waitLimit)
|
|
||||||
t.Cleanup(cancel)
|
|
||||||
|
|
||||||
out := &output{}
|
out := &output{}
|
||||||
cmd := exec.CommandContext(ctx, binary) //nolint:gosec // this test binary
|
cmd := exec.CommandContext(t.Context(), binary) //nolint:gosec // this test binary
|
||||||
cmd.Stdout = out
|
cmd.Stdout = out
|
||||||
|
|
||||||
cmd.Env = append(os.Environ(),
|
cmd.Env = append(os.Environ(),
|
||||||
@@ -529,19 +527,25 @@ func startRProxyProcess(t *testing.T, env ...string) (string, *exec.Cmd, *output
|
|||||||
"SWRP_LISTEN_ADDR="+localhost+":0")
|
"SWRP_LISTEN_ADDR="+localhost+":0")
|
||||||
cmd.Env = append(cmd.Env, env...)
|
cmd.Env = append(cmd.Env, env...)
|
||||||
|
|
||||||
err = cmd.Start()
|
exited := startProcess(t, cmd)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("start: %v", err)
|
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
|
||||||
|
|
||||||
|
return addr, func() {
|
||||||
|
err := cmd.Process.Signal(syscall.SIGTERM)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("signal: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case status := <-exited:
|
||||||
|
if status != 0 {
|
||||||
|
t.Errorf("exit status %d, want 0; output:\n%s", status, out.text())
|
||||||
|
}
|
||||||
|
case <-time.After(waitLimit):
|
||||||
|
t.Error("still running after being told to stop")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Cleanup(func() {
|
|
||||||
_ = cmd.Process.Kill()
|
|
||||||
_ = cmd.Wait()
|
|
||||||
})
|
|
||||||
|
|
||||||
addr, _ := out.line(t, "msg", "starting")["address"].(string)
|
|
||||||
|
|
||||||
return addr, cmd, out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRProxyAsksAWAFThatSpeaksHTTP2OverHTTP1(t *testing.T) {
|
func TestRProxyAsksAWAFThatSpeaksHTTP2OverHTTP1(t *testing.T) {
|
||||||
@@ -572,7 +576,7 @@ func TestRProxyAsksAWAFThatSpeaksHTTP2OverHTTP1(t *testing.T) {
|
|||||||
t.Fatalf("write the certificate: %v", err)
|
t.Fatalf("write the certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, _, _ := startRProxyProcess(t,
|
addr, _ := startRProxyProcess(t,
|
||||||
wafBackend+"="+backend.URL,
|
wafBackend+"="+backend.URL,
|
||||||
"SWRP_UPSTREAM_URL="+startApp(t),
|
"SWRP_UPSTREAM_URL="+startApp(t),
|
||||||
"SSL_CERT_FILE="+certificates)
|
"SSL_CERT_FILE="+certificates)
|
||||||
@@ -651,7 +655,7 @@ func TestRProxyStoppingWaitsForAReportBeingSent(t *testing.T) {
|
|||||||
exited <- runRProxy(ctx, env, out)
|
exited <- runRProxy(ctx, env, out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
addr, _ := out.line(t, "msg", "starting")["address"].(string)
|
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
|
||||||
|
|
||||||
wantStatus(t, "http://"+addr+"/", placed, http.StatusOK)
|
wantStatus(t, "http://"+addr+"/", placed, http.StatusOK)
|
||||||
|
|
||||||
@@ -750,7 +754,7 @@ func TestRProxyStoppingCutsOffARequestAfterFiveSeconds(t *testing.T) {
|
|||||||
exited <- runRProxy(ctx, env, out)
|
exited <- runRProxy(ctx, env, out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
addr, _ := out.line(t, "msg", "starting")["address"].(string)
|
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
|
||||||
conn := sendAndKeepOpen(t, addr, "GET / HTTP/1.1\r\nHost: site.example\r\n\r\n")
|
conn := sendAndKeepOpen(t, addr, "GET / HTTP/1.1\r\nHost: site.example\r\n\r\n")
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -845,7 +849,7 @@ func TestMainRunsRProxy(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Nothing listens there; the health check does not ask.
|
// Nothing listens there; the health check does not ask.
|
||||||
addr, cmd, out := startRProxyProcess(t, wafBackend+"=http://127.0.0.1:9")
|
addr, stop := startRProxyProcess(t, wafBackend+"=http://127.0.0.1:9")
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(t.Context(), http.MethodGet,
|
req, err := http.NewRequestWithContext(t.Context(), http.MethodGet,
|
||||||
"http://"+addr+waf.HealthPath, http.NoBody)
|
"http://"+addr+waf.HealthPath, http.NoBody)
|
||||||
@@ -868,13 +872,5 @@ func TestMainRunsRProxy(t *testing.T) {
|
|||||||
t.Errorf("health check answered %q (%v)", body, err)
|
t.Errorf("health check answered %q (%v)", body, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmd.Process.Signal(syscall.SIGTERM)
|
stop()
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("signal: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("exit: %v; output:\n%s", err, out.text())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+40
-18
@@ -38,6 +38,35 @@ func TestMain(m *testing.M) {
|
|||||||
os.Exit(sww.Main(testVersion))
|
os.Exit(sww.Main(testVersion))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// startProcess starts cmd and returns a channel that gets its exit status. As
|
||||||
|
// the test ends, cmd is killed and the test waits for it to exit.
|
||||||
|
func startProcess(t *testing.T, cmd *exec.Cmd) <-chan int {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("start: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
exited := make(chan int, 1)
|
||||||
|
waitReturned := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
_ = cmd.Wait()
|
||||||
|
exited <- cmd.ProcessState.ExitCode()
|
||||||
|
|
||||||
|
close(waitReturned)
|
||||||
|
}()
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
_ = cmd.Process.Kill()
|
||||||
|
|
||||||
|
<-waitReturned
|
||||||
|
})
|
||||||
|
|
||||||
|
return exited
|
||||||
|
}
|
||||||
|
|
||||||
func TestMainRunsWAF(t *testing.T) {
|
func TestMainRunsWAF(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -54,12 +83,9 @@ func TestMainRunsWAF(t *testing.T) {
|
|||||||
t.Fatalf("find the test binary: %v", err)
|
t.Fatalf("find the test binary: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(t.Context(), 3*waitLimit)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
out := &output{}
|
out := &output{}
|
||||||
cmd := exec.CommandContext(ctx, binary) //nolint:gosec // this test binary
|
cmd := exec.CommandContext(t.Context(), binary) //nolint:gosec // this test binary
|
||||||
cmd.Stdout = out
|
cmd.Stdout = out
|
||||||
|
|
||||||
cmd.Env = append(os.Environ(),
|
cmd.Env = append(os.Environ(),
|
||||||
@@ -70,17 +96,9 @@ func TestMainRunsWAF(t *testing.T) {
|
|||||||
rulesDir+"="+t.TempDir(),
|
rulesDir+"="+t.TempDir(),
|
||||||
lookupSource+"=off")
|
lookupSource+"=off")
|
||||||
|
|
||||||
err = cmd.Start()
|
exited := startProcess(t, cmd)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("start: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Cleanup(func() {
|
starting := out.lineBeforeExit(t, "starting", exited)
|
||||||
_ = cmd.Process.Kill()
|
|
||||||
_ = cmd.Wait()
|
|
||||||
})
|
|
||||||
|
|
||||||
starting := out.line(t, "msg", "starting")
|
|
||||||
addr, _ := starting["address"].(string)
|
addr, _ := starting["address"].(string)
|
||||||
ask(t, addr, "/", http.StatusOK, waf.DispositionAllow)
|
ask(t, addr, "/", http.StatusOK, waf.DispositionAllow)
|
||||||
|
|
||||||
@@ -90,9 +108,13 @@ func TestMainRunsWAF(t *testing.T) {
|
|||||||
t.Fatalf("signal: %v", err)
|
t.Fatalf("signal: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmd.Wait()
|
select {
|
||||||
if err != nil {
|
case status := <-exited:
|
||||||
t.Fatalf("exit: %v; output:\n%s", err, out.text())
|
if status != 0 {
|
||||||
|
t.Fatalf("exit status %d, want 0; output:\n%s", status, out.text())
|
||||||
|
}
|
||||||
|
case <-time.After(waitLimit):
|
||||||
|
t.Fatal("still running after being told to stop")
|
||||||
}
|
}
|
||||||
|
|
||||||
wantUTC(t, "the process line", starting["time"])
|
wantUTC(t, "the process line", starting["time"])
|
||||||
@@ -215,7 +237,7 @@ func runWAF(t *testing.T, env map[string]string, use func(addr string)) {
|
|||||||
exited <- run(ctx, env, out)
|
exited <- run(ctx, env, out)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
addr, _ := out.line(t, "msg", "starting")["address"].(string)
|
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
|
||||||
use(addr)
|
use(addr)
|
||||||
stop()
|
stop()
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user