diff --git a/backend_server.go b/backend_server.go index 53672c7..ed6ee3c 100644 --- a/backend_server.go +++ b/backend_server.go @@ -34,9 +34,11 @@ import ( "log" "net" "net/http" + "net/http/pprof" "net/url" "reflect" "regexp" + runtimepprof "runtime/pprof" "slices" "strings" "sync" @@ -66,6 +68,7 @@ type BackendServer struct { roomSessions RoomSessions version string + debug bool welcomeMessage string turnapikey string @@ -111,8 +114,8 @@ func NewBackendServer(config *goconf.ConfigFile, hub *Hub, version string) (*Bac if !statsAllowedIps.Empty() { log.Printf("Only allowing access to the stats endpoint from %s", statsAllowed) } else { - log.Printf("No IPs configured for the stats endpoint, only allowing access from 127.0.0.1") statsAllowedIps = DefaultAllowedIps() + log.Printf("No IPs configured for the stats endpoint, only allowing access from %s", statsAllowedIps) } invalidSecret := make([]byte, 32) @@ -120,11 +123,14 @@ func NewBackendServer(config *goconf.ConfigFile, hub *Hub, version string) (*Bac return nil, err } + debug, _ := config.GetBool("app", "debug") + result := &BackendServer{ hub: hub, events: hub.events, roomSessions: hub.roomSessions, version: version, + debug: debug, turnapikey: turnapikey, turnsecret: []byte(turnsecret), @@ -145,8 +151,8 @@ func (b *BackendServer) Reload(config *goconf.ConfigFile) { if !statsAllowedIps.Empty() { log.Printf("Only allowing access to the stats endpoint from %s", statsAllowed) } else { - log.Printf("No IPs configured for the stats endpoint, only allowing access from 127.0.0.1") statsAllowedIps = DefaultAllowedIps() + log.Printf("No IPs configured for the stats endpoint, only allowing access from %s", statsAllowedIps) } b.statsAllowedIps.Store(statsAllowedIps) } else { @@ -167,22 +173,42 @@ func (b *BackendServer) Start(r *mux.Router) error { b.welcomeMessage = string(welcomeMessage) + "\n" + if b.debug { + log.Println("Installing debug handlers in \"/debug/pprof\"") + s := r.PathPrefix("/debug/pprof").Subrouter() + s.HandleFunc("", b.setCommonHeaders(b.validateStatsRequest(func(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, "/debug/pprof/", http.StatusTemporaryRedirect) + }))) + s.HandleFunc("/", b.setCommonHeaders(b.validateStatsRequest(pprof.Index))) + s.HandleFunc("/cmdline", b.setCommonHeaders(b.validateStatsRequest(pprof.Cmdline))) + s.HandleFunc("/profile", b.setCommonHeaders(b.validateStatsRequest(pprof.Profile))) + s.HandleFunc("/symbol", b.setCommonHeaders(b.validateStatsRequest(pprof.Symbol))) + s.HandleFunc("/trace", b.setCommonHeaders(b.validateStatsRequest(pprof.Trace))) + for _, profile := range runtimepprof.Profiles() { + name := profile.Name() + handler := pprof.Handler(name) + s.HandleFunc("/"+name, b.setCommonHeaders(b.validateStatsRequest(func(w http.ResponseWriter, r *http.Request) { + handler.ServeHTTP(w, r) + }))) + } + } + s := r.PathPrefix("/api/v1").Subrouter() - s.HandleFunc("/welcome", b.setComonHeaders(b.welcomeFunc)).Methods("GET") - s.HandleFunc("/room/{roomid}", b.setComonHeaders(b.parseRequestBody(b.roomHandler))).Methods("POST") - s.HandleFunc("/stats", b.setComonHeaders(b.validateStatsRequest(b.statsHandler))).Methods("GET") - s.HandleFunc("/serverinfo", b.setComonHeaders(b.validateStatsRequest(b.serverinfoHandler))).Methods("GET") + s.HandleFunc("/welcome", b.setCommonHeaders(b.welcomeFunc)).Methods("GET") + s.HandleFunc("/room/{roomid}", b.setCommonHeaders(b.parseRequestBody(b.roomHandler))).Methods("POST") + s.HandleFunc("/stats", b.setCommonHeaders(b.validateStatsRequest(b.statsHandler))).Methods("GET") + s.HandleFunc("/serverinfo", b.setCommonHeaders(b.validateStatsRequest(b.serverinfoHandler))).Methods("GET") // Expose prometheus metrics at "/metrics". - r.HandleFunc("/metrics", b.setComonHeaders(b.validateStatsRequest(b.metricsHandler))).Methods("GET") + r.HandleFunc("/metrics", b.setCommonHeaders(b.validateStatsRequest(b.metricsHandler))).Methods("GET") // Provide a REST service to get TURN credentials. // See https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00 - r.HandleFunc("/turn/credentials", b.setComonHeaders(b.getTurnCredentials)).Methods("GET") + r.HandleFunc("/turn/credentials", b.setCommonHeaders(b.getTurnCredentials)).Methods("GET") return nil } -func (b *BackendServer) setComonHeaders(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { +func (b *BackendServer) setCommonHeaders(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Server", "nextcloud-spreed-signaling/"+b.version) w.Header().Set("X-Spreed-Signaling-Features", strings.Join(b.hub.info.Features, ", ")) diff --git a/proxy.conf.in b/proxy.conf.in index 22174ac..ac3482b 100644 --- a/proxy.conf.in +++ b/proxy.conf.in @@ -4,7 +4,9 @@ #listen = 127.0.0.1:9090 [app] -# Set to "true" to install pprof debug handlers. +# Set to "true" to install pprof debug handlers. Access will only be possible +# from IPs allowed through the "allowed_ips" option below. +# # See "https://golang.org/pkg/net/http/pprof/" for further information. #debug = false @@ -90,8 +92,9 @@ url = ws://localhost:8188/ #blockedcandidates = 1.2.3.0/24 [stats] -# Comma-separated list of IP addresses that are allowed to access the stats -# endpoint. Leave empty (or commented) to only allow access from "127.0.0.1". +# Comma-separated list of IP addresses that are allowed to access the debug, +# stats and metrics endpoints. +# Leave empty (or commented) to only allow access from localhost. #allowed_ips = [etcd] diff --git a/proxy/proxy_server.go b/proxy/proxy_server.go index b7179c1..89bbd9a 100644 --- a/proxy/proxy_server.go +++ b/proxy/proxy_server.go @@ -246,8 +246,8 @@ func NewProxyServer(r *mux.Router, version string, config *goconf.ConfigFile) (* if !statsAllowedIps.Empty() { log.Printf("Only allowing access to the stats endpoint from %s", statsAllowed) } else { - log.Printf("No IPs configured for the stats endpoint, only allowing access from 127.0.0.1") statsAllowedIps = signaling.DefaultAllowedIps() + log.Printf("No IPs configured for the stats endpoint, only allowing access from %s", statsAllowedIps) } trustedProxies, _ := config.GetString("app", "trustedproxies") @@ -377,14 +377,21 @@ func NewProxyServer(r *mux.Router, version string, config *goconf.ConfigFile) (* if debug, _ := config.GetBool("app", "debug"); debug { log.Println("Installing debug handlers in \"/debug/pprof\"") - r.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index)) - r.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline)) - r.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile)) - r.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol)) - r.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace)) + s := r.PathPrefix("/debug/pprof").Subrouter() + s.HandleFunc("", result.setCommonHeaders(result.validateStatsRequest(func(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, "/debug/pprof/", http.StatusTemporaryRedirect) + }))) + s.HandleFunc("/", result.setCommonHeaders(result.validateStatsRequest(pprof.Index))) + s.HandleFunc("/cmdline", result.setCommonHeaders(result.validateStatsRequest(pprof.Cmdline))) + s.HandleFunc("/profile", result.setCommonHeaders(result.validateStatsRequest(pprof.Profile))) + s.HandleFunc("/symbol", result.setCommonHeaders(result.validateStatsRequest(pprof.Symbol))) + s.HandleFunc("/trace", result.setCommonHeaders(result.validateStatsRequest(pprof.Trace))) for _, profile := range runtimepprof.Profiles() { name := profile.Name() - r.Handle("/debug/pprof/"+name, pprof.Handler(name)) + handler := pprof.Handler(name) + s.HandleFunc("/"+name, result.setCommonHeaders(result.validateStatsRequest(func(w http.ResponseWriter, r *http.Request) { + handler.ServeHTTP(w, r) + }))) } } @@ -594,8 +601,8 @@ func (s *ProxyServer) Reload(config *goconf.ConfigFile) { if !statsAllowedIps.Empty() { log.Printf("Only allowing access to the stats endpoint from %s", statsAllowed) } else { - log.Printf("No IPs configured for the stats endpoint, only allowing access from 127.0.0.1") statsAllowedIps = signaling.DefaultAllowedIps() + log.Printf("No IPs configured for the stats endpoint, only allowing access from %s", statsAllowedIps) } s.statsAllowedIps.Store(statsAllowedIps) } else { diff --git a/server.conf.in b/server.conf.in index 8f437e3..2e0a7cf 100644 --- a/server.conf.in +++ b/server.conf.in @@ -25,7 +25,9 @@ certificate = /etc/nginx/ssl/server.crt key = /etc/nginx/ssl/server.key [app] -# Set to "true" to install pprof debug handlers. +# Set to "true" to install pprof debug handlers. Access will only be possible +# from IPs allowed through the "allowed_ips" option below. +# # See "https://golang.org/pkg/net/http/pprof/" for further information. debug = false @@ -270,8 +272,9 @@ connectionsperhost = 8 #SA = NA [stats] -# Comma-separated list of IP addresses that are allowed to access the stats -# endpoint. Leave empty (or commented) to only allow access from "127.0.0.1". +# Comma-separated list of IP addresses that are allowed to access the debug, +# stats and metrics endpoints. +# Leave empty (or commented) to only allow access from localhost. #allowed_ips = [etcd] diff --git a/server/main.go b/server/main.go index eedf316..80474a8 100644 --- a/server/main.go +++ b/server/main.go @@ -30,7 +30,6 @@ import ( "log" "net" "net/http" - "net/http/pprof" "os" "os/signal" "runtime" @@ -310,19 +309,6 @@ func main() { log.Fatal("Could not start backend server: ", err) } - if debug, _ := config.GetBool("app", "debug"); debug { - log.Println("Installing debug handlers in \"/debug/pprof\"") - r.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index)) - r.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline)) - r.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile)) - r.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol)) - r.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace)) - for _, profile := range runtimepprof.Profiles() { - name := profile.Name() - r.Handle("/debug/pprof/"+name, pprof.Handler(name)) - } - } - var listeners Listeners if saddr, _ := signaling.GetStringOptionWithEnv(config, "https", "listen"); saddr != "" {