Commit Graph

886 Commits

Author SHA1 Message Date
Kristoffer Dalby c604874dba policy/v2: suggest approved exit nodes by default
Matches SaaS; Apple clients hide the exit-node list without a suggestion.

Fixes #3415
2026-09-23 14:48:45 +02:00
Kristoffer Dalby 06fa3075da hscontrol: replace tailscale line refs with doc links
Line numbers drift on every upstream bump.
2026-09-23 14:48:45 +02:00
Kristoffer Dalby 0e8a3bba54 policy/v2: compare peer CapMap against SaaS route captures
SaaS stamps suggest-exit-node on approved exit peers without nodeAttrs.

Updates #3415
2026-09-23 14:48:45 +02:00
Kristoffer Dalby e48bc46cc6 mapper: take peer visibility from the peer map only
Fixes #3408
2026-09-23 14:48:35 +02:00
Kristoffer Dalby 5861005ef6 policy/v2: add via exit node capture
Updates #3408
2026-09-23 14:48:35 +02:00
Kristoffer Dalby 23f7eedac6 servertest: compare user-owned nodes in via compat tests
Updates #3408
2026-09-23 14:48:35 +02:00
Kristoffer Dalby 5401edb6a8 policy: ignore '#' metadata fields across the whole policy
The filter lived in ACL.UnmarshalJSON, so grants, ssh and nodeAttrs still
hit RejectUnknownMembers. Strip the members in the HuJSON AST instead, at
the single decode entrypoint. Grant "app" payloads are left untouched.

Fixes #3479
2026-09-23 09:30:22 +02:00
Kristoffer Dalby 804954f5bc types: regenerate node view
Updates #3470
2026-09-23 09:23:51 +02:00
Kristoffer Dalby 80c863b15a state: mark expired nodes offline without ending the session
Online now requires a live session and an unexpired key, derived in one
place by Node.ShouldBeOnline so every writer agrees what online means.

Fixes #3470
2026-09-23 09:23:51 +02:00
Andrei Korviakov 7472e98f6c hscontrol: keep the ACME error body readable in acmeLogger
acmeLogger drained and closed the body of every ACME error response before
handing the response back to golang.org/x/crypto/acme. The client parses that
body to classify errors, so badNonce was no longer recognised: isBadNonce
returned false, clearNonces was never called and Client.post treated the 400 as
non-retriable.

One badNonce reply therefore stops certificate renewal for good. autocert
retries every 30-60 minutes, each attempt reuses a nonce stored from the
previous failed response, that nonce has already expired, and the loop repeats
until the process is restarted or the certificate expires.

