mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
proxy: Fix transparent pass-thru of existing X-Forwarded-For headers
* Fixes #1960 Transparent proxy not appending existing X-Forwarded-For header * Fixes #1960 Formatting Code
This commit is contained in:
parent
64c18a7c6c
commit
88edca65d3
3 changed files with 85 additions and 7 deletions
|
@ -913,6 +913,67 @@ func TestHostSimpleProxyNoHeaderForward(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestReverseProxyTransparentHeaders(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
remoteAddr string
|
||||
forwardedForHeader string
|
||||
expected []string
|
||||
}{
|
||||
{"No header", "192.168.0.1:80", "", []string{"192.168.0.1"}},
|
||||
{"Existing", "192.168.0.1:80", "1.1.1.1, 2.2.2.2", []string{"1.1.1.1, 2.2.2.2, 192.168.0.1"}},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
testReverseProxyTransparentHeaders(t, tc.remoteAddr, tc.forwardedForHeader, tc.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testReverseProxyTransparentHeaders(t *testing.T, remoteAddr, forwardedForHeader string, expected []string) {
|
||||
// Arrange
|
||||
log.SetOutput(ioutil.Discard)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
|
||||
var actualHeaders http.Header
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
actualHeaders = r.Header
|
||||
}))
|
||||
defer backend.Close()
|
||||
|
||||
config := "proxy / " + backend.URL + " {\n transparent \n}"
|
||||
|
||||
// make proxy
|
||||
upstreams, err := NewStaticUpstreams(caddyfile.NewDispenser("Testfile", strings.NewReader(config)), "")
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error. Got: %s", err.Error())
|
||||
}
|
||||
|
||||
// set up proxy
|
||||
p := &Proxy{
|
||||
Next: httpserver.EmptyNext, // prevents panic in some cases when test fails
|
||||
Upstreams: upstreams,
|
||||
}
|
||||
|
||||
// create request and response recorder
|
||||
r := httptest.NewRequest("GET", backend.URL, nil)
|
||||
r.RemoteAddr = remoteAddr
|
||||
if forwardedForHeader != "" {
|
||||
r.Header.Set("X-Forwarded-For", forwardedForHeader)
|
||||
}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
// Act
|
||||
p.ServeHTTP(w, r)
|
||||
|
||||
// Assert
|
||||
if got := actualHeaders["X-Forwarded-For"]; !reflect.DeepEqual(got, expected) {
|
||||
t.Errorf("Transparent proxy response does not contain expected %v header: expect %v, but got %v",
|
||||
"X-Forwarded-For", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostHeaderReplacedUsingForward(t *testing.T) {
|
||||
var requestHost string
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -943,11 +1004,22 @@ func TestHostHeaderReplacedUsingForward(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBasicAuth(t *testing.T) {
|
||||
basicAuthTestcase(t, nil, nil)
|
||||
basicAuthTestcase(t, nil, url.UserPassword("username", "password"))
|
||||
basicAuthTestcase(t, url.UserPassword("usename", "password"), nil)
|
||||
basicAuthTestcase(t, url.UserPassword("unused", "unused"),
|
||||
url.UserPassword("username", "password"))
|
||||
testCases := []struct {
|
||||
name string
|
||||
upstreamUser *url.Userinfo
|
||||
clientUser *url.Userinfo
|
||||
}{
|
||||
{"Nil Both", nil, nil},
|
||||
{"Nil Upstream User", nil, url.UserPassword("username", "password")},
|
||||
{"Nil Client User", url.UserPassword("usename", "password"), nil},
|
||||
{"Both Provided", url.UserPassword("unused", "unused"),
|
||||
url.UserPassword("username", "password")},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
basicAuthTestcase(t, tc.upstreamUser, tc.clientUser)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func basicAuthTestcase(t *testing.T, upstreamUser, clientUser *url.Userinfo) {
|
||||
|
|
|
@ -431,9 +431,10 @@ func parseBlock(c *caddyfile.Dispenser, u *staticUpstream, hasSrv bool) error {
|
|||
}
|
||||
u.downstreamHeaders.Add(header, value)
|
||||
case "transparent":
|
||||
// Note: X-Forwarded-For header is always being appended for proxy connections
|
||||
// See implementation of createUpstreamRequest in proxy.go
|
||||
u.upstreamHeaders.Add("Host", "{host}")
|
||||
u.upstreamHeaders.Add("X-Real-IP", "{remote}")
|
||||
u.upstreamHeaders.Add("X-Forwarded-For", "{remote}")
|
||||
u.upstreamHeaders.Add("X-Forwarded-Proto", "{scheme}")
|
||||
case "websocket":
|
||||
u.upstreamHeaders.Add("Connection", "{>Connection}")
|
||||
|
|
|
@ -282,7 +282,8 @@ func TestStop(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseBlock(t *testing.T) {
|
||||
func TestParseBlockTransparent(t *testing.T) {
|
||||
// tests for transparent proxy presets
|
||||
r, _ := http.NewRequest("GET", "/", nil)
|
||||
tests := []struct {
|
||||
config string
|
||||
|
@ -316,6 +317,10 @@ func TestParseBlock(t *testing.T) {
|
|||
if _, ok := headers["X-Forwarded-Proto"]; !ok {
|
||||
t.Errorf("Test %d: Could not find the X-Forwarded-Proto header", i+1)
|
||||
}
|
||||
|
||||
if _, ok := headers["X-Forwarded-For"]; ok {
|
||||
t.Errorf("Test %d: Found unexpected X-Forwarded-For header", i+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue