| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 | 
							- // Copyright (C) 2019-2023 Nicola Murino
 
- //
 
- // This program is free software: you can redistribute it and/or modify
 
- // it under the terms of the GNU Affero General Public License as published
 
- // by the Free Software Foundation, version 3.
 
- //
 
- // This program is distributed in the hope that it will be useful,
 
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
 
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
- // GNU Affero General Public License for more details.
 
- //
 
- // You should have received a copy of the GNU Affero General Public License
 
- // along with this program. If not, see <https://www.gnu.org/licenses/>.
 
- // Package telemetry provides telemetry information for SFTPGo, such as:
 
- //   - health information (for health checks)
 
- //   - metrics
 
- //   - profiling information
 
- package telemetry
 
- import (
 
- 	"crypto/tls"
 
- 	"log"
 
- 	"net/http"
 
- 	"path/filepath"
 
- 	"runtime"
 
- 	"time"
 
- 	"github.com/go-chi/chi/v5"
 
- 	"github.com/drakkan/sftpgo/v2/internal/common"
 
- 	"github.com/drakkan/sftpgo/v2/internal/logger"
 
- 	"github.com/drakkan/sftpgo/v2/internal/util"
 
- )
 
- const (
 
- 	logSender     = "telemetry"
 
- 	metricsPath   = "/metrics"
 
- 	pprofBasePath = "/debug"
 
- )
 
- var (
 
- 	router   *chi.Mux
 
- 	httpAuth common.HTTPAuthProvider
 
- 	certMgr  *common.CertManager
 
- )
 
- // Conf telemetry server configuration.
 
- type Conf struct {
 
- 	// The port used for serving HTTP requests. 0 disable the HTTP server. Default: 0
 
- 	BindPort int `json:"bind_port" mapstructure:"bind_port"`
 
- 	// The address to listen on. A blank value means listen on all available network interfaces. Default: "127.0.0.1"
 
- 	BindAddress string `json:"bind_address" mapstructure:"bind_address"`
 
- 	// Enable the built-in profiler.
 
- 	// The profiler will be accessible via HTTP/HTTPS using the base URL "/debug/pprof/"
 
- 	EnableProfiler bool `json:"enable_profiler" mapstructure:"enable_profiler"`
 
- 	// Path to a file used to store usernames and password for basic authentication.
 
- 	// This can be an absolute path or a path relative to the config dir.
 
- 	// We support HTTP basic authentication and the file format must conform to the one generated using the Apache
 
- 	// htpasswd tool. The supported password formats are bcrypt ($2y$ prefix) and md5 crypt ($apr1$ prefix).
 
- 	// If empty HTTP authentication is disabled
 
- 	AuthUserFile string `json:"auth_user_file" mapstructure:"auth_user_file"`
 
- 	// If files containing a certificate and matching private key for the server are provided the server will expect
 
- 	// HTTPS connections.
 
- 	// Certificate and key files can be reloaded on demand sending a "SIGHUP" signal on Unix based systems and a
 
- 	// "paramchange" request to the running service on Windows.
 
- 	CertificateFile    string `json:"certificate_file" mapstructure:"certificate_file"`
 
- 	CertificateKeyFile string `json:"certificate_key_file" mapstructure:"certificate_key_file"`
 
- 	// TLSCipherSuites is a list of supported cipher suites for TLS version 1.2.
 
- 	// If CipherSuites is nil/empty, a default list of secure cipher suites
 
- 	// is used, with a preference order based on hardware performance.
 
- 	// Note that TLS 1.3 ciphersuites are not configurable.
 
- 	// The supported ciphersuites names are defined here:
 
- 	//
 
- 	// https://github.com/golang/go/blob/master/src/crypto/tls/cipher_suites.go#L53
 
- 	//
 
- 	// any invalid name will be silently ignored.
 
- 	// The order matters, the ciphers listed first will be the preferred ones.
 
- 	TLSCipherSuites []string `json:"tls_cipher_suites" mapstructure:"tls_cipher_suites"`
 
- 	// Defines the minimum TLS version. 13 means TLS 1.3, default is TLS 1.2
 
- 	MinTLSVersion int `json:"min_tls_version" mapstructure:"min_tls_version"`
 
- 	// HTTP protocols to enable in preference order. Supported values: http/1.1, h2
 
- 	Protocols []string `json:"tls_protocols" mapstructure:"tls_protocols"`
 
- }
 
