package clientip import ( "net/http" "net/netip" "testing" ) func TestResolverUsesRemoteAddressByDefault(t *testing.T) { req := &http.Request{ Header: http.Header{"X-Forwarded-For": {"203.0.113.10"}}, RemoteAddr: "198.51.100.20:54123", } got := (Resolver{}).FromRequest(req) want := "198.51.100.20" if got != want { t.Fatalf("got %q, want %q", got, want) } } func TestResolverCanTrustForwardedFor(t *testing.T) { req := &http.Request{ Header: http.Header{ "X-Forwarded-For": {"203.0.113.10, 198.51.100.20"}, }, RemoteAddr: "192.0.2.30:54123", } got := (Resolver{TrustProxyHeaders: true}).FromRequest(req) want := "203.0.113.10" if got != want { t.Fatalf("got %q, want %q", got, want) } } func TestResolverCanTrustRFCForwardedHeader(t *testing.T) { req := &http.Request{ Header: http.Header{ "Forwarded": {`for="203.0.113.10";proto=https;host=ip.example.com`}, }, RemoteAddr: "192.0.2.30:54123", } got := (Resolver{TrustProxyHeaders: true}).FromRequest(req) want := "203.0.113.10" if got != want { t.Fatalf("got %q, want %q", got, want) } } func TestResolverOnlyTrustsConfiguredProxyCIDRs(t *testing.T) { trustedProxy := netip.MustParsePrefix("127.0.0.1/32") resolver := Resolver{ TrustProxyHeaders: true, TrustedProxies: []netip.Prefix{trustedProxy}, } req := &http.Request{ Header: http.Header{"X-Forwarded-For": {"203.0.113.10"}}, RemoteAddr: "198.51.100.20:54123", } got := resolver.FromRequest(req) want := "198.51.100.20" if got != want { t.Fatalf("got %q, want %q", got, want) } } func TestResolverTrustsForwardedHeaderFromConfiguredProxyCIDR(t *testing.T) { trustedProxy := netip.MustParsePrefix("127.0.0.1/32") resolver := Resolver{ TrustProxyHeaders: true, TrustedProxies: []netip.Prefix{trustedProxy}, } req := &http.Request{ Header: http.Header{"X-Forwarded-For": {"203.0.113.10"}}, RemoteAddr: "127.0.0.1:54123", } got := resolver.FromRequest(req) want := "203.0.113.10" if got != want { t.Fatalf("got %q, want %q", got, want) } } func TestResolverFallsBackToRealIPHeader(t *testing.T) { req := &http.Request{ Header: http.Header{"X-Real-IP": {"203.0.113.10"}}, RemoteAddr: "192.0.2.30:54123", } got := (Resolver{TrustProxyHeaders: true}).FromRequest(req) want := "203.0.113.10" if got != want { t.Fatalf("got %q, want %q", got, want) } } func TestResolverHandlesIPv6RemoteAddress(t *testing.T) { req := &http.Request{ Header: http.Header{}, RemoteAddr: "[2001:db8::1]:54123", } got := (Resolver{}).FromRequest(req) want := "2001:db8::1" if got != want { t.Fatalf("got %q, want %q", got, want) } } func TestResolverSkipsInvalidForwardedForEntries(t *testing.T) { req := &http.Request{ Header: http.Header{ "X-Forwarded-For": {"unknown, 203.0.113.10"}, }, RemoteAddr: "192.0.2.30:54123", } got := (Resolver{TrustProxyHeaders: true}).FromRequest(req) want := "203.0.113.10" if got != want { t.Fatalf("got %q, want %q", got, want) } }