Restore the body with a fresh reader after logging it.
2026-09-15 14:37:20 +02:00
Kristoffer Dalby 4c6a2dff52 state: resolve changed peers through adjacency
ListPeers now filters named peers against the recipient's adjacency, so
a node the policy hides is never delivered.

Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby e3c4c81b18 state: reuse peer adjacency for payload-only writes
A write that cannot move visibility carries the previous adjacency
forward; policy and user changes rebuild it explicitly.

Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby 95ba787417 policy,state: key the peer map by node ID
Adjacency becomes immutable, so a snapshot can resolve peers through its
own fresh views instead of storing them.

Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby 1b820b7ebe state: skip node health writes that change nothing
An all-unchanged probe cycle no longer publishes a snapshot.

Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby dfe0d3f2e5 state: stop broadcasting a whole peer on disconnect
Going offline changes nothing the policy reads, so the row write skips
the policy refresh and peers get only the offline patch.

Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby 59f3ff12a7 state: classify map requests before broadcasting
Each request is reduced to the narrowest change it justifies, so a
keepalive or endpoint bump no longer resends the whole node to peers.

Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby 286f1d5a12 mapper: drop empty changes before fan-out
An empty change carries no work for any recipient, so it never becomes
a pending entry. Adds headscale_mapper_changes_dropped_total.

Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby 905ab92fe0 types: detect policy change on user identity and exit routes
Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby be322e8ea7 policy,types: skip recompile when the user list is unchanged
SetUsers now also reports whether user-derived peer adjacency moved.

Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby 1bbe59b98d state: rename persist helpers to say what they do
Updates #3417
2026-09-10 13:06:13 +02:00
Kristoffer Dalby 10dd38fcef oidc: harden reloadable confirmation flow
Updates #3365
2026-09-09 19:01:43 +02:00
Sean Reifschneider 6d377b5348 oidc: serve the registration confirmation page from a reloadable URL
The interstitial was the body of /oidc/callback, the URL carrying the
single-use code, so any reload re-entered the spent exchange. Redirect to
GET /register/confirm/{auth_id}, also missing from the route table.
2026-09-09 19:01:43 +02:00
Kristoffer Dalby 8995d8a558 mapper: assert no map response lists the recipient as its own peer
Covers every change shape under four policy shapes, plus connect churn. The
zero-matcher shape is the gap: buildTailPeers skips ReduceNodes there, so the
peer lookup is the only self filter left.
2026-09-09 18:18:53 +02:00
Kristoffer Dalby d9aebf472d state: exclude self from peers on the named peer-ID path
ListPeers with explicit IDs filtered every node, not every peer, so a change
batch naming the recipient returned it as its own peer. db.ListPeers keeps
this out with `id <> nodeID`; the NodeStore rewrite dropped it.
2026-09-09 18:18:53 +02:00
Kristoffer Dalby afb3020ef0 noise: make deleted-node expiry clock independent
Updates #3410
2026-09-09 18:18:17 +02:00
Kristoffer Dalby a91c0519c2 change, mapper: distinguish deleted nodes
Updates #3410
2026-09-09 18:18:17 +02:00
Kristoffer Dalby fc6a16fdfc state: preserve committed node deletion changes
Updates #3410
2026-09-09 18:18:17 +02:00
Kristoffer Dalby ef456542ce poll: interrupt blocked map writes
Updates #3410
2026-09-09 18:18:17 +02:00
Kristoffer Dalby b1fb6ed2e6 poll, noise: tell a deleted node to re-authenticate
A bare 404 is indistinguishable from any other map-path error to a Tailscale
client: it retries forever, still logged in. Only a self node with a past
KeyExpiry reaches NeedsLogin. Also skip the reconnect grace wait, which a
deleted node can never satisfy.

Fixes #3410
2026-09-09 18:18:17 +02:00
Kristoffer Dalby 42bf00523a types/change: drop unused VisibilityChange
It fills PeersRemoved without deleting anything. The batcher now tears down
the session behind every removed id, so a caller would kill a live poll.

Updates #3410
2026-09-09 18:18:17 +02:00
Kristoffer Dalby 0b69e844f5 mapper: stop a deleted node's map session
Dropping the batcher entry left serveLongPoll streaming to a node that no
longer exists: Close ranges b.nodes and can no longer reach it, so shutdown
blocks and the client keeps polling instead of re-authenticating.

Updates #3410
2026-09-09 18:18:17 +02:00
Saleh 95ba1f0566 types: lowercase DNS extra record names
DNS names are case-insensitive, but clients match extra records against
the lowercased query name, so records with mixed-case names (for example
"Printer.fritz.box" in an extra_records_path file) never resolved and
queries fell through to the global nameserver.

Normalize record names to lowercase where the records enter the tailcfg
DNS config, covering both dns.extra_records and extra_records_path.

Fixes #2782
2026-09-09 12:09:52 +02:00
Sebastien Tardif a48a42baf4 dns: cancel extra-records retry on shutdown and close watcher on setup error
After Remove/Rename, the extra-records filewatcher retried with
context.Background and the default 15-minute backoff budget, so Close
could not stop Run. Cancel that retry when closeCh closes. If the file
is still missing after the budget, watch the parent directory so a later
recreate is seen.

Close the fsnotify watcher on NewExtraRecordsManager error paths after
NewWatcher succeeds.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
2026-09-04 11:35:45 +02:00
Igor Serganov c26b2fd0a4 linting issue fix 2026-09-04 11:33:48 +02:00
Igor Serganov a9f80d8802 hscontrol: cancel tailsql on graceful shutdown
Serve stored a Background context for tailsql and called
context.Done() during signal shutdown. Done only returns the
done channel and does not cancel, so tailsql never stopped
when Headscale shut down.

Create a cancellable child of the Serve context, run
`runTailSQLService` in the listener errgroup so its error is
surfaced, and call the cancel func on shutdown - tailsql
unblocks on ctx.Done.
2026-09-04 11:33:48 +02:00
Igor Bernstein efe947507b templates: apply the tvOS setup reorder to the served /apple page
The instructions are duplicated between the docs and the HTML page
headscale serves at /apple. Reorder the tvOS steps there to match, so
the VPN configuration is installed before the alternate coordination
server URL is set.
2026-08-29 18:18:35 +02:00
Paulo Luna 63ce8f2295 fix(metrics): collect metrics for non-OPTIONS requests
Fix the inverted HTTP metrics skip condition, which caused the collector to ignore all requests except OPTIONS.

Apply the correction to both the main and Noise routers so regular HTTP traffic is included in http_requests_total and http_request_duration_seconds.
2026-08-28 13:13:48 +02:00
Kristoffer Dalby 63123196cc all: inline deprecated tailcfg capability aliases
go 1.27 vet reports the //go:fix inline directives tailscale added to
the tailcfg cap aliases; applied with `go fix -inline ./...`.
2026-08-25 21:59:00 +02:00
Simon Law 3aece65014 build: update tailscale.com to v1.103.0-pre.0.20260819232550-0e84b4a3a0a0
PR tailscale/tailscale#20646 changed the representation of DERP region
IDs from plain ints to a tailcfg.DERPRegionID type. This patch
requires that version of the tailscale.com library and updates our
code to also use the new type.

Updates: tailscale/tailscale#20165
(cherry picked from commit 79695ab51b)
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 7e12e46f63 capver: regenerate for Tailscale v1.102 2026-08-25 21:59:00 +02:00
Kristoffer Dalby d7c1ecce92 mapper: correct the send timer rationale
time.After has been GC-recoverable since Go 1.23, so the leak the comment
described cannot happen and the test asserting it proved nothing.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 0a4d56494f hscontrol: drop the net/http/pprof import
Nothing serves DefaultServeMux; the debug mux already exposes every
profile through tsweb.Debugger.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 1994f50fe8 policy/v2: drop elided struct types in test users
Promoted field keys let the literals skip the embedded gorm.Model.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 93e29ec38d all: use strings.CutLast
Replaces LastIndex plus slice arithmetic when splitting on the last
separator.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 373c60efe3 all: use sync.WaitGroup.Go
Drops the Add/Done bookkeeping, which in batcher.go was spread across
three functions.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 1c6809089f hscontrol: use the stdlib uuid package
Go 1.27 ships RFC 9562 UUIDs and NewV4 cannot fail, dropping gofrs/uuid
and two error paths.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 0c0b0c68a6 derp: drop deprecated DERPRegion.Avoid
Zero value, superseded by NoMeasureNoHome.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 77caa94400 policy/v2: use value receiver for SSHCheckPeriod.Validate
recvcheck ignores UnmarshalJSON, so the pointer receiver here was the
odd one out against value-receiver MarshalJSON. Validate only reads.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby 2c76d5c5b7 all: apply golangci-lint autofixes
Go 1.27 allows setting promoted fields of embedded structs directly in
composite literals, so gorm.Model wrappers go away. Plus strings.Cut,
errors.AsType, reflect.TypeAssert and one gofumpt nit.
2026-08-25 21:59:00 +02:00
Kristoffer Dalby d28a6b111a hscontrol: prefer completed auth over expired ctx in followup wait
waitForFollowup selected on ctx.Done() and the verdict channel with equal
priority; when both were ready, select picked at random and discarded a
successful registration as a spurious 401 timeout. Check for a completed
verdict first, race the deadline only if none is ready.

Fixes #3385
2026-07-29 11:03:23 +02:00