diff --git a/hscontrol/app.go b/hscontrol/app.go index ecce42b1..016a2037 100644 --- a/hscontrol/app.go +++ b/hscontrol/app.go @@ -24,6 +24,7 @@ import ( "github.com/juanfont/headscale" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/juanfont/headscale/hscontrol/db" + "github.com/juanfont/headscale/hscontrol/derp" "github.com/juanfont/headscale/hscontrol/policy" "github.com/juanfont/headscale/hscontrol/types" "github.com/juanfont/headscale/hscontrol/util" @@ -59,18 +60,12 @@ var ( ) const ( - AuthPrefix = "Bearer " - updateInterval = 5000 - HTTPReadTimeout = 30 * time.Second - HTTPShutdownTimeout = 3 * time.Second - privateKeyFileMode = 0o600 + AuthPrefix = "Bearer " + updateInterval = 5000 + privateKeyFileMode = 0o600 registerCacheExpiration = time.Minute * 15 registerCacheCleanup = time.Minute * 20 - - DisabledClientAuth = "disabled" - RelaxedClientAuth = "relaxed" - EnforcedClientAuth = "enforced" ) // Headscale represents the base app of the service. @@ -241,6 +236,31 @@ func (h *Headscale) expireExpiredMachines(milliSeconds int64) { } } +// scheduledDERPMapUpdateWorker refreshes the DERPMap stored on the global object +// at a set interval +func (h *Headscale) scheduledDERPMapUpdateWorker(cancelChan <-chan struct{}) { + log.Info(). + Dur("frequency", h.cfg.DERP.UpdateFrequency). + Msg("Setting up a DERPMap update worker") + ticker := time.NewTicker(h.cfg.DERP.UpdateFrequency) + + for { + select { + case <-cancelChan: + return + + case <-ticker.C: + log.Info().Msg("Fetching DERPMap updates") + h.DERPMap = derp.GetDERPMap(h.cfg.DERP) + if h.cfg.DERP.ServerEnabled { + h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region + } + + h.setLastStateChangeToNow() + } + } +} + func (h *Headscale) failoverSubnetRoutes(milliSeconds int64) { ticker := time.NewTicker(time.Duration(milliSeconds) * time.Millisecond) for range ticker.C { @@ -455,7 +475,7 @@ func (h *Headscale) Serve() error { var err error // Fetch an initial DERP Map before we start serving - h.DERPMap = GetDERPMap(h.cfg.DERP) + h.DERPMap = derp.GetDERPMap(h.cfg.DERP) if h.cfg.DERP.ServerEnabled { // When embedded DERP is enabled we always need a STUN server @@ -615,7 +635,7 @@ func (h *Headscale) Serve() error { httpServer := &http.Server{ Addr: h.cfg.Addr, Handler: router, - ReadTimeout: HTTPReadTimeout, + ReadTimeout: types.HTTPReadTimeout, // Go does not handle timeouts in HTTP very well, and there is // no good way to handle streaming timeouts, therefore we need to // keep this at unlimited and be careful to clean up connections @@ -645,7 +665,7 @@ func (h *Headscale) Serve() error { promHTTPServer := &http.Server{ Addr: h.cfg.MetricsAddr, Handler: promMux, - ReadTimeout: HTTPReadTimeout, + ReadTimeout: types.HTTPReadTimeout, WriteTimeout: 0, } @@ -709,7 +729,7 @@ func (h *Headscale) Serve() error { // Gracefully shut down servers ctx, cancel := context.WithTimeout( context.Background(), - HTTPShutdownTimeout, + types.HTTPShutdownTimeout, ) if err := promHTTPServer.Shutdown(ctx); err != nil { log.Error().Err(err).Msg("Failed to shutdown prometheus http") @@ -792,7 +812,7 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) { server := &http.Server{ Addr: h.cfg.TLS.LetsEncrypt.Listen, Handler: certManager.HTTPHandler(http.HandlerFunc(h.redirect)), - ReadTimeout: HTTPReadTimeout, + ReadTimeout: types.HTTPReadTimeout, } go func() { diff --git a/hscontrol/derp.go b/hscontrol/derp/derp.go similarity index 80% rename from hscontrol/derp.go rename to hscontrol/derp/derp.go index 1e712a51..83c200a2 100644 --- a/hscontrol/derp.go +++ b/hscontrol/derp/derp.go @@ -1,4 +1,4 @@ -package hscontrol +package derp import ( "context" @@ -7,7 +7,6 @@ import ( "net/http" "net/url" "os" - "time" "github.com/juanfont/headscale/hscontrol/types" "github.com/rs/zerolog/log" @@ -32,7 +31,7 @@ func loadDERPMapFromPath(path string) (*tailcfg.DERPMap, error) { } func loadDERPMapFromURL(addr url.URL) (*tailcfg.DERPMap, error) { - ctx, cancel := context.WithTimeout(context.Background(), HTTPReadTimeout) + ctx, cancel := context.WithTimeout(context.Background(), types.HTTPReadTimeout) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, addr.String(), nil) @@ -41,7 +40,7 @@ func loadDERPMapFromURL(addr url.URL) (*tailcfg.DERPMap, error) { } client := http.Client{ - Timeout: HTTPReadTimeout, + Timeout: types.HTTPReadTimeout, } resp, err := client.Do(req) @@ -133,26 +132,3 @@ func GetDERPMap(cfg types.DERPConfig) *tailcfg.DERPMap { return derpMap } - -func (h *Headscale) scheduledDERPMapUpdateWorker(cancelChan <-chan struct{}) { - log.Info(). - Dur("frequency", h.cfg.DERP.UpdateFrequency). - Msg("Setting up a DERPMap update worker") - ticker := time.NewTicker(h.cfg.DERP.UpdateFrequency) - - for { - select { - case <-cancelChan: - return - - case <-ticker.C: - log.Info().Msg("Fetching DERPMap updates") - h.DERPMap = GetDERPMap(h.cfg.DERP) - if h.cfg.DERP.ServerEnabled { - h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region - } - - h.setLastStateChangeToNow() - } - } -} diff --git a/hscontrol/noise.go b/hscontrol/noise.go index f938dfe5..0fa28d19 100644 --- a/hscontrol/noise.go +++ b/hscontrol/noise.go @@ -7,6 +7,7 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/juanfont/headscale/hscontrol/types" "github.com/rs/zerolog/log" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" @@ -100,12 +101,12 @@ func (h *Headscale) NoiseUpgradeHandler( router.HandleFunc("/machine/map", noiseServer.NoisePollNetMapHandler) server := http.Server{ - ReadTimeout: HTTPReadTimeout, + ReadTimeout: types.HTTPReadTimeout, } noiseServer.httpBaseConfig = &http.Server{ Handler: router, - ReadHeaderTimeout: HTTPReadTimeout, + ReadHeaderTimeout: types.HTTPReadTimeout, } noiseServer.http2Server = &http2.Server{} diff --git a/hscontrol/types/config.go b/hscontrol/types/config.go index 1172b3e7..dbbb0bed 100644 --- a/hscontrol/types/config.go +++ b/hscontrol/types/config.go @@ -23,12 +23,6 @@ import ( ) const ( - TlsALPN01ChallengeType = "TLS-ALPN-01" - Http01ChallengeType = "HTTP-01" - - JSONLogFormat = "json" - TextLogFormat = "text" - defaultOIDCExpiryTime = 180 * 24 * time.Hour // 180 Days maxDuration time.Duration = 1<<63 - 1 ) diff --git a/hscontrol/types/const.go b/hscontrol/types/const.go new file mode 100644 index 00000000..3a733ea9 --- /dev/null +++ b/hscontrol/types/const.go @@ -0,0 +1,16 @@ +package types + +import "time" + +const ( + HTTPReadTimeout = 30 * time.Second + HTTPShutdownTimeout = 3 * time.Second + TlsALPN01ChallengeType = "TLS-ALPN-01" + Http01ChallengeType = "HTTP-01" + + JSONLogFormat = "json" + TextLogFormat = "text" + + KeepAliveInterval = 60 * time.Second + MaxHostnameLength = 255 +) diff --git a/hscontrol/types/machine.go b/hscontrol/types/machine.go index 15f71b7d..9a576ad7 100644 --- a/hscontrol/types/machine.go +++ b/hscontrol/types/machine.go @@ -17,12 +17,6 @@ import ( "tailscale.com/types/key" ) -const ( - // TODO(kradalby): Move out of here when we got circdeps under control. - keepAliveInterval = 60 * time.Second - MaxHostnameLength = 255 -) - var ( ErrMachineAddressesInvalid = errors.New("failed to parse machine addresses") ErrHostnameTooLong = errors.New("hostname too long") @@ -160,7 +154,7 @@ func (machine *Machine) IsOnline() bool { return false } - return machine.LastSeen.After(time.Now().Add(-keepAliveInterval)) + return machine.LastSeen.After(time.Now().Add(-KeepAliveInterval)) } // IsEphemeral returns if the machine is registered as an Ephemeral node.