mirror of
https://github.com/juanfont/headscale.git
synced 2026-04-11 03:27:20 +02:00
debug: route statsviz through tsweb.Protected
Build the statsviz Server directly and wrap its Index/Ws handlers in tsweb.Protected instead of calling statsviz.Register on the raw mux which bypasses AllowDebugAccess.
This commit is contained in:
@@ -3,7 +3,9 @@ package hscontrol
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/arl/statsviz"
|
||||
@@ -12,6 +14,35 @@ import (
|
||||
"tailscale.com/tsweb"
|
||||
)
|
||||
|
||||
// protectedDebugHandler wraps an http.Handler with an access check that
|
||||
// allows requests from loopback, Tailscale CGNAT IPs, and private
|
||||
// (RFC 1918 / RFC 4193) addresses. This extends tsweb.Protected which
|
||||
// only allows loopback and Tailscale IPs.
|
||||
func protectedDebugHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if tsweb.AllowDebugAccess(r) {
|
||||
h.ServeHTTP(w, r)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// tsweb.AllowDebugAccess rejects X-Forwarded-For and non-TS IPs.
|
||||
// Additionally allow private/LAN addresses so operators can reach
|
||||
// debug endpoints from their local network without tailscaled.
|
||||
ipStr, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err == nil {
|
||||
ip, parseErr := netip.ParseAddr(ipStr)
|
||||
if parseErr == nil && ip.IsPrivate() {
|
||||
h.ServeHTTP(w, r)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
http.Error(w, "debug access denied", http.StatusForbidden)
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Headscale) debugHTTPServer() *http.Server {
|
||||
debugMux := http.NewServeMux()
|
||||
debug := tsweb.Debugger(debugMux)
|
||||
@@ -293,8 +324,13 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||
}
|
||||
}))
|
||||
|
||||
err := statsviz.Register(debugMux)
|
||||
// statsviz.Register would mount handlers directly on the raw mux,
|
||||
// bypassing the access gate. Build the server by hand and wrap
|
||||
// each handler with protectedDebugHandler.
|
||||
statsvizSrv, err := statsviz.NewServer()
|
||||
if err == nil {
|
||||
debugMux.Handle("/debug/statsviz/", protectedDebugHandler(statsvizSrv.Index()))
|
||||
debugMux.Handle("/debug/statsviz/ws", protectedDebugHandler(statsvizSrv.Ws()))
|
||||
debug.URL("/debug/statsviz", "Statsviz (visualise go metrics)")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user