- // ShouldBind returns true if there service must be started
 
- func (c Conf) ShouldBind() bool {
 
- 	if c.BindPort > 0 {
 
- 		return true
 
- 	}
 
- 	if filepath.IsAbs(c.BindAddress) && runtime.GOOS != "windows" {
 
- 		return true
 
- 	}
 
- 	return false
 
- }
 
- // Initialize configures and starts the telemetry server.
 
- func (c Conf) Initialize(configDir string) error {
 
- 	var err error
 
- 	logger.Info(logSender, "", "initializing telemetry server with config %+v", c)
 
- 	authUserFile := getConfigPath(c.AuthUserFile, configDir)
 
- 	httpAuth, err = common.NewBasicAuthProvider(authUserFile)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	certificateFile := getConfigPath(c.CertificateFile, configDir)
 
- 	certificateKeyFile := getConfigPath(c.CertificateKeyFile, configDir)
 
- 	initializeRouter(c.EnableProfiler)
 
- 	httpServer := &http.Server{
 
- 		Handler:           router,
 
- 		ReadHeaderTimeout: 30 * time.Second,
 
- 		ReadTimeout:       60 * time.Second,
 
- 		WriteTimeout:      60 * time.Second,
 
- 		IdleTimeout:       60 * time.Second,
 
- 		MaxHeaderBytes:    1 << 14, // 16KB
 
- 		ErrorLog:          log.New(&logger.StdLoggerWrapper{Sender: logSender}, "", 0),
 
- 	}
 
- 	if certificateFile != "" && certificateKeyFile != "" {
 
- 		keyPairs := []common.TLSKeyPair{
 
- 			{
 
- 				Cert: certificateFile,
 
- 				Key:  certificateKeyFile,
 
- 				ID:   common.DefaultTLSKeyPaidID,
 
- 			},
 
- 		}
 
- 		certMgr, err = common.NewCertManager(keyPairs, configDir, logSender)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 		config := &tls.Config{
 
- 			GetCertificate: certMgr.GetCertificateFunc(common.DefaultTLSKeyPaidID),
 
- 			MinVersion:     util.GetTLSVersion(c.MinTLSVersion),
 
- 			NextProtos:     util.GetALPNProtocols(c.Protocols),
 
- 			CipherSuites:   util.GetTLSCiphersFromNames(c.TLSCipherSuites),
 
- 		}
 
- 		logger.Debug(logSender, "", "configured TLS cipher suites: %v", config.CipherSuites)
 
- 		httpServer.TLSConfig = config
 
- 		return util.HTTPListenAndServe(httpServer, c.BindAddress, c.BindPort, true, logSender)
 
- 	}
 
- 	return util.HTTPListenAndServe(httpServer, c.BindAddress, c.BindPort, false, logSender)
 
- }
 
- // ReloadCertificateMgr reloads the certificate manager
 
- func ReloadCertificateMgr() error {
 
- 	if certMgr != nil {
 
- 		return certMgr.Reload()
 
- 	}
 
- 	return nil
 
- }
 
- func getConfigPath(name, configDir string) string {
 
- 	if !util.IsFileInputValid(name) {
 
- 		return ""
 
- 	}
 
- 	if name != "" && !filepath.IsAbs(name) {
 
- 		return filepath.Join(configDir, name)
 
- 	}
 
- 	return name
 
- }
 
 
  |