From 698bea4ec84721eb8ca997b448ae1f3bf188c4a7 Mon Sep 17 00:00:00 2001 From: Ole Bertram Date: Wed, 6 Dec 2023 19:48:05 +0100 Subject: [PATCH] Fix inaccessible metrics endpoint when listening on Unix socket --- internal/http/request/client_ip.go | 11 ++--------- internal/http/request/client_ip_test.go | 10 +++++----- internal/http/server/httpd.go | 8 +++++++- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/internal/http/request/client_ip.go b/internal/http/request/client_ip.go index f145c36a..e403e029 100644 --- a/internal/http/request/client_ip.go +++ b/internal/http/request/client_ip.go @@ -30,20 +30,13 @@ func FindClientIP(r *http.Request) string { return FindRemoteIP(r) } -// FindRemoteIP returns remote client IP address. +// FindRemoteIP returns remote client IP address without considering HTTP headers. func FindRemoteIP(r *http.Request) string { remoteIP, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil { remoteIP = r.RemoteAddr } - remoteIP = dropIPv6zone(remoteIP) - - // When listening on a Unix socket, RemoteAddr is empty. - if remoteIP == "" { - remoteIP = "127.0.0.1" - } - - return remoteIP + return dropIPv6zone(remoteIP) } func dropIPv6zone(address string) string { diff --git a/internal/http/request/client_ip_test.go b/internal/http/request/client_ip_test.go index 7f958d64..3c03a193 100644 --- a/internal/http/request/client_ip_test.go +++ b/internal/http/request/client_ip_test.go @@ -104,20 +104,20 @@ func TestClientIPWithBothHeaders(t *testing.T) { } } -func TestClientIPWithNoRemoteAddress(t *testing.T) { - r := &http.Request{} +func TestClientIPWithUnixSocketRemoteAddress(t *testing.T) { + r := &http.Request{RemoteAddr: "@"} - if ip := FindClientIP(r); ip != "127.0.0.1" { + if ip := FindClientIP(r); ip != "@" { t.Fatalf(`Unexpected result, got: %q`, ip) } } -func TestClientIPWithoutRemoteAddrAndBothHeaders(t *testing.T) { +func TestClientIPWithUnixSocketRemoteAddrAndBothHeaders(t *testing.T) { headers := http.Header{} headers.Set("X-Forwarded-For", "203.0.113.195, 70.41.3.18, 150.172.238.178") headers.Set("X-Real-Ip", "192.168.122.1") - r := &http.Request{RemoteAddr: "", Header: headers} + r := &http.Request{RemoteAddr: "@", Header: headers} if ip := FindClientIP(r); ip != "203.0.113.195" { t.Fatalf(`Unexpected result, got: %q`, ip) diff --git a/internal/http/server/httpd.go b/internal/http/server/httpd.go index 87875be4..c7428a32 100644 --- a/internal/http/server/httpd.go +++ b/internal/http/server/httpd.go @@ -268,6 +268,12 @@ func isAllowedToAccessMetricsEndpoint(r *http.Request) bool { } } + remoteIP := request.FindRemoteIP(r) + if remoteIP == "@" { + // This indicates a request sent via a Unix socket, always consider these trusted. + return true + } + for _, cidr := range config.Opts.MetricsAllowedNetworks() { _, network, err := net.ParseCIDR(cidr) if err != nil { @@ -283,7 +289,7 @@ func isAllowedToAccessMetricsEndpoint(r *http.Request) bool { // We use r.RemoteAddr in this case because HTTP headers like X-Forwarded-For can be easily spoofed. // The recommendation is to use HTTP Basic authentication. - if network.Contains(net.ParseIP(request.FindRemoteIP(r))) { + if network.Contains(net.ParseIP(remoteIP)) { return true } }