tailcat changelog
v0.7.0 (2026-09-19)
--serve=exit-nodeservers now forward UDP flows; previously only
TCP was forwarded, so DNS, QUIC, and other UDP traffic through an
exit node went nowhere.- Serving local ports works from Windows: the server resolves
localhostitself instead of using the hosts file, which Windows
ships without localhost entries, so the name no longer escapes to
real DNS servers. It also dials both 127.0.0.1 and ::1, reaching
services bound to only one loopback address. Official binaries also
no longer build with thenetgotag that forced Go's pure resolver
on Windows and macOS; they now use the operating system's resolver
there, like a defaultgo builddoes.
(#108, reported
by @Sammy-T) tailcat cpnow works with OpenSSH 8.7 through 8.9 clients, such
as Ubuntu 22.04's. Those versions still speak the legacy SCP
protocol unlessscp -sasks for SFTP, which is all tailcat file
services accept, so copies failed. tailcat now checks whether the
installed scp understands-sand passes it when it does; older
clients without the flag are unchanged.
(#114, fixed in
#123 by
@BreezeDelegate)- Go library:
Server.Status()now includes aPeerentry per
connected client, withCurAddrandRelayto tell a direct path
from a DERP-relayed one.
(#116, reported
by @Mo3he) - Go library: the new
Server.Listen(ctx, network, address)serves
TCP and UDP ports in the standardnet.Listenershape, as an
alternative to theOnTCPandOnUDPhooks; for UDP, each Accept
returns one client flow as anet.Conn. Listeners claim their
specific ports ahead of the wildcard hooks, and Listen starts the
server if it isn't running yet. tailcat forwardtakes an--open-browserflag that opens a web
browser to the forwarded local port;tailcat browse <tc-addr>is
an alias fortailcat forward --open-browser <tc-addr> 0:80.execservice:tailcat serve exec -- <command>runs the command
for each incoming connection with the connection as its stdin and
stdout, like inetd. With thesshorno-auth-sshservice, the
command after--instead replaces the shell for every session,
like OpenSSH'sForceCommand, with no shell, client-chosen command,
or SFTP offered.tailcat sshto a DNS-named destination first probes the server the
way a stranger would, with no credentials, and refuses to connect if
the server hands out a shell to anyone, since an address published
in DNS is public;--skip-dns-safety-checkopts out. The README,
the root help's DNS section, andserve no-auth-sshstartup now all
warn that DNS-published addresses need--allowor
--ssh-authorized-keys.
(#100)- Fixed argument parsing under Termux on Android, whose loader inserts
the executable's path as an extra argument.
(#92, @shaunlee) - The linux binaries now work when run directly on Android, under
Termux,adb shell, or a rooted shell. Android has no
/etc/resolv.conf, so a plain Go binary there could not resolve any
name and failed at startup fetching the DERP map; it also found no
CA roots and could not enumerate network interfaces. tailcat now
links tailscale.com'sandroiddnsandandroidbinfeatures, which
detect Android at runtime, resolve names through Android's DNS
resolver daemon, use the system certificate store, and fall back to
a synthetic single interface. On regular Linux they do nothing.
(#117, reported
by @risharde) - Updated the tailscale.com dependency to its 2026-09-16 main branch,
which brings data path performance work from wireguard-go and
gVisor. wireguard-go now moves each batch of packets through one
buffer of about 128 KiB instead of a separate buffer per packet,
which in upstream's iperf3 benchmarks between two Linux machines
raised throughput by 7% to 35% depending on the workload and cut
peak memory for TCP transfers by half to three quarters. Small
outbound packets such as keepalives and handshakes now use 2 KiB
buffers, so packets waiting on a peer with no active session hold
at least 97% less memory than before. gVisor's TCP stack, which
carries every tailcat connection, now uses CUBIC congestion control
and RACK loss detection; both had been switched off because of
gVisor bugs that have since been fixed upstream. - tailcat is on the Snap Store as a
community-maintained, strictly confined snap; see INSTALL.md for
where its config lives. - tailcat now has a Bluesky account for release and project news:
@tailcat.dev.
Changelog
- 15ab9e6 tailcat: report peers in Server.Status so callers can see direct vs relayed
- 6b10612 cmd/tailcat: use SFTP when scp supports it
- 79dc7ef all: bump tailscale.com, run on Android, fix e2e test deadlock
- 9777a39 cmd/tailcat: fix nil Process crash in two e2e test timeouts
- 6b73a26 INSTALL.md: drop -t from the docker run example
- cbbabaf README.md, INSTALL.md: move install instructions to their own page
- ece58d8 cmd/tailcat: fix ETXTBSY flake starting test-built binaries
- 57b8ce5 CHANGELOG.md: add unreleased entries for changes since v0.6.0
- d0d5991 cmd/tailcat: forward UDP through --serve=exit-node
- 5ceb166 cmd/tailcat, internal/localhostdns: fix serving local ports from Windows
- fd10188 tailcat: add Server.Listen for net.Listener-style TCP and UDP serving
- 91dc497 cmd/tailcat: add a browse command and a forward --open-browser flag
- 7a50a1a cmd/tailcat, tailcat: add an exec service and an SSH forced command
- 1233960 cmd/tailcat: warn about public DNS in root help and at no-auth-ssh startup
- 5a83b9f cmd/tailcat, README.md: warn when a DNS-named SSH destination is wide open
- b3aeffb cmd/tailcat: fix argument parsing under Termux on Android