Commit Graph
1498 Commits
Author SHA1 Message Date
Theodor S. Midtlien ec3a20e979 Merge branch 'main' into profile-ownership 2026-09-24 11:49:13 +02:00
Theodor Midtlien 4c19226342 [client] Use POSIX style file read/write of json for windows (#7631)
* Use POSIX-like file read/write of json for windows + tests: allow renaming an open file.
2026-09-24 10:23:50 +02:00
Riccardo Manfrin 6e17f50040 [client] Validate the saved service parameters and pin the netsh lookup (#7584)
* [client] Export the only-owner-writable path check from elevate

Pure refactor, no behavior change: the existing checkOnlyOwnerWritable gets a
thin exported wrapper so callers outside the elevation path can reuse it. No
call site changes here.

* [client] Validate the saved service parameters before applying them

The install reads <stateDir>/service.json and applies it to the service it then
registers: its arguments, its config path and its environment. The restricted
ACL that saveServiceParams puts on the state directory is applied when the file
is written, which is not necessarily before the file is first read, so the
install now checks the file rather than assuming it.

A file whose ownership or permissions are not the ones saveServiceParams
produces is treated as absent, and the install proceeds with its defaults. The
check covers the directories above the file as well, so what is checked is what
is read.

* [client] Restrict which environment variables the service is registered with

--service-env, and the service.json it persists to, accepted any name. A small
set of them decides how a process resolves the executables and libraries it
loads, and the daemon needs none of those: it now refuses them when they are
passed explicitly, and drops them with a warning when they come back from a
service.json written by an older version, so an upgrade does not fail over a
variable nobody needs.

* [client] Resolve netsh by absolute path

The lookup consulted PATH first and fell back to System32, in both the copy the
userspace firewall uses and the one that tears the interface down. It now asks
Windows for the system directory, so the resolution no longer depends on the
environment the service happens to be started with.

* [client] Move the System32 lookup into a package both callers share

Pure refactor, no behavior change: client/iface and client/firewall/uspfilter
carried a copy each of the same function, and neither imports the other, so the
body moves to client/internal/wincmd — alongside winregistry, which is where
the client's other Windows-only helper already lives. Both call sites now read
wincmd.System32("netsh").

* [client] Cover the System32 lookup with a test

Asserts what the previous commits changed: the lookup is absolute, and neither
PATH nor %SystemRoot% moves it.

* [client] Refuse the loader environment families by prefix

Review follow-up on the previous commit:

- LD_* and DYLD_* are now refused whole rather than name by name. Their members
  differ per platform and libc and grow with new OS releases, so a list of them
  is out of date as soon as it is written — DYLD_FALLBACK_LIBRARY_PATH and
  DYLD_FALLBACK_FRAMEWORK_PATH were already missing from it.
- The names are folded to upper case only on Windows, where a variable is the
  same one however it is spelled. Elsewhere the environment is case-sensitive,
  so Path and PATH are two variables and only the exact spelling is the one that
  is read; the fold refused the wrong one.
- TEMP and TMP stay in the denylist, but the rationale and the message now say
  what they actually decide: where the service writes, not what it loads.
2026-09-23 21:47:48 +02:00
Theodor S. Midtlien cfcb304fbf Use ReadJson for parseProfile 2026-09-23 16:02:36 +02:00
Riccardo Manfrin cb7ca8ef3f [client,management] Skip route firewall rule computation when no firewall (#7624)
* [client,management] Skip route firewall rule computation when no firewall

A peer that runs with the firewall disabled has no ACL manager and no
firewall to program, so nothing ever reads RoutesFirewallRules: the only
consumers are acl.Manager, which is reached solely when e.acl is set, and
the legacy-management probe in updateNetworkMap, which is guarded by a
non-nil firewall.

Building those rules is the most expensive part of a sync on a peer that
routes many network resources. On a 15k-peer deployment a debug bundle
showed getPeerNetworkResourceFirewallRules accounting for 62% of the
allocations of Calculate, and Calculate for effectively all of the
allocations of handleSync, which was taking 3.2s on average and holding
the engine lock for the duration.

Let the caller ask Calculate to leave the rules out. The client passes
its existing DisableFirewall setting; the management server keeps the
default and still produces them.

RoutesFirewallRulesIsEmpty is set from the resulting empty list, so a
receiver that would otherwise infer legacy management from an empty rule
set does not misread the skip.

* [client,management] Cover the skip flag through the envelope

Review feedback on #7624.

The components test compared only the length of the peer firewall rules, so
a change to their content would have passed while the message claimed they
came out unchanged. Compare the slices.

The skip path was also only exercised by setting the field directly on the
components, which bypasses the envelope conversion where
RoutesFirewallRulesIsEmpty is derived. That bit is what keeps the client from
reading skipped rules as a legacy management server, so it gets a test that
goes through EnvelopeToNetworkMap with the flag set.

* [management] Give the router a peer ACL so the rule comparison bites

Review feedback on #7624.

peer-router-1 appears in no peer ACL in the shared fixture, so its
FirewallRules came out empty and the equality assertion compared two empty
slices — it would have passed even if the peer rules were dropped entirely.

Add a policy covering the router and require the baseline to be non-empty
before comparing.
2026-09-23 11:50:44 +02:00
Theodor S. Midtlien 485c905b88 Only log active profile lookup on debug 2026-09-22 17:37:27 +02:00
Theodor S. Midtlien dc45215348 Add config name to ConfigInput 2026-09-22 17:32:05 +02:00
Theodor S. Midtlien 9d40a09459 Disable ownership on mobile 2026-09-22 15:29:39 +02:00
Viktor Liu f6109a3395 [client] Remove the empty GPO DNS policy store on Windows teardown (#7563) 2026-09-22 12:44:10 +02:00
Theodor S. Midtlien a785814a3f Improve ui when other holds the session 2026-09-21 17:35:11 +02:00
Zoltan Papp bc0671fd21 [client] Fix peers not being notified when the relay connection drops (#7490)
* [relay] Signal relay disconnects through the conn context

AddCloseListener deduplicated listeners by comparing
reflect.ValueOf(callback).Pointer(). For a method value that pointer is
the address of the compiler-generated wrapper, not an identity bound to
the receiver, so every peer's w.onRelayClientDisconnected compared equal.

All peers on the home relay register under the same connectionURL key, so
only the first registration survived and the rest were silently dropped.
On a relay disconnect those peers were never notified: statusRelay stayed
connected and the reconnect guard never fired. The relayed net.Conn itself
was closed by closeAllConns, so nothing leaked, but the peer state machine
did not learn about it. Foreign relays had the same defect scoped to the
peers sharing that server.

Rather than fixing the deduplication, drop the peer-level listener registry
entirely. A relayed Conn now exposes Context(), cancelled when the
connection is torn down, with a cancellation cause naming the reason. This
is the same shape quic-go uses for its Conn and Stream types, and it
removes the whole class of problems around listener identity, lifetime and
deregistration: the signal belongs to the resource instead of a side table.

WorkerRelay watches that context in a goroutine whose lifetime matches the
connection. A watcher that wakes up for a superseded connection compares
the conn pointer against the current one and returns without touching the
state machine, so a fast relay reconnect cannot have a stale watcher tear
down the connection that replaced it.

Client.SetOnDisconnectListener stays: it is server-level and drives the
reconnect guard and foreign relay eviction, unrelated to peers.

handleRelayReady also checks the conn context, closing the race where the
relay dies between OpenConn and the readiness handoff and the peer would
otherwise build a WireGuard endpoint over a dead connection.

TestNotifierDoubleAdd covered the removed mechanism and is gone.
TestForeignAutoClose asserted nothing (both branches logged); it now waits
for the relay to leave the client map and fails if it does not.

* [relay] Fix build: return the concrete conn from Client.OpenConn

OpenConn now returns *Conn, but it still went through connContainer.netConn(),
which widens to net.Conn. The helper had one caller and only existed to produce
the interface value the signature no longer wants, so return container.conn
directly and drop it.

* [relay] Assert the local-close cancellation cause explicitly

The local-close test only rejected ErrServerDisconnected, so it would also
have passed for ErrPeerDisconnected or a bare context.Canceled. closeConn
cancels with net.ErrClosed, so assert that.

* [client] Ignore relay disconnects from superseded connections

The relayed conn watcher compared the conn pointer under relayLock, released
it, and only then tore the connection down. A new offer could install its
replacement in that window, so a watcher that validated the old pointer went
on to close the proxy of the connection that had already replaced it and
report the peer as disconnected while it was up.

Move the decision to where the teardown happens. Conn records which relayed
connection the current proxy was built from, and onRelayDisconnected takes the
connection the signal belongs to and drops it under conn.mu when it is no
longer the current one. Check and effect are now in the same critical section,
so the verdict cannot go stale before it is acted on.

This also covers the proxy read loops, whose disconnect listener took no
argument and had the same defect: it now names the connection it belongs to.
The WG timeout path keeps passing nil, since it deliberately tears down
whatever is current.

* [client] Bind the relayed conn reference to the proxy swap

relayedConnRef was set at the top of the readiness path, but wgProxyRelay only
changes at the end, in setRelayedProxy. The two failure returns in between —
newProxy and ConfigureWGEndpoint — left the reference pointing at a connection
that never became active while the old proxy was still installed. A disconnect
of that old, live relay would then be dismissed as belonging to a superseded
connection and never cleaned up.

Set the reference in setRelayedProxy, next to the proxy it belongs to. Both
success paths go through it and neither failure path does, so no failure branch
has to remember to roll anything back.
2026-09-21 17:00:37 +02:00
Theodor S. Midtlien e5c1b21fd3 Fix listing unowned profile and fallback 2026-09-21 15:56:06 +02:00
Theodor S. Midtlien f8944699dd Resolve username for CLI owner output 2026-09-21 13:49:42 +02:00
Theodor Midtlienandcubic-dev-ai[bot] 7e3759a5a1 Update client/internal/profilemanager/service.go
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-09-18 18:16:40 +02:00
Theodor S. Midtlien 8403085a44 Only show owner on --show-owner for profile list 2026-09-18 18:10:28 +02:00
Theodor S. Midtlien d98ef09141 Add NB_DISABLE_PROFILE_OWNERSHIP env flag 2026-09-18 17:56:03 +02:00
Theodor S. Midtlien f0d2dd474c Clean up claim command text 2026-09-18 17:35:59 +02:00
Theodor S. Midtlien 9beecf7d69 Move disable default auto claim check 2026-09-18 17:15:07 +02:00
Theodor S. Midtlien cda3da5ed1 Fix tests for denial errors 2026-09-18 17:08:06 +02:00
Theodor S. Midtlien 1a74019161 Fix status before up 2026-09-18 14:52:25 +02:00
Theodor S. Midtlien 5d9e791626 Fix comments 2026-09-18 14:19:59 +02:00
Theodor S. Midtlien 3d6591b053 Fix status and up cli output 2026-09-18 13:17:21 +02:00
Theodor S. Midtlien 64c84df357 Remove race reload test 2026-09-18 12:22:57 +02:00
Theodor S. Midtlien 29be224cdf Cleaup profile parsing 2026-09-18 12:22:04 +02:00
Theodor S. Midtlien cb9d2ee3bb Small refactor of Authz 2026-09-18 11:28:16 +02:00
Theodor S. Midtlien 6dcb1374e9 Move profile resolution to the authz gate 2026-09-18 11:19:35 +02:00
Theodor S. Midtlien 96f9ea7428 Move active migration to OwnsProfile 2026-09-17 19:57:40 +02:00
Theodor Midtlien cec9ee6699 [Client] Surface readable Authz errors and add profile claim command (#7540)
* [client] Surface error messages for IPC authz in UI (#7553)
2026-09-17 14:36:56 +02:00
Theodor S. Midtlien 499b5a8cd0 Fix service test for windows 2026-09-17 13:21:05 +02:00
Theodor Midtlien 90052cbefb [client] Profile ownership console user tofu (#7529)
* Add consoleuser and stamp default profile on known username in migration

* Refactor consoleuser to verify Id, fix seats on linux and default stamp

* Add default profile claim

* Add disable auto-claim of default profile and always fail close

* Add disable auto-claim flag to migration

* Adding timeout to console user on Linux and close library load on darwin

* Fixed failed close test

* Close both Dlopen for darwin

* Replace RegisterFunc with purego.Dlsym to avoid possible panic

* Fix freebsd tty enumeration

* Fix active profile migration logic and add test

* Log defaultClaimDisabled error once

* Guard against panicking console user lookup.

* Fix merge conflict

* Fix broken tests
2026-09-17 11:20:13 +02:00
Theodor Midtlienandcubic-dev-ai[bot] 52b16e7a5c [client] Profile ownership migration (#7508)
* Implement OwnsProfile on Server

* (WIP) List profiles based on ownership by Identity

* (WIP) Migrate active_profile

* Fix status and list profiles

* Add profile stamping as active migration

* Add one-shot migration

* Only default profile fail open

* Use restricted write for config json

* Fix stale server config after stamp

* Fix OwnsProfile fallback to active profile

* Fix config concurrent reload during OwnsProfile check

* Move known check to inside stamp owner

* Update client/internal/profilemanager/service.go

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* Recover from dup active profiles that cannot be resolved with username.

* Add test for already owned profile during migration

* Improve stamping of fields in the config

* Apply suggestion from @cubic-dev-ai[bot]

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* Fix codespell and test comment

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-09-17 11:20:12 +02:00
Viktor Liu 15ed6f8f15 Add an optional --allow-group flag restricting the daemon sockets (#7478) 2026-09-16 13:30:10 +02:00
Theodor Midtlienandcubic-dev-ai[bot] abb94ad2d2 Update client/internal/debug/debug.go
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 258a20c433 Fix empty active state read 2026-09-16 10:37:59 +02:00
Theodor Midtlienandcubic-dev-ai[bot] fa3689c079 Update client/internal/debug/debug.go
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 331c490326 Fix typo 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 2d5ee900d0 Replace RequireFlowInitiator with AuthzLevel and clear flow on switch profile 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 7705645492 Remove double error log 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 1538d5f11c Add profile owners to debug bundle 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 5f7d869426 Fix status and list profiles 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 45e8bd8af4 Let unimplemented RequireFlowInitiator pass 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien b620173f51 Clarify the Rule comment 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien a585626950 Remove Authorization context and fix bugs in rule and targetProfile 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien fc93bfc561 Add method interceptor tests to ensure that authz is configured for every RPC 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien bbf28a40ed Add authorization framework for gRPC methods 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien cacdb50c0e Add known mark to identity, fix credentials comparison bugs 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 15003fc495 Add owners to list profile ipc 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien a9fb48d80b Let active profile owner be the source of truth for the session holder 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 3a2f6df038 Fix debug test 2026-09-16 10:37:59 +02:00
Theodor S. Midtlien 04c00a9a19 Improve owner config parsing 2026-09-16 10:37:59 +02:00