Report ssh command failures to the surface (#1959)
The ssh debug commands told the user when something went wrong but
never told the surface that ran them, so `ssh host cmd` always exited 0
and a few failures were not reported at all. A failed command now
returns its error, a failure the user has already heard about is a
commands.Failure, and the ssh exec path exits 1 for either. The command
bodies also lose their ssh prefixes and the duplication they carried
over from ssh.go; both goldens pin that nothing else changed.
- Dispatch returns the callback's error, or shlex's; the ssh session
logs it at debug, and not at all for a Failure the user already saw
- commands.Fail writes a message and returns it as a Failure in one step;
an unknown command, `help` for a command that is not there, a failed
reload and an unbalanced quote are failures
- ssh exec exit-status is 1 for a command, flag or failure error, 0
otherwise; the e2e golden records the exit status for every case
- Clone rebinds help to the copy, so an ssh session's help lists logout
and `help logout` and `logout -h` answer; sshd.LogoutCommand is the
session's logout, exported for tests
- "did not understand" names the first word only, the one looked up;
DispatchArgs takes just the tokens
- log-format writes its refusal to the user, as log-level does
- print-relays emits the relay error as a string and omits the key when
there is none, where it printed {} or "Error":null
- list-hostmap and list-lighthouse-addrmap -json return the encode
error; print-cert reports a certificate that will not marshal
- a flags type that is not the one registered is an internal error, not
a silent success
- command functions and flag types are <name>Command and <name>Flags;
parseVpnAddr and listHostMapFlagSet replace the repeated parse block
and flag set; close-tunnel sends through sendCloseTunnel
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Migrate commands from ssh into a transport neutral package
- add golden tests validating that output remains unchanged
- move commands to commands.go
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
gvisor's arm64 race-build compare-and-swap (pkg/sync/race_arm64.s)
loaded the new value into the register meant for the old one (R1
instead of R2), so it never succeeded. Sleepers could not commit to
parking and spun: under -race on arm64 every idle service netstack
busied about 14 cores, and TestService's static host lookup of
localhost missed its 250ms timeout and stalled for the 30s static_map
cadence. Fixed in gvisor 1b2946c4fa.
Go 1.27.2 is now the minimum because gvisor's go branch requires it.
golangci-lint is bumped to v2.14, the first release that can read
go1.27.2 export data.
Tailscale with an exit node treats every interface address prefix as an
attached LAN and either claims it or excludes it, and configd then rewrites
the matching route away from nebula's utun. Interfaces holding a single
address are skipped, so assign /32 and /128 and add the network route
ourselves for both families.
* examples: set socket buffers and raise tun tx_queue
* examples: use the default tcp max window for socket buffers
* examples: note buffers are linux only, clarify tx_queue default
* tun: default tx_queue to 5000
On a domain-joined Windows host the DNS Client registers every adapter's
addresses under the host name in AD DNS when "Register this connection's
addresses in DNS" is on, which is the default for a new adapter. When the
Nebula adapter registers, LAN clients that are not on the overlay resolve
the host name to its overlay IP and RDP, SMB and PowerShell Remoting to it
fail intermittently, with nothing pointing at the tunnel as the cause.
Windows registers on address assignment, periodically, and on every
ipconfig /registerdns.
Right after the wintun adapter is created and before Activate assigns any
address, write RegistrationEnabled=0, DisableDynamicUpdate=1 and
MaxNumberOfAddressesToRegister=0 under both the Tcpip and Tcpip6
Parameters\Interfaces\{GUID} keys. The adapter checkbox alone has proven
insufficient in practice, as has disabling dynamic updates alone, so all
three are set, matching what Tailscale and NetBird do. A failure to write
the keys is logged as a warning and does not fail adapter creation.
StartHandshake returned a hostinfo with no RemoteList; handleOutbound attached
one lazily on its first tick. Anything that touched the pending host before
then, notably create-tunnel -address, dereferenced nil and took the daemon
down. StartHandshake now attaches the lighthouse's list as it builds the
hostinfo. To keep the surrounding locking sound, a lighthouse now resolves a
punch target before taking the querier's RemoteList lock, and closeTunnel
deletes the host and evicts its RemoteList under a single hostmap write lock so
a completing handshake cannot land in between. The lock order, now documented
on the handshake manager mutex, is hostmap, then handshake manager, then
lighthouse, then RemoteList; no RemoteList lock is ever held across a hostmap
lookup.
newTunFromFd was a stub on darwin, so an embedder handed a utun by the OS had
no way to use it. A darwin network extension is given exactly that:
NEPacketTunnelProvider creates the device and applies addressing, mtu and
routes from its network settings, and a sandboxed extension cannot change them
afterwards. Adopting that fd means everything about moving packets is shared
with newTun and only the setup differs, so the tun tracks whether the host owns
it and leaves the system routing table and interface config alone when it does.
Co-authored-by: Nate Brown <nbrown.us@gmail.com>
The goroutines Main starts stop only when its context does, and only a caller
holding the Control can arrange that. Cancelling solely on error left a config
test, which returns no Control and no error, with the lighthouse query worker
and a hostname resolver per dns named static host running for the life of the
process. Every embedder that validates a config in process rather than by
exec'ing pays for that on each config load, dnclient and the apple clients
included.
Co-authored-by: Nate Brown <nbrown.us@gmail.com>
* Add script to backport a merged PR to a release branch
.github/backport.sh cherry-picks a merged PR's commit onto a release
branch and opens a backport PR mirroring the shape of #1842.
- Infers the target release from the PR's milestone (v1.12.0 -> release-1.11);
an explicit target-version argument overrides it.
- Requires a clean working tree (untracked files allowed) before starting.
- Prompts with the exact push and gh pr create commands before running them.
- Sets the new PR's milestone to the highest open v<target>.* milestone.
- Removes the needs-backport label from the original PR once the backport opens.
- Supports --continue to resume after resolving cherry-pick conflicts.
* cleanup
* just fetch all of origin
We need to ensure we have MERGE_SHA available too