91 lines
2.5 KiB
Go
91 lines
2.5 KiB
Go
package api
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"net/http"
|
||
|
|
"net/netip"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/ponzischeme89/memby/server/internal/config"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestClientIPFrom(t *testing.T) {
|
||
|
|
trusted := config.DefaultTrustedProxyRanges()
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
remoteAddr string
|
||
|
|
headers map[string]string
|
||
|
|
wantAddr string
|
||
|
|
wantVia string
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "direct public client, no proxy headers believed",
|
||
|
|
remoteAddr: "203.0.113.9:52344",
|
||
|
|
headers: map[string]string{"X-Forwarded-For": "10.0.0.9"},
|
||
|
|
wantAddr: "203.0.113.9",
|
||
|
|
wantVia: "socket",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "through the household proxy, real client in X-Forwarded-For",
|
||
|
|
remoteAddr: "10.0.0.2:41000",
|
||
|
|
headers: map[string]string{"X-Forwarded-For": "203.0.113.42, 10.0.0.2"},
|
||
|
|
wantAddr: "203.0.113.42",
|
||
|
|
wantVia: "forwarded",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "direct LAN client behind the proxy still shows its LAN address",
|
||
|
|
remoteAddr: "10.0.0.2:41000",
|
||
|
|
headers: map[string]string{"X-Forwarded-For": "10.0.0.50"},
|
||
|
|
wantAddr: "10.0.0.50",
|
||
|
|
wantVia: "forwarded",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "proxy sets only X-Real-IP",
|
||
|
|
remoteAddr: "192.168.1.1:8443",
|
||
|
|
headers: map[string]string{"X-Real-IP": "198.51.100.7"},
|
||
|
|
wantAddr: "198.51.100.7",
|
||
|
|
wantVia: "real-ip",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "trusted proxy with no forwarding headers",
|
||
|
|
remoteAddr: "127.0.0.1:5000",
|
||
|
|
wantAddr: "127.0.0.1",
|
||
|
|
wantVia: "socket",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "spoofed X-Real-IP from an untrusted client is ignored",
|
||
|
|
remoteAddr: "203.0.113.9:1000",
|
||
|
|
headers: map[string]string{"X-Real-IP": "10.0.0.1"},
|
||
|
|
wantAddr: "203.0.113.9",
|
||
|
|
wantVia: "socket",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "unparseable remote address",
|
||
|
|
remoteAddr: "garbage",
|
||
|
|
wantAddr: "unknown",
|
||
|
|
wantVia: "none",
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, test := range tests {
|
||
|
|
t.Run(test.name, func(t *testing.T) {
|
||
|
|
header := http.Header{}
|
||
|
|
for key, value := range test.headers {
|
||
|
|
header.Set(key, value)
|
||
|
|
}
|
||
|
|
got := clientIPFrom(test.remoteAddr, header, trusted)
|
||
|
|
if got.String() != test.wantAddr || got.Via != test.wantVia {
|
||
|
|
t.Fatalf("clientIPFrom = %+v, want addr %q via %q", got, test.wantAddr, test.wantVia)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestClientIPFromTrustsNothingWhenListEmpty(t *testing.T) {
|
||
|
|
header := http.Header{"X-Forwarded-For": {"203.0.113.1"}}
|
||
|
|
got := clientIPFrom("10.0.0.2:5000", header, []netip.Prefix{})
|
||
|
|
if got.String() != "10.0.0.2" || got.Via != "socket" {
|
||
|
|
t.Fatalf("clientIPFrom with no trusted proxies = %+v, want 10.0.0.2 via socket", got)
|
||
|
|
}
|
||
|
|
}
|