diff --git a/caddyhttp/httpserver/context.go b/caddyhttp/httpserver/context.go index d7d233c5d..33fa602c4 100644 --- a/caddyhttp/httpserver/context.go +++ b/caddyhttp/httpserver/context.go @@ -63,6 +63,18 @@ func (c Context) Header(name string) string { return c.Req.Header.Get(name) } +// Hostname gets the (remote) hostname of the client making the request. +func (c Context) Hostname() string { + ip := c.IP() + + hostnameList, err := net.LookupAddr(ip) + if err != nil || len(hostnameList) == 0 { + return c.Req.RemoteAddr + } + + return hostnameList[0] +} + // Env gets a map of the environment variables. func (c Context) Env() map[string]string { osEnv := os.Environ() diff --git a/caddyhttp/httpserver/context_test.go b/caddyhttp/httpserver/context_test.go index 50d9c67ff..dfd5cb226 100644 --- a/caddyhttp/httpserver/context_test.go +++ b/caddyhttp/httpserver/context_test.go @@ -244,6 +244,37 @@ func TestHeader(t *testing.T) { } } +func TestHostname(t *testing.T) { + context := getContextOrFail(t) + + tests := []struct { + inputRemoteAddr string + expectedHostname string + }{ + // Test 0 - ipv4 with port + {"8.8.8.8:1111", "google-public-dns-a.google.com."}, + // Test 1 - ipv4 without port + {"8.8.8.8", "google-public-dns-a.google.com."}, + // Test 2 - ipv6 with port + {"[2001:4860:4860::8888]:11", "google-public-dns-a.google.com."}, + // Test 3 - ipv6 without port and brackets + {"2001:4860:4860::8888", "google-public-dns-a.google.com."}, + // Test 4 - no hostname available + {"1.1.1.1", "1.1.1.1"}, + } + + for i, test := range tests { + testPrefix := getTestPrefix(i) + + context.Req.RemoteAddr = test.inputRemoteAddr + actualHostname := context.Hostname() + + if actualHostname != test.expectedHostname { + t.Errorf(testPrefix+"Expected hostname %s, found %s", test.expectedHostname, actualHostname) + } + } +} + func TestEnv(t *testing.T) { context := getContextOrFail(t)