Skip to content

control: plain http key fetching, optional early payload#111

Merged
3 commits merged intomainfrom
npry/ctrl.http
Apr 22, 2026
Merged

control: plain http key fetching, optional early payload#111
3 commits merged intomainfrom
npry/ctrl.http

Conversation

@npry
Copy link
Copy Markdown
Collaborator

@npry npry commented Apr 17, 2026

Alternate to #93, same concept

By comparison, this puts insecure key fetching behind a feature flag (insecure-keyfetch), refactors the prefixed reader type to use Bytes internally and drop the Unpin bound, and generally minimizes the diff size

@npry npry changed the title control: control: plain http key fetching, optional early payload Apr 17, 2026
@npry npry force-pushed the npry/ctrl.http branch 2 times, most recently from 4ec4c22 to 92a7441 Compare April 20, 2026 09:14
@npry npry marked this pull request as ready for review April 20, 2026 13:15
@npry
Copy link
Copy Markdown
Collaborator Author

npry commented Apr 20, 2026

The examples work against local testcontrol with --features ts_control/insecure-keyfetch — I wrote a little testcontrol cli driver in my private repo and added support for TS_CONTROL_URL and --control-url in the examples here

Copy link
Copy Markdown
Member

@bradfitz bradfitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM at least (fwiw)

@npry npry force-pushed the npry/ctrl.http branch 4 times, most recently from 95c2aba to b7f02a8 Compare April 22, 2026 15:50
bradfitz and others added 3 commits April 22, 2026 12:41
The control client previously assumed the server always sends an early
challenge packet after the Noise handshake. This breaks when using Go's
testcontrol server, which skips the early payload.

Changes:

- ts_control/connect: make the post-handshake early payload (challenge
  packet) optional by peeking at the first 9 bytes and chaining them
  back if they aren't the magic prefix
- ts_control/control_dialer: use the same optional challenge logic for
  reconnections

Co-Authored-By: Nathan Perry <np@npry.dev>
The control client previously required TLS for all control server
connections. This assumptions break when using Go's testcontrol server,
which serves plain HTTP.

Changes:

- ts_control/connect: select HTTP/1.1 over TCP or TLS based on URL
  scheme, making http:// control URLs work
- ts_http_util: change upgrade request from GET to POST to match Go's
  controlhttpserver which requires POST for /ts2021

Co-Authored-By: Nathan Perry <nathan@tailscale.com>
Signed-off-by: Nathan Perry <nathan@tailscale.com>
Change-Id: I4e0f6f1f3481199356ebb3750cbc2fd26a6a6964
@npry npry closed this pull request by merging all changes into main in 4df80de Apr 22, 2026
@npry npry deleted the npry/ctrl.http branch April 22, 2026 16:54
kradalby added a commit to kradalby/headscale that referenced this pull request Apr 28, 2026
Add TailscaleRustInContainer (tsric), a Rust-client counterpart to
integration/tsic. It runs the axum example from tailscale-rs in a
Docker container and exposes the same lifecycle hooks as tsic
(Shutdown, SaveLog, Execute, WriteFile) so integration tests can
treat it as any other Tailscale node.

Dockerfile.tailscale-rs clones tailscale-rs at build time, so no
local source checkout is required. The repo URL and ref are Docker
build arguments (TAILSCALE_RS_REPO, TAILSCALE_RS_REF) exposed as
tsric.WithRepo / tsric.WithRef options. The HEADSCALE_INTEGRATION_
TAILSCALE_RS_IMAGE environment variable provides an escape hatch for
using a pre-built image instead of building from source.

The default ref is upstream main. Two upstream changes wire the
example to a local headscale:

  - tailscale/tailscale-rs#109 — env fallback for control URL and
    auth key in the axum example (merged 2026-04-21)
  - tailscale/tailscale-rs#111 — plain-HTTP control-key fetching
    behind the ts_control insecure-keyfetch Cargo feature
    (merged 2026-04-22)

The Dockerfile patches the cloned root Cargo.toml to expose
ts_control's insecure-keyfetch through the tailscale crate so it
can be enabled when building the axum example, since headscale's
integration harness runs the control plane over plain HTTP.
kradalby added a commit to kradalby/headscale that referenced this pull request Apr 28, 2026
Add TailscaleRustInContainer (tsric), a Rust-client counterpart to
integration/tsic. It runs the axum example from tailscale-rs in a
Docker container and exposes the same lifecycle hooks as tsic
(Shutdown, SaveLog, Execute, WriteFile) so integration tests can
treat it as any other Tailscale node.

Dockerfile.tailscale-rs clones tailscale-rs at build time, so no
local source checkout is required. The repo URL and ref are Docker
build arguments (TAILSCALE_RS_REPO, TAILSCALE_RS_REF) exposed as
tsric.WithRepo / tsric.WithRef options. The HEADSCALE_INTEGRATION_
TAILSCALE_RS_IMAGE environment variable provides an escape hatch for
using a pre-built image instead of building from source.

The default ref is upstream main. Two upstream changes wire the
example to a local headscale:

  - tailscale/tailscale-rs#109 — env fallback for control URL and
    auth key in the axum example (merged 2026-04-21)
  - tailscale/tailscale-rs#111 — plain-HTTP control-key fetching
    behind the ts_control insecure-keyfetch Cargo feature
    (merged 2026-04-22)

The Dockerfile patches the cloned root Cargo.toml to expose
ts_control's insecure-keyfetch through the tailscale crate so it
can be enabled when building the axum example, since headscale's
integration harness runs the control plane over plain HTTP.
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.

3 participants