diff --git a/http/http.go b/http/http.go index 82295ed..2119942 100644 --- a/http/http.go +++ b/http/http.go @@ -5,6 +5,7 @@ import ( "fmt" "html/template" "path/filepath" + "strings" "github.com/mpolden/ipd/iputil" "github.com/mpolden/ipd/iputil/geo" @@ -47,10 +48,22 @@ func New(db geo.Reader) *Server { return &Server{gr: db} } +func ipFromForwardedForHeader(v string) string { + // Handle both comma and comma+space separator + ips := strings.Fields(strings.Replace(v, ",", " ", -1)) + if len(ips) == 0 { + return "" + } + return ips[0] +} + func ipFromRequest(headers []string, r *http.Request) (net.IP, error) { remoteIP := "" for _, header := range headers { remoteIP = r.Header.Get(header) + if http.CanonicalHeaderKey(header) == "X-Forwarded-For" { + remoteIP = ipFromForwardedForHeader(remoteIP) + } if remoteIP != "" { break } diff --git a/http/http_test.go b/http/http_test.go index c30bb05..4c67bae 100644 --- a/http/http_test.go +++ b/http/http_test.go @@ -87,7 +87,7 @@ func TestDisabledHandlers(t *testing.T) { server := testServer() server.LookupPort = nil server.LookupAddr = nil - server.db, _ = geo.New("", "") + server.gr, _ = geo.Open("", "") s := httptest.NewServer(server.Handler()) var tests = []struct { @@ -161,6 +161,8 @@ func TestIPFromRequest(t *testing.T) { {"127.0.0.1:9999", "X-Real-IP", "1.3.3.7", []string{"X-Foo-Bar"}, "127.0.0.1"}, // Trusted header does not match {"127.0.0.1:9999", "X-Real-IP", "1.3.3.7", []string{"X-Real-IP", "X-Forwarded-For"}, "1.3.3.7"}, // Trusted header matches {"127.0.0.1:9999", "X-Forwarded-For", "1.3.3.7", []string{"X-Real-IP", "X-Forwarded-For"}, "1.3.3.7"}, // Second trusted header matches + {"127.0.0.1:9999", "X-Forwarded-For", "1.3.3.7,4.2.4.2", []string{"X-Forwarded-For"}, "1.3.3.7"}, // X-Forwarded-For with multiple entries (commas separator) + {"127.0.0.1:9999", "X-Forwarded-For", "1.3.3.7, 4.2.4.2", []string{"X-Forwarded-For"}, "1.3.3.7"}, // X-Forwarded-For with multiple entries (space+comma separator) } for _, tt := range tests { r := &http.Request{