diff --git a/hscontrol/auth_noise.go b/hscontrol/auth_noise.go index 4fb4bb05e6b..b0bf2129413 100644 --- a/hscontrol/auth_noise.go +++ b/hscontrol/auth_noise.go @@ -2,6 +2,7 @@ package hscontrol import ( "encoding/json" + "errors" "io" "net/http" @@ -21,6 +22,29 @@ func (ns *noiseServer) NoiseRegistrationHandler( return } + capVer, err := parseCabailityVersion(req) + if err != nil && !errors.Is(err, ErrNoCapabilityVersion) { + log.Error(). + Caller(). + Err(err). + Msg("failed to parse capVer") + http.Error(writer, "Internal error", http.StatusInternalServerError) + + return + } + + // Reject unsupported versions + if capVer < MinimumCapVersion { + log.Info(). + Caller(). + Int("min_version", int(MinimumCapVersion)). + Int("client_version", int(capVer)). + Msg("unsupported client connected") + http.Error(writer, "Internal error", http.StatusBadRequest) + + return + } + log.Trace(). Any("headers", req.Header). Caller(). diff --git a/hscontrol/poll.go b/hscontrol/poll.go index d0ee7c8cd08..c366acb24bd 100644 --- a/hscontrol/poll.go +++ b/hscontrol/poll.go @@ -79,6 +79,7 @@ func (h *Headscale) handlePoll( Str("node_key", node.NodeKey). Str("node", node.Hostname). Strs("endpoints", node.Endpoints). + Int("cap_ver", int(capVer)). Msg("Received endpoint update") now := time.Now().UTC() diff --git a/hscontrol/poll_noise.go b/hscontrol/poll_noise.go index 67585d11737..e1aac8b383c 100644 --- a/hscontrol/poll_noise.go +++ b/hscontrol/poll_noise.go @@ -12,6 +12,10 @@ import ( "tailscale.com/types/key" ) +const ( + MinimumCapVersion tailcfg.CapabilityVersion = 36 +) + // NoisePollNetMapHandler takes care of /machine/:id/map using the Noise protocol // // This is the busiest endpoint, as it keeps the HTTP long poll that updates @@ -34,6 +38,29 @@ func (ns *noiseServer) NoisePollNetMapHandler( Caller(). Msg("Headers") + capVer, err := parseCabailityVersion(req) + if err != nil && !errors.Is(err, ErrNoCapabilityVersion) { + log.Error(). + Caller(). + Err(err). + Msg("failed to parse capVer") + http.Error(writer, "Internal error", http.StatusInternalServerError) + + return + } + + // Reject unsupported versions + if capVer < MinimumCapVersion { + log.Info(). + Caller(). + Int("min_version", int(MinimumCapVersion)). + Int("client_version", int(capVer)). + Msg("unsupported client connected") + http.Error(writer, "Internal error", http.StatusBadRequest) + + return + } + body, _ := io.ReadAll(req.Body) mapRequest := tailcfg.MapRequest{} @@ -75,18 +102,5 @@ func (ns *noiseServer) NoisePollNetMapHandler( Str("node", node.Hostname). Msg("A node sending a MapRequest with Noise protocol") - capVer, err := parseCabailityVersion(req) - if err != nil && !errors.Is(err, ErrNoCapabilityVersion) { - log.Error(). - Caller(). - Err(err). - Msg("failed to parse capVer") - http.Error(writer, "Internal error", http.StatusInternalServerError) - - return - } - - // TODO(kradalby): since we are now passing capVer, we could arguably stop passing - // isNoise, and rather have a isNoise function that takes capVer ns.headscale.handlePoll(writer, req.Context(), node, mapRequest, capVer) }