@@ -12,12 +12,15 @@ import (
1212 _ "embed"
1313 "html"
1414 "html/template"
15+ "net"
1516 "net/http"
1617 "net/http/pprof"
18+ "net/netip"
1719 "net/url"
1820 "os"
1921 "runtime"
2022 "slices"
23+ "strings"
2124 "sync"
2225 "time"
2326
@@ -119,6 +122,88 @@ var timeStart = time.Now()
119122
120123func uptime () time.Duration { return time .Since (timeStart ).Round (time .Second ) }
121124
125+ type xffDebugPart struct {
126+ Raw string `json:"raw"`
127+ Parsed string `json:"parsed,omitempty"`
128+ Valid bool `json:"valid"`
129+ }
130+
131+ type xffDebugResponse struct {
132+ RemoteAddr string `json:"remote_addr"`
133+ RemoteHost string `json:"remote_host"`
134+ RemoteAddrParsed bool `json:"remote_addr_parsed"`
135+ RemoteAddrIP string `json:"remote_addr_ip,omitempty"`
136+
137+ ConnNetwork string `json:"conn_network,omitempty"`
138+ ListenerNetwork string `json:"listener_network,omitempty"`
139+
140+ UsingDefaultTrustedProxies bool `json:"using_default_trusted_proxies"`
141+ TrustedForwardedSource bool `json:"trusted_forwarded_source"`
142+ TrustedProxies []string `json:"trusted_proxies"`
143+
144+ XForwardedForRaw string `json:"x_forwarded_for_raw"`
145+ XForwardedForParts []xffDebugPart `json:"x_forwarded_for_parts"`
146+ XRealIP string `json:"x_real_ip,omitempty"`
147+ Forwarded string `json:"forwarded,omitempty"`
148+
149+ RealIPResult string `json:"real_ip_result"`
150+ }
151+
152+ func (s * Server ) xffDebugHandler () http.Handler {
153+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
154+ host , _ , err := net .SplitHostPort (r .RemoteAddr )
155+ if err != nil {
156+ host = r .RemoteAddr
157+ }
158+ host = strings .TrimSpace (host )
159+
160+ addr , parseErr := netip .ParseAddr (host )
161+ hasAddr := parseErr == nil
162+
163+ var trustedProxies []string
164+ for _ , prefix := range s .trustedProxies () {
165+ trustedProxies = append (trustedProxies , prefix .String ())
166+ }
167+
168+ var parts []xffDebugPart
169+ for part := range strings .SplitSeq (r .Header .Get ("X-Forwarded-For" ), "," ) {
170+ raw := strings .TrimSpace (part )
171+ if raw == "" {
172+ continue
173+ }
174+
175+ item := xffDebugPart {Raw : raw }
176+ if parsed , err := netip .ParseAddr (raw ); err == nil {
177+ item .Valid = true
178+ item .Parsed = parsed .String ()
179+ }
180+ parts = append (parts , item )
181+ }
182+
183+ connNetwork , _ := r .Context ().Value (connNetworkContextKey ).(string )
184+ resp := xffDebugResponse {
185+ RemoteAddr : r .RemoteAddr ,
186+ RemoteHost : host ,
187+ RemoteAddrParsed : hasAddr ,
188+ ConnNetwork : connNetwork ,
189+ ListenerNetwork : s .listenerNetwork ,
190+ UsingDefaultTrustedProxies : s .TrustedProxies == nil ,
191+ TrustedForwardedSource : s .isTrustedForwardedSource (r , hasAddr , addr ),
192+ TrustedProxies : trustedProxies ,
193+ XForwardedForRaw : r .Header .Get ("X-Forwarded-For" ),
194+ XForwardedForParts : parts ,
195+ XRealIP : r .Header .Get ("X-Real-IP" ),
196+ Forwarded : r .Header .Get ("Forwarded" ),
197+ RealIPResult : s .realIP (r ),
198+ }
199+ if hasAddr {
200+ resp .RemoteAddrIP = addr .String ()
201+ }
202+
203+ RespondJSON (w , resp )
204+ })
205+ }
206+
122207// ServeHTTP implements the [http.Handler] interface.
123208func (d * DebugHandler ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
124209 if r .URL .Path != "/debug/" {
0 commit comments