Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial capver packet tracking version #2391

Merged
merged 6 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

- `oidc.map_legacy_users` is now `false` by default
[#2350](https://github.com/juanfont/headscale/pull/2350)
- Print Tailscale version instead of capability versions for outdated nodes
[#2391](https://github.com/juanfont/headscale/pull/2391)

## 0.24.2 (2025-01-30)

Expand All @@ -24,8 +26,8 @@
[#2367](https://github.com/juanfont/headscale/pull/2367)
- Relax username validation to allow emails
[#2364](https://github.com/juanfont/headscale/pull/2364)
- Remove invalid routes and add stronger constraints for routes to avoid API panic
[#2371](https://github.com/juanfont/headscale/pull/2371)
- Remove invalid routes and add stronger constraints for routes to avoid API
panic [#2371](https://github.com/juanfont/headscale/pull/2371)
- Fix panic when `derp.update_frequency` is 0
[#2368](https://github.com/juanfont/headscale/pull/2368)

Expand Down Expand Up @@ -60,8 +62,7 @@ and have it populate to Headscale automatically the next time they log in.
However, this may affect the way you reference users in policies.

Headscale v0.23.0 and earlier never recorded the `iss` and `sub` fields, so all
legacy (existing) OIDC accounts _need to be migrated_ to be properly
secured.
legacy (existing) OIDC accounts _need to be migrated_ to be properly secured.

#### What do I need to do to migrate?

Expand All @@ -73,8 +74,8 @@ The migration will mostly be done automatically, with one exception. If your
OIDC does not provide an `email_verified` claim, Headscale will ignore the
`email`. This means that either the administrator will have to mark the user
emails as verified, or ensure the users verify their emails. Any unverified
emails will be ignored, meaning that the users will get new accounts instead
of being migrated.
emails will be ignored, meaning that the users will get new accounts instead of
being migrated.

After this exception is ensured, make all users log into Headscale with their
account, and Headscale will automatically update the account record. This will
Expand Down Expand Up @@ -175,7 +176,8 @@ This will also affect the way you
- User gRPC/API [#2261](https://github.com/juanfont/headscale/pull/2261):
- If you depend on a Headscale Web UI, you should wait with this update until
the UI have been updated to match the new API.
- `GET /api/v1/user/{name}` and `GetUser` have been removed in favour of `ListUsers` with an ID parameter
- `GET /api/v1/user/{name}` and `GetUser` have been removed in favour of
`ListUsers` with an ID parameter
- `RenameUser` and `DeleteUser` now require an ID instead of a name.

### Changes
Expand All @@ -197,9 +199,12 @@ This will also affect the way you
- CLI for managing users now accepts `--identifier` in addition to `--name`,
usage of `--identifier` is recommended
[#2261](https://github.com/juanfont/headscale/pull/2261)
- Add `dns.extra_records_path` configuration option [#2262](https://github.com/juanfont/headscale/issues/2262)
- Support client verify for DERP [#2046](https://github.com/juanfont/headscale/pull/2046)
- Add PKCE Verifier for OIDC [#2314](https://github.com/juanfont/headscale/pull/2314)
- Add `dns.extra_records_path` configuration option
[#2262](https://github.com/juanfont/headscale/issues/2262)
- Support client verify for DERP
[#2046](https://github.com/juanfont/headscale/pull/2046)
- Add PKCE Verifier for OIDC
[#2314](https://github.com/juanfont/headscale/pull/2314)

## 0.23.0 (2024-09-18)

Expand Down Expand Up @@ -730,8 +735,8 @@ behaviour.
- All machines can communicate with all machines by default
- Tags should now work correctly and adding a host to Headscale should now
reload the rules.
- The documentation have a [fictional example](./docs/ref/acls.md) that should cover
some use cases of the ACLs features
- The documentation have a [fictional example](./docs/ref/acls.md) that should
cover some use cases of the ACLs features

### Features

Expand All @@ -749,7 +754,8 @@ behaviour.

- Add IPv6 support to the prefix assigned to namespaces
- Add API Key support
- Enable remote control of `headscale` via CLI [docs](./docs/ref/remote-cli.md)
- Enable remote control of `headscale` via CLI
[docs](./docs/ref/remote-cli.md)
- Enable HTTP API (beta, subject to change)
- OpenID Connect users will be mapped per namespaces
- Each user will get its own namespace, created if it does not exist
Expand Down
6 changes: 6 additions & 0 deletions hscontrol/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
grpcRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol/capver"
"github.com/juanfont/headscale/hscontrol/db"
"github.com/juanfont/headscale/hscontrol/derp"
derpServer "github.com/juanfont/headscale/hscontrol/derp/server"
Expand Down Expand Up @@ -560,6 +561,11 @@ func (h *Headscale) Serve() error {
spew.Dump(h.cfg)
}

log.Info().
Caller().
Str("minimum_version", capver.TailscaleVersion(MinimumCapVersion)).
Msg("Clients with a lower minimum version will be rejected")

// Fetch an initial DERP Map before we start serving
h.DERPMap = derp.GetDERPMap(h.cfg.DERP)
h.mapper = mapper.NewMapper(h.db, h.cfg, h.DERPMap, h.nodeNotifier, h.polMan)
Expand Down
92 changes: 92 additions & 0 deletions hscontrol/capver/capver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package capver

import (
"sort"
"strings"

xmaps "golang.org/x/exp/maps"
"tailscale.com/tailcfg"
"tailscale.com/util/set"
)

func tailscaleVersSorted() []string {
vers := xmaps.Keys(tailscaleToCapVer)
sort.Strings(vers)
return vers
}

func capVersSorted() []tailcfg.CapabilityVersion {
capVers := xmaps.Keys(capVerToTailscaleVer)
sort.Slice(capVers, func(i, j int) bool {
return capVers[i] < capVers[j]
})
return capVers
}

// TailscaleVersion returns the Tailscale version for the given CapabilityVersion.
func TailscaleVersion(ver tailcfg.CapabilityVersion) string {
return capVerToTailscaleVer[ver]
}

// CapabilityVersion returns the CapabilityVersion for the given Tailscale version.
func CapabilityVersion(ver string) tailcfg.CapabilityVersion {
if !strings.HasPrefix(ver, "v") {
ver = "v" + ver
}
return tailscaleToCapVer[ver]
}

// TailscaleLatest returns the n latest Tailscale versions.
func TailscaleLatest(n int) []string {
if n <= 0 {
return nil
}

tsSorted := tailscaleVersSorted()

if n > len(tsSorted) {
return tsSorted
}

return tsSorted[len(tsSorted)-n:]
}

// TailscaleLatestMajorMinor returns the n latest Tailscale versions (e.g. 1.80).
func TailscaleLatestMajorMinor(n int, stripV bool) []string {
if n <= 0 {
return nil
}

majors := set.Set[string]{}
for _, vers := range tailscaleVersSorted() {
if stripV {
vers = strings.TrimPrefix(vers, "v")
}
v := strings.Split(vers, ".")
majors.Add(v[0] + "." + v[1])
}

majorSl := majors.Slice()
sort.Strings(majorSl)

if n > len(majorSl) {
return majorSl
}

return majorSl[len(majorSl)-n:]
}

// CapVerLatest returns the n latest CapabilityVersions.
func CapVerLatest(n int) []tailcfg.CapabilityVersion {
if n <= 0 {
return nil
}

s := capVersSorted()

if n > len(s) {
return s
}

return s[len(s)-n:]
}
54 changes: 54 additions & 0 deletions hscontrol/capver/capver_generated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package capver

//Generated DO NOT EDIT

import "tailscale.com/tailcfg"

var tailscaleToCapVer = map[string]tailcfg.CapabilityVersion{
"v1.44.3": 63,
"v1.56.1": 82,
"v1.58.0": 85,
"v1.58.1": 85,
"v1.58.2": 85,
"v1.60.0": 87,
"v1.60.1": 87,
"v1.62.0": 88,
"v1.62.1": 88,
"v1.64.0": 90,
"v1.64.1": 90,
"v1.64.2": 90,
"v1.66.0": 95,
"v1.66.1": 95,
"v1.66.2": 95,
"v1.66.3": 95,
"v1.66.4": 95,
"v1.68.0": 97,
"v1.68.1": 97,
"v1.68.2": 97,
"v1.70.0": 102,
"v1.72.0": 104,
"v1.72.1": 104,
"v1.74.0": 106,
"v1.74.1": 106,
"v1.76.0": 106,
"v1.76.1": 106,
"v1.76.6": 106,
"v1.78.0": 109,
"v1.78.1": 109,
}


var capVerToTailscaleVer = map[tailcfg.CapabilityVersion]string{
63: "v1.44.3",
82: "v1.56.1",
85: "v1.58.0",
87: "v1.60.0",
88: "v1.62.0",
90: "v1.64.0",
95: "v1.66.0",
97: "v1.68.0",
102: "v1.70.0",
104: "v1.72.0",
106: "v1.74.0",
109: "v1.78.0",
}
53 changes: 53 additions & 0 deletions hscontrol/capver/capver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package capver

import (
"testing"

"github.com/google/go-cmp/cmp"
"tailscale.com/tailcfg"
)

func TestTailscaleLatestMajorMinor(t *testing.T) {
tests := []struct {
n int
stripV bool
expected []string
}{
{3, false, []string{"v1.74", "v1.76", "v1.78"}},
{2, true, []string{"1.76", "1.78"}},
{0, false, nil},
}

for _, test := range tests {
t.Run("", func(t *testing.T) {
output := TailscaleLatestMajorMinor(test.n, test.stripV)
if diff := cmp.Diff(output, test.expected); diff != "" {
t.Errorf("TailscaleLatestMajorMinor(%d, %v) mismatch (-want +got):\n%s", test.n, test.stripV, diff)
}
})
}
}

func TestCapVerMinimumTailscaleVersion(t *testing.T) {
tests := []struct {
input tailcfg.CapabilityVersion
expected string
}{
{85, "v1.58.0"},
{90, "v1.64.0"},
{95, "v1.66.0"},
{106, "v1.74.0"},
{109, "v1.78.0"},
{9001, ""}, // Test case for a version higher than any in the map
{60, ""}, // Test case for a version lower than any in the map
}

for _, test := range tests {
t.Run("", func(t *testing.T) {
output := TailscaleVersion(test.input)
if output != test.expected {
t.Errorf("CapVerFromTailscaleVersion(%d) = %s; want %s", test.input, output, test.expected)
}
})
}
}
Loading
Loading