mirror of
https://github.com/jetkvm/kvm.git
synced 2026-05-21 05:20:35 +00:00
d1027206bc
* Enhance synctrace logging. Switched the maps to be indexed by the .Pointer (not a string) Grouped the lockCount, unlockCount ,and lastLock in an trackingEntry so we can detect unlocks of something that wasn't ever locked and excessive unlocks and also tracks the first time locked and the last unlock time. Added LogDangledLocks for debugging use. Added a panic handler to the Main so we can log out panics * Switch to traceable sync for most everything * More documentation * Update internal/sync/log.go * Update DEVELOPMENT.md * Resolve merge issue. * Applied review comments * Restore --enable-sync-trace option. * Use WithLevel so we can re-panic as desired
218 lines
5.0 KiB
Go
218 lines
5.0 KiB
Go
package kvm
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/jetkvm/kvm/internal/sync"
|
|
"github.com/jetkvm/kvm/internal/websecure"
|
|
)
|
|
|
|
const (
|
|
tlsStorePath = "/userdata/jetkvm/tls"
|
|
webSecureSelfSignedDefaultDomain = "jetkvm.local"
|
|
webSecureSelfSignedCAName = "JetKVM Self-Signed CA"
|
|
webSecureSelfSignedOrganization = "JetKVM"
|
|
webSecureSelfSignedOU = "JetKVM Self-Signed"
|
|
webSecureCustomCertificateName = "user-defined"
|
|
)
|
|
|
|
var (
|
|
certStore *websecure.CertStore
|
|
certSigner *websecure.SelfSigner
|
|
)
|
|
|
|
type TLSState struct {
|
|
Mode string `json:"mode"`
|
|
Certificate string `json:"certificate"`
|
|
PrivateKey string `json:"privateKey"`
|
|
}
|
|
|
|
func initCertStore() {
|
|
if certStore != nil {
|
|
websecureLogger.Warn().Msg("TLS store already initialized, it should not be initialized again")
|
|
return
|
|
}
|
|
certStore = websecure.NewCertStore(tlsStorePath, websecureLogger)
|
|
certStore.LoadCertificates()
|
|
|
|
certSigner = websecure.NewSelfSigner(
|
|
certStore,
|
|
websecureLogger,
|
|
webSecureSelfSignedDefaultDomain,
|
|
webSecureSelfSignedOrganization,
|
|
webSecureSelfSignedOU,
|
|
webSecureSelfSignedCAName,
|
|
)
|
|
}
|
|
|
|
func getCertificate(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
|
switch config.TLSMode {
|
|
case "self-signed":
|
|
if isTimeSyncNeeded() || !timeSync.IsSyncSuccess() {
|
|
return nil, fmt.Errorf("time is not synced")
|
|
}
|
|
return certSigner.GetCertificate(info)
|
|
case "custom":
|
|
return certStore.GetCertificate(webSecureCustomCertificateName), nil
|
|
}
|
|
|
|
websecureLogger.Info().Msg("TLS mode is disabled but WebSecure is running, returning nil")
|
|
return nil, nil
|
|
}
|
|
|
|
func getTLSState() TLSState {
|
|
s := TLSState{}
|
|
switch config.TLSMode {
|
|
case "disabled":
|
|
s.Mode = "disabled"
|
|
case "custom":
|
|
s.Mode = "custom"
|
|
cert := certStore.GetCertificate(webSecureCustomCertificateName)
|
|
if cert != nil {
|
|
var certPEM []byte
|
|
// convert to pem format
|
|
for _, c := range cert.Certificate {
|
|
block := pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: c,
|
|
}
|
|
|
|
certPEM = append(certPEM, pem.EncodeToMemory(&block)...)
|
|
}
|
|
s.Certificate = string(certPEM)
|
|
}
|
|
case "self-signed":
|
|
s.Mode = "self-signed"
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func setTLSState(s TLSState) error {
|
|
var isChanged = false
|
|
|
|
switch s.Mode {
|
|
case "disabled":
|
|
if config.TLSMode != "" {
|
|
isChanged = true
|
|
}
|
|
config.TLSMode = ""
|
|
case "custom":
|
|
if config.TLSMode == "" {
|
|
isChanged = true
|
|
}
|
|
// parse pem to cert and key
|
|
if certStore == nil {
|
|
initCertStore()
|
|
}
|
|
err, _ := certStore.ValidateAndSaveCertificate(webSecureCustomCertificateName, s.Certificate, s.PrivateKey, true)
|
|
// warn doesn't matter as ... we don't know the hostname yet
|
|
if err != nil {
|
|
return fmt.Errorf("failed to save certificate: %w", err)
|
|
}
|
|
config.TLSMode = "custom"
|
|
case "self-signed":
|
|
if config.TLSMode == "" {
|
|
isChanged = true
|
|
}
|
|
config.TLSMode = "self-signed"
|
|
default:
|
|
return fmt.Errorf("invalid TLS mode: %s", s.Mode)
|
|
}
|
|
|
|
if !isChanged {
|
|
websecureLogger.Info().Msg("TLS enabled state is not changed, not starting/stopping websecure server")
|
|
return nil
|
|
}
|
|
|
|
if config.TLSMode == "" {
|
|
websecureLogger.Info().Msg("Stopping websecure server, as TLS mode is disabled")
|
|
stopWebSecureServer()
|
|
} else {
|
|
websecureLogger.Info().Msg("Starting websecure server, as TLS mode is enabled")
|
|
startWebSecureServer()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
var (
|
|
startTLS = make(chan struct{})
|
|
stopTLS = make(chan struct{})
|
|
tlsServiceLock = sync.Mutex{}
|
|
tlsStarted = false
|
|
)
|
|
|
|
// RunWebSecureServer runs a web server with TLS.
|
|
func runWebSecureServer() {
|
|
tlsServiceLock.Lock()
|
|
defer tlsServiceLock.Unlock()
|
|
|
|
tlsStarted = true
|
|
defer func() {
|
|
tlsStarted = false
|
|
}()
|
|
|
|
r := setupRouter()
|
|
|
|
// Determine the binding address based on the config
|
|
bindAddress := getBindAddress(443)
|
|
|
|
server := &http.Server{
|
|
Addr: bindAddress,
|
|
Handler: r,
|
|
TLSConfig: &tls.Config{
|
|
MaxVersion: tls.VersionTLS13,
|
|
CurvePreferences: []tls.CurveID{},
|
|
GetCertificate: getCertificate,
|
|
},
|
|
}
|
|
websecureLogger.Info().Str("bindAddress", bindAddress).Bool("loopbackOnly", config.LocalLoopbackOnly).Msg("Starting websecure server")
|
|
|
|
go func() {
|
|
for range stopTLS {
|
|
websecureLogger.Info().Msg("Shutting down websecure server")
|
|
err := server.Shutdown(context.Background())
|
|
if err != nil {
|
|
websecureLogger.Error().Err(err).Msg("failed to shutdown websecure server")
|
|
}
|
|
}
|
|
}()
|
|
|
|
err := server.ListenAndServeTLS("", "")
|
|
if !errors.Is(err, http.ErrServerClosed) {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func stopWebSecureServer() {
|
|
if !tlsStarted {
|
|
websecureLogger.Info().Msg("Websecure server is not running, not stopping it")
|
|
return
|
|
}
|
|
stopTLS <- struct{}{}
|
|
}
|
|
|
|
func startWebSecureServer() {
|
|
if tlsStarted {
|
|
websecureLogger.Info().Msg("Websecure server is already running, not starting it again")
|
|
return
|
|
}
|
|
startTLS <- struct{}{}
|
|
}
|
|
|
|
func RunWebSecureServer() {
|
|
for range startTLS {
|
|
websecureLogger.Info().Msg("Starting websecure server, as we have received a start signal")
|
|
if certStore == nil {
|
|
initCertStore()
|
|
}
|
|
go runWebSecureServer()
|
|
}
|
|
}
|