Skip to content

feat: add engine surface for daemon — listen port, peer SSH host keys, re_stun#263

Merged
GeiserX merged 1 commit into
mainfrom
feat/engine-asks-listenport-sshkeys-restun
Jun 15, 2026
Merged

feat: add engine surface for daemon — listen port, peer SSH host keys, re_stun#263
GeiserX merged 1 commit into
mainfrom
feat/engine-asks-listenport-sshkeys-restun

Conversation

@GeiserX

@GeiserX GeiserX commented Jun 15, 2026

Copy link
Copy Markdown
Owner

What

Three small, additive engine-API surfaces the downstream daemon needs (its ENGINE_ASKS.md #22, #23, #26). Each unblocks a daemon CLI feature on a pin bump. Behaviorally faithful to Go tsnet/tailscaled.

#23StatusNode.ssh_host_keys (Go ipnstate.PeerStatus.SSH_HostKeys)

The wire HostInfo.ssh_host_keys already existed but wasn't projected. Now the domain Node carries ssh_host_keys: Vec<String> (populated in the wire→domain conversion from HostInfo.sshHostKeys), and StatusNode surfaces it. Pure read-projection. Lets the daemon write a known_hosts from the netmap for tnet ssh (pinned host-key verification, no TOFU).

#26Device::re_stun() (Go magicsock.Conn.ReSTUN)

Forces an immediate STUN re-probe / endpoint re-derivation without tearing down sockets — the lighter sibling of rebind(). Reuses the STUN-sweep machinery (probe_stun_servers_once, gated by stun_probe_should_run); no socket swap, no control round-trip; clean no-op when DERP-only. For tnet debug restun.

#22Config.wireguard_listen_port: Option<u16> (Go tailscaled --port)

Pins the UDP port magicsock binds for WireGuard + disco. None = ephemeral (unchanged default behavior, = Go's port 0); Some(p) binds p for fixed-firewall-pinhole deployments. Threaded Config → ts_control::Config → Env → bind_underlay_addr (the single initial-bind site). A taken pinned port falls back to ephemeral (never hard-fails bring-up — mirrors rebind_socket's fallback). The bind family is unchanged (IPv4-only default + fail-closed posture untouched — only the port is configurable). A later rebind() keeps the pinned port automatically (it already prefers the current local port).

Tests

Wire→domain→status ssh_host_keys projection (present + absent); re_stun peer-gate + DERP-only no-op; bind_underlay_addr pins a free port and falls back to ephemeral when taken; wireguard_listen_port threads Config → Env and crosses From<&Config>; default is None.

Gates (local, all green — re-verified after rebasing onto current main)

cargo test -p geiserx_ts_control -p geiserx_ts_runtime -p geiserx_tailscale (248 + 354 + 24) · clippy -D warnings (3 crates + tun lane) · cargo fmt --check · cargo doc (broken_intra_doc_links=deny) · cargo run -p checks.

First batch of the daemon engine-asks. After this lands + a release, the daemon enables these via a pin bump: tnet ssh (host-key pinning), tnet debug restun, tailnetd --port. (Separately confirmed for the daemon: the identity-federation feature compiles clean on the facade — the 4 WIF flags need only the feature flag on, no engine code.)

Signed-off-by: Sergio sergio@geiser.cloud

Created using Claude Code (Opus 4.8)

…, re_stun

Three additive engine-API asks the tailscaled-rs daemon needs, mirroring Go
tsnet/tailscale behavior:

- StatusNode.ssh_host_keys: project Hostinfo.sshHostKeys onto the domain Node
  and surface it on StatusNode (Go ipnstate.PeerStatus.SSH_HostKeys), for
  tailscale ssh host-key pinning. Empty when control advertised none. The wire
  PeerChange carries no ssh host keys, so it is left unchanged.

- Device::re_stun: force an immediate STUN/endpoint re-probe without rebinding
  the underlay socket (Go magicsock Conn.ReSTUN). Factored the STUN sweep out
  of rebind_and_reprobe into a shared DirectManager::stun_sweep_once; no socket
  swap, no re-ping, no-op when DERP-only inert.

- Config.wireguard_listen_port: pin the UDP port magicsock binds for WireGuard
  + disco (Go tailscaled --port), threaded Config -> ts_control::Config ->
  ForwarderConfig -> Env -> the initial bind_underlay_addr. None keeps today's
  ephemeral bind; Some(p) pins p with an ephemeral fallback if taken (mirroring
  rebind_socket) so a port collision never fails bring-up, and a successful pin
  carries across rebind. IPv4-only-default + fail-closed bind family unchanged.

Signed-off-by: GeiserX <9169332+GeiserX@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@GeiserX, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 34 minutes and 22 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3e3f5432-5a51-4488-9459-31da41f0c98d

📥 Commits

Reviewing files that changed from the base of the PR and between c3e27c7 and 1c45704.

📒 Files selected for processing (22)
  • src/config.rs
  • src/lib.rs
  • ts_control/src/config.rs
  • ts_control/src/node.rs
  • ts_control/src/serve.rs
  • ts_control/src/service.rs
  • ts_runtime/src/derp_latency.rs
  • ts_runtime/src/direct.rs
  • ts_runtime/src/env.rs
  • ts_runtime/src/forwarder_actor.rs
  • ts_runtime/src/ipn_bus.rs
  • ts_runtime/src/lib.rs
  • ts_runtime/src/magic_dns.rs
  • ts_runtime/src/netmon.rs
  • ts_runtime/src/netstack_actor.rs
  • ts_runtime/src/peer_tracker/mod.rs
  • ts_runtime/src/peer_tracker/peer_db.rs
  • ts_runtime/src/peerapi.rs
  • ts_runtime/src/route_updater.rs
  • ts_runtime/src/src_filter.rs
  • ts_runtime/src/status.rs
  • ts_runtime/src/tun_actor.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/engine-asks-listenport-sshkeys-restun

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@GeiserX GeiserX merged commit 66f8626 into main Jun 15, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant