This repository was archived by the owner on Jul 13, 2025. It is now read-only.
Fork Sync: Update from parent repository - #36
Open
github-actions[bot] wants to merge 2043 commits into
Open
Conversation
… path Processing a peer add/remove delta still materialized the full netmap (an O(n) slicesx.MapValues plus sort over all peers, at 10k+ peers in a large tailnet) twice per delta: once in UpdateNetmapDelta purely to hand the self node to Engine.SetSelfNode, and once in authReconfigLocked. Neither needs peers anymore. SetSelfNode gets the self node from the existing nodeBackend.Self accessor. authReconfigLocked only reads self-node fields (SelfNode, NodeKey, GetAddresses, HasCap) now that WireGuard peers ride the incremental route manager and per-peer config source, so it can use the peers-free NetMap accessor. That also makes nmcfg.WGCfg vestigial: since wgcfg.Config lost its Peers field, its peer walk existed only to emit the [v1] skip logs (expired peers, unselected exit nodes, unaccepted subnet routes), duplicating filtering the route manager already does. Delete the package and construct the two-field wgcfg.Config inline. The skip logs go away; if they're missed, the route manager can log them incrementally at upsert time instead of rescanning every peer on every reconfig. With this, the runtime.DidRange analysis (see the ts_rangehook test) shows a delta netmap update performing no O(n) range loops except updateRouteManagerExtras, and the delta phase of that test drops from 1.09s to 0.14s for 400 deltas at n=10000 (from 4.79s at the start of this effort, before the incremental route manager work). Updates #12542 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: Ia0e03ef9db0c988790b2c29de1f0505305e93f58
The tailscale/gokrazy-kernel module was a fork of rtr7/kernel that stalled at Linux 6.8.9 (July 2024). All of the kernel config options we had added in that fork (ENA, Xen for EC2, virtio-mmio for qemu microvm, virtio RNG, IPv6 policy routing, netlink diag, etc) are now present in the gokrazy project's own gokrazy/kernel.amd64 module, which tracks current kernel.org releases (Linux 7.1.3 as of this change) and is the gokrazy project's supported kernel for x86_64 PCs and VMs. Switch the tsapp and natlabapp images, the natlab VM tests, and the CI workflow to gokrazy/kernel.amd64, drop the tailscale/gokrazy-kernel dependency, and update gokrazy/kernel.arm64 to latest while here. Verified with TestEasyEasy, TestJustIPv6, and TestTailscaleSSH in tstest/natlab/vmtest with --run-vm-tests. Updates #1866 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I90c3765a4e18f5609b4d77b51ac38d17c8e3688a
Split TestTailscaleSSH into separate tests per host OS being tested to allow for potentially running these tests in parallel on different machines. Updates #13038 Signed-off-by: Mario Minardi <mario@tailscale.com>
The nodeBackend's netMap.Peers slice is frozen at the last full netmap install; the live per-peer state lives in the nodeBackend.peers map, updated by delta mutations. Three spots still read the stale slice or paid to materialize a fresh one: AppendMatchingPeers iterated netMap.Peers and re-looked-up each ID in the peers map (with a lock round-trip per peer), so peers added by a delta since the last full netmap were invisible to it. That affected its callers: taildrop's file-target list, exit node suggestions, and conn25's connector discovery. It now snapshots the peers map directly (sorted by node ID, matching the old netmap ordering). DebugPeerDiscoKeys read netMap.Peers and so returned stale disco keys after deltas. It now reads the peers map via the new nodeBackend.peerDiscoKeys. pingPeerAPI called NetMapWithPeers, building and sorting the full O(n) peer slice, just to linearly scan it for one IP. It now uses the nodeBackend's existing by-address index and the new O(1) PeerByID accessor, and passes the peers-free netmap to peerAPIBase, which only reads the self node's addresses. Updates #12542 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I2e57527d64733b4eb17006f896faaa907b1d128c
The android client was converted in tailscale/tailscale-android#797 Updates #12542 Change-Id: Ibb2cc6fbafdad93ae44e1a60e5cc5de8183f9b97 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The Apple clients' last consumer of the legacy Notify.NetMap field was converted to peer deltas in tailscale/corp#44962, so tailscaled no longer needs to build and emit full netmaps on the IPN bus for darwin and ios. Windows is now the only remaining platform on the legacy path. Updates #12542 Change-Id: I295d826735191bb601d2b69d8d85d37a5a82b6c9 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
…tests The "vm" CI job ran a single test (TestRunUbuntu2404 from tstest/integration/vms) on a privileged self-hosted runner. Its coverage is nearly all redundant with the modern natlab vmtest suite, which boots real Ubuntu VMs and already exercises connectivity, kernel TUN, SSH, Taildrop, ACME, and OS DNS integration on GitHub-hosted runners. The two things it tested that natlab didn't are added back as natlab tests so the runner can be decommissioned: TestUbuntuSystemdUnit runs tailscaled via the stock systemd unit that Linux packages ship (cmd/tailscaled/tailscaled.service with tailscaled.defaults as its EnvironmentFile) instead of launching the binary directly, verifying the unit's directives and its Type=notify readiness handshake. TestDNSExtraRecordsSearchDomains verifies that control-plane DNS ExtraRecords and search domains are resolvable through the guest's OS resolver (libc to systemd-resolved to quad-100). Updates #13038 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I8d0dfb8b8153289e7ca78f3af03dfece9497bfe8
…ertificate (#20478) ModifyTLSConfigToAddMetaCert (and its inline copy in cmd/derper) appended the DERP meta cert directly to the *tls.Certificate returned by the underlying GetCertificate. autocert returns a certificate sharing a cached chain slice (and, on the TLS-ALPN token path, the same pointer) across concurrent handshakes, so the in-place append was a data race and could grow the served chain unboundedly. Return a shallow copy with the meta cert appended to a fresh backing array instead, and have cmd/derper reuse ModifyTLSConfigToAddMetaCert rather than duplicating the wrapper. Fixes #20352 Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
The job is consistently failing on main when it hits the 5 minute timeout; let's double it to get useful results. Updates #cleanup Change-Id: Iaff2f95d4944929e6832273c94d628f376e2d30e Signed-off-by: Alex Chan <alexc@tailscale.com>
…erve Allow `tailscale serve --tcp <port> unix:/path/to/socket` and `tailscale serve --tls-terminated-tcp <port> unix:/path/to/socket` to forward TCP connections to a Unix domain socket. Previously only host:port targets were supported for TCP serve mode. Updates #20161 Signed-off-by: ayanamist <ayanamist@gmail.com>
Updates #20081 Signed-off-by: Jordan Whited <jordan@tailscale.com>
Updates tailscale/corp#41997 Change-Id: I5fb3d4705766deb71abd0b79a186e99e86be0b15 Signed-off-by: Mike Jensen <mikej@tailscale.com>
At /v0/conn25-state. State includes whether the node is configured for Connectors 2025, as well as client-specific and connector-specific state, if the node is acting in those contexts. Client-specific state includes the reserved Magic IPs and Transit IPs on the client that have not been returned to their IP pools, and their associated apps, domains, real destination IPs, and active flow counts. We also report IP pool utilization: the number of magic and transit IPs in use versus each pool's capacity, split by IP family. Connector-specific state includes a peer list of clients that have registered Transit IPs with the connector, and the apps are real destination IPs the Transit IPs map to. Updates tailscale/corp#40125 Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>
* wgengine: configure DNS even when router.Set fails Reconfig configured the router first and returned on any router.Set error, before the DNS block ran. On a host where router config fails on every reconfig -- e.g. a tun MTU below 1280 that breaks IPv6, or a kernel missing netfilter features -- the OS resolver was never told about MagicDNS or the tailnet search domain, so tailnet names failed to resolve with no DNS error in the logs. Record the router error and continue instead of returning on it, still attempt dns.Set, and join the router, DNS, and VPN-reconfigure errors into the return value. DNS stays after router config (still needed: some DNS managers refuse to apply settings before the device has an address); only the error coupling is broken. Fixes a regression from 84430cd (v1.8.0). Updates #20447 Signed-off-by: Brendan Creane <bcreane@gmail.com> * wgengine/router/osrouter: gate IPv6 on per-interface support, not just global getV6Available reported IPv6 usable whenever the netfilter runner reported global IPv6 support, missing the case where the kernel has IPv6 but has not enabled it on tailscale0 specifically -- e.g. when the tun MTU is below the 1280-byte IPv6 minimum, so /proc/sys/net/ipv6/conf/tailscale0 never exists and the v6 address and route adds fail, aborting the whole Set. See #20447. AND a per-interface check into getV6Available, evaluated per call so a later Set picks up v6 if the interface gains it. All v6-gated operations funnel through getV6Available, so Set now skips v6 gracefully instead of erroring. Also remove the dead r.v6Available field that masked this with its global name. Updates #20447 Signed-off-by: Brendan Creane <bcreane@gmail.com> --------- Signed-off-by: Brendan Creane <bcreane@gmail.com>
We were accidentally hardcoding TTL 0 before. Fixes tailscale/corp#45025 Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>
Fixes tailscale/corp#45066 Signed-off-by: Jordan Whited <jordan@tailscale.com>
Updates #cleanup Signed-off-by: Jordan Whited <jordan@tailscale.com>
Updates #cleanup Signed-off-by: Jordan Whited <jordan@tailscale.com>
…os.OpenInRoot (#20505) interfaceV6UsableForTun interpolates the interface name into a /proc path. A plain filepath.Join + os.Open only cleans the path, so a tunname with ".." (or a symlinked component) could read outside /proc/sys/net/ipv6/conf. Open under that fixed directory with os.OpenInRoot, which rejects any path escaping the root (openat-based, so also TOCTOU-resistant), still using filepath.Join to build the relative name. See https://go.dev/blog/osroot. Updates #20447 Signed-off-by: Brendan Creane <bcreane@gmail.com>
…ero keys in TSMP (#20508) Updates tailscale/corp#45042 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
Enforce that TSMP messages are only accepted for transmission over the wireguard connection from within the client. Updates tailscale/corp#45059 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
…vice (#20382) * tstest/integration: run a test against a real Windows tailscaled service Updates #20381 Signed-off-by: Yaruk Asghar <yaruk@tailscale.com> * tstest/integration: serialize Windows service tests and clean up state Updates #20381 Signed-off-by: Yaruk Asghar <yaruk@tailscale.com> * tstest/integration: address review feedback on Windows service tests Updates #20381 Signed-off-by: Yaruk Asghar <yaruk@tailscale.com> * tstest/integration: use background context for service teardown Updates #20381 Signed-off-by: Yaruk Asghar <yaruk@tailscale.com> * tstest/integration: run Windows service test via the normal windows CI run Updates #20381 Signed-off-by: Yaruk Asghar <yaruk@tailscale.com> * tstest/integration: address review feedback on Windows service tests Updates #20381 Signed-off-by: Yaruk Asghar <yaruk@tailscale.com> --------- Signed-off-by: Yaruk Asghar <yaruk@tailscale.com>
Add a new modular syslog feature providing a tailscaled --syslog flag that sends the daemon's logs to the system syslog daemon instead of stderr, which is useful when running as a daemon without a service manager that captures stderr (e.g. OpenWrt's procd). The feature package registers two new hooks: one to register its flag before flag parsing, and one that tailscaled calls early in main to redirect the standard library's default logger. Because logpolicy later points the default logger at logtail, whose local console copy writes to stderr, logpolicy now also consults the hook and sends its console copy to the same sink (with timestamps disabled, as syslog records its own). The feature is linked by default only on Linux, FreeBSD, and OpenBSD, and can be removed with the ts_omit_syslog build tag. If connecting to the syslog daemon fails at startup, tailscaled logs a warning and continues logging to stderr. Fixes #16270 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I8f3a92d4c1e6b70a5d29e4f61b3c874250a9de13
…20304) * net/tsaddr: unmap IPv4-mapped IPv6 addrs in IsTailscaleIP IsTailscaleIP branched on ip.Is4() before checking the CGNAT range, so an IPv4-mapped IPv6 address (e.g. ::ffff:100.64.0.1) took the IPv6 path and was tested only against the ULA range, wrongly returning false for a Tailscale CGNAT address. Unmap at the top so both forms are classified identically; Unmap is cheap and IsTailscaleIPv4 stays IPv4-only for callers that need it. Signed-off-by: Brendan Creane <bcreane@gmail.com> * wgengine/router/osrouter: remove orphaned tailnet addrs on cleanup The orphan-address sweep added in #20199 ran only inside Router.Set, so the teardown path (tailscaled --cleanup, and the unconditional cleanup at daemon start) never removed stale Tailscale addresses a previous instance left on a persistent tailscale0 -- it only flushed iptables/nftables. Wire address removal into cleanUp: with no desired config, every Tailscale-range address on the interface is an orphan, so enumerate and delete them all (IPv4 and IPv6, best-effort) in removeOrphanedAddrsForCleanup. tailscaleInterfaceAddrs now yields the interface's addresses as an iter.Seq[netip.Prefix], and the filters compose lazily over it: tailscaleAddrs (every Tailscale-range address; used by cleanup), deletableAddrs (isDeletableAddr: Tailscale-range and deletable now, i.e. excluding v6 when v6 is unavailable; used by the live Set sweep), and orphanedAddrs (drops the desired addresses). The Set sweep ranges the composed iterator directly, so no throwaway slices are built. delAddress is made idempotent: it attempts both the loopback-rule teardown and the address delete and joins their errors, so a missing firewall rule can't leak the address, and it no longer no-ops on v6 (cleanup relies on that to remove v6 orphans even when this process never brought IPv6 up). The Set-time sweep is otherwise unchanged; re-running it on network changes (netmon) for late orphans remains a follow-up (tailscale/corp#43882). Updates #19974 Fixes tailscale/corp#44173 Signed-off-by: Brendan Creane <bcreane@gmail.com> --------- Signed-off-by: Brendan Creane <bcreane@gmail.com>
…eers (#20513) This change ensures `packetFilterPermitsUnlockedNodes` also considers SrcCaps-based grants when checking for unsigned peer access. Fixes tailscale/corp#45116 Change-Id: I0ac938367888f67ed6f355fc19959cc8c31722a2 Signed-off-by: Mike Jensen <mikej@tailscale.com>
…DoH (#20463) DoHEndpointFromIP mapped the entire 2606:1a40::/48 range to a dns.controld.com/<id> DoH URL, but the ID-encoded addresses in that range are legacy plaintext-DNS endpoints that refuse :443. They now fall through as ordinary port-53 resolvers; the free anycast freedns.controld.com/pN addresses still upgrade via exact match. Fixes #20433 Signed-off-by: Brendan Creane <bcreane@gmail.com>
Simplifies cmd/containerboot env var parsing. Most of the private helpers did not earn their abstraction: defaultEnv(name, "") is just os.Getenv(name), and the rest collapse into cmp.Or and the existing def.Bool. defaultEnv, defaultEnvs and defaultBool are gone. Adds def.LookupEnv, the env companion to def.Bool, for the one case that needs it: TS_KUBE_SECRET, where an explicit "" disables Kubernetes secret storage and must stay distinct from unset (cmp.Or cannot express that). Updates #20018 Signed-off-by: Nick Rossi <nrossi0530@gmail.com>
Promote the toolchain from Go 1.26.6 to Go 1.27.0, matching what go.toolchain.next.rev has been testing. Besides the toolchain files themselves (updated by pull-toolchain.sh), this bumps the go.mod go directive, the Dockerfile golang base image, and the README, and regenerates the depaware.txt files and the gzip assets in tempfork/spf13/cobra and util/eventbus, whose bytes change with Go 1.27's rewritten compress/flate. Also bump golangci-lint to v2.13.1, the first release line built with Go 1.27; the prebuilt v2.10.1 binary refuses to target a Go version newer than the one it was built with. Also bump golang.org/x/net to v0.58.0 (plus the sibling x/ module upgrades it requires) to pick up upstream commit 8d10596d2624 (http2: avoid deadlocks in wrapped ClientConn state callback), which we hit during Go 1.27 rc testing. Also add docs/go-bump-checklist.md for next time. Updates #20220 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: Ia3e4c9effafbc91227eed39efb52f1fba1b8d89c
The messages needs to be received so that a node not participating in caching can talk to a node that is participating in caching but is unable to share its key over control. Fixes #21008 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
If web proxy auto discovery is disabled system wide, net/tshttpproxy now respects this configuration and avoids connection to the proxy system service. Updates #16813 Updates tailscale/corp#29168 Fixes tailscale/corp#38489 Signed-off-by: James Tucker <james@tailscale.com>
openresolv exits 2 when no config snippets are registered; treating that as a failure aborted the entire DNS reconfiguration. Filtering out our own snippet could also leave "resolvconf -l" with no arguments, which lists every snippet including ours and would make quad-100 its own upstream. Fixes #20825 Signed-off-by: Brendan Creane <bcreane@gmail.com>
The SOCKS5 server checked the client-supplied username and password against the configured credentials with plain string equality, which returns on the first differing byte. In tsnet the password is a random 128-bit value that gates every dial out through the node, and the listener is on 127.0.0.1, so a local process can time the auth reject to recover it a byte at a time with unlimited attempts and no lockout. The LocalAPI sharing the same loopback listener already compares its credential with subtle.ConstantTimeCompare; do the same here for both fields, evaluating both so the username result does not gate whether the password is examined. Updates #20998 Signed-off-by: basavaraj-sm05 <basavaraj@digiscrypt.com>
Signed-off-by: Winter M <winter@antithesis.com>
Dialer.Close unconditionally called PeerAPITransport, which panics when the binary is built with the ts_omit_peerapiclient build tag, so any such binary crashed on shutdown. Skip the idle connection cleanup in that case; there is no peerapi transport to clean up. Updates #12614 Change-Id: I6a8fd1860f8b74407fbb12c9a46d5fb07711e142 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Previously Server.HTTPClient returned a client whose transport set only DialContext, losing http.DefaultTransport's defaults such as ForceAttemptHTTP2, MaxIdleConns, IdleConnTimeout, TLSHandshakeTimeout, and ExpectContinueTimeout. Now it clones http.DefaultTransport and overrides DialContext to dial over the tailnet, so it picks up those settings and any future defaults. Proxy is explicitly nil: an HTTP proxy from the environment would be dialed through the tailnet, where it's unlikely to be reachable. The new test compares the transport field by field against a clone of http.DefaultTransport and fails on any unknown future field, forcing a decision about how HTTPClient should handle it. Updates tailscale/corp#47393 (as motivation) Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I1e800982ee11d386699dd4f588c1fd2ce392f229
The dialer returned by makeHangDialer runs on netstack-owned goroutines that can outlive the test, so calling tb.Logf from it raced with the test completing. Use tstest.WhileTestRunningLogger, which stops logging once the test is done, as makeNetstack already does. Fixes #21052 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: Ibbf4288eff48f3ae0bb5812204a1cdfd567322a3
This change adds an entry point for oss-fuzz `fuzz/oss-fuzz.sh`, allowing us to wire in our current and future fuzzing into oss-fuzz without needing to update the google/oss-fuzz repo. Existing fuzzing was also reviewed with the following changes: * disco/disco_fuzzer.go renamed to disco/fuzz_test.go so that it can have a _test.go suffix and match the modern go fuzzing design. * net/stun/stun_fuzzer.go renamed to net/stun/fuzz_test.go similar to the above * Disco and stun recieved seeds for their fuzzing starts * All existing fuzzing was given a local round of testing, which resulted in a round trip fix for disco not handling a full zero node key. * Running and building fuzzing was removed from CI (build only). The fuzz seeds are validated in normal go testing, but the fuzzing itself will only happen if run manually or on oss-fuzz. Updates tailscale/corp#46608 Change-Id: I47cb70169aefb02ac5a56220f26a6ec07fa135ee Signed-off-by: Mike Jensen <mikej@tailscale.com>
Use net.JoinHostPort when expanding proxy targets so IPv6 loopback addresses retain the required brackets. Accept ::1 as an HTTP and TCP destination in both current and legacy serve implementations. Fixes #8702 Signed-off-by: James Tucker <jftucker@gmail.com>
This change expands on #20862 to allow our oss-fuzz.sh script to be flexible for go1.27 (and future go versions without needing oss-fuzz changes). The [PR on oss-fuzz](google/oss-fuzz#15996) has been updated to no longer pin the go version. Updates tailscale/corp#46608 Change-Id: If5c7fe9e4171d9f31b4a767e9ec372d5e0edbe0d Signed-off-by: Mike Jensen <mikej@tailscale.com>
CheckIPForwarding unconditionally returned a "not currently officially supported" warning on FreeBSD without ever reading the forwarding sysctls. Subnet routers on FreeBSD therefore got a spurious "IP forwarding is disabled" health warning and admin console banner even with net.inet.ip.forwarding=1 and net.inet6.ip6.forwarding=1 set. Read the sysctls instead, and only warn for the protocols actually required by the advertised routes. FreeBSD has no per-interface forwarding knob, so only the global sysctls are checked. dragonfly, netbsd and openbsd keep the previous unsupported warning. Updates #5573 Signed-off-by: Martin Minkus <martin.minkus@sonic.com>
…self) The FreeBSD subnet-router NAT rule translated with "-> (self)": nat on ! tailscale0 inet from 100.64.0.0/10 to any -> (self) In pf, "(self)" is a round-robin pool of every address on the machine, including tailscale0's own address and loopback, and pf deals each new state the next address in the pool. Only flows that happen to draw the egress interface's address work; a flow translated to any other address gets replies the far end cannot route, and hangs at SYN. With N usable addresses on the box, roughly (N-1)/N of connections through the subnet router silently fail. Observed in a natlab vmtest against a FreeBSD 15.0 subnet router with four addresses (WAN, LAN, QEMU debug NIC, tailscale0): exactly half of 8 HTTP requests hung, alternating, and the pf state table showed the failed flows translated to the debug NIC's address and to tailscale0's own address: 10.0.0.102:51100 (100.64.0.1:35132) -> 10.0.0.103:8080 ESTABLISHED 10.0.2.15:56553 (100.64.0.1:35148) -> 10.0.0.103:8080 SYN_SENT:CLOSED 100.64.0.2:52655 (100.64.0.1:54106) -> 10.0.0.103:8080 SYN_SENT:CLOSED On a production FreeBSD firewall running this branch, the equivalent IPv6 rule shows 55 state creations totalling 117 packets (about two packets per state): SYNs whose replies never came back. Emit one rule per up, non-loopback, non-Tailscale interface instead, translating to that interface's own address, per address family only where the interface holds a usable address of that family: nat on vtnet0 inet from 100.64.0.0/10 to any -> (vtnet0) nat on vtnet1 inet from 100.64.0.0/10 to any -> (vtnet1) which is also the rule form FreeBSD firewall operators write by hand. With this, the same 8-request test passes 8/8, and the LAN interface's rule shows 8 states with healthy packet counts (56 packets total). The interface set is sampled when SNAT is enabled; interfaces added later are not covered until SNAT is toggled or tailscaled restarts. Updates #5573 Change-Id: Ife3367124737ce5c8785ca7f920eafca593ec705 Signed-off-by: Martin Minkus <martin.minkus@sonic.com>
…refs ensurePFAnchorRef reconstructs the main ruleset from "pfctl -sn" and "pfctl -sr" output and reloads it with "pfctl -f -". That output names any table a rule references but never prints its contents, so the reconstructed ruleset re-declares every table as empty. Reloading it silently drops the addresses of any table the operator populates out-of-band -- a "persist file" table, "pfctl -T add", pfctl's own automatic tables for interface groups -- and every rule referencing that table then matches nothing. That is a quiet, security-relevant failure: a ruleset whose "pass ... from <trusted>" rules still exist but match no addresses looks fine in "pfctl -sr". There is no way to insert an anchor reference into a running ruleset without a reload, so detect the case and refuse, pointing the operator at the durable fix (putting the anchor references in /etc/pf.conf, where they survive reboots and pf reloads anyway). Boxes that already have the anchor references configured are unaffected: ensurePFAnchorRef returns early before reaching this check. Updates #5573 Change-Id: I6efa9a63e1322af2ec8fd986a774ed76c5d5766e Signed-off-by: Martin Minkus <martin.minkus@sonic.com>
removePFAnchorRef ran at shutdown (and from the startup cleanup hook) and
unconditionally rewrote the main PF ruleset to strip the "tailscale"
anchor references. That is wrong twice over for an operator who
configured those references statically in /etc/pf.conf -- the durable
setup the ensurePFAnchorRef error message recommends:
- it drifts the running ruleset away from /etc/pf.conf on every
tailscaled shutdown, and
- the rewrite reconstructs the ruleset from "pfctl -s" output, which
names PF tables but never their contents, so any table the operator
populates out-of-band is silently emptied (same failure mode
ensurePFAnchorRef now refuses).
Track whether this process inserted the references and only remove what
we added, and even then leave them alone if the ruleset now references
tables. Skipped removal is harmless: callers flush the anchor's contents
first, and a reference to an empty anchor has no effect on traffic. The
flag is process-local by design, so the cross-process startup cleanup
hook never removes references it cannot prove are tailscaled's.
The only-remove-what-we-added semantics were first identified and
implemented by Ross Williams (@overhacked) on a fork of this branch;
this is an independent implementation of the same idea alongside the
table guard.
Updates #5573
Change-Id: Idf579a8b4190c37211782feac4e5bfd057c3ace0
Signed-off-by: Martin Minkus <martin.minkus@sonic.com>
Moving FreeBSD subnet routing from netstack to the kernel changes the
behavior of every existing FreeBSD subnet router, and the kernel path is
not yet ready to be the default:
- The pf NAT rule we install never matches. On a production FreeBSD
15.0 subnet router, "pfctl -vsn -a tailscale" reports 97071
evaluations with 0 packets and 0 translations, and "pfctl -s info"
reports translate: 0. So --snat-subnet-routes=true, the default,
silently performs no source NAT at all.
- Inserting the pf anchor at runtime requires reloading the main
ruleset, which cannot preserve the contents of any table that
ruleset references. See the comment in osrouter.loadPFMainRuleset.
Netstack does its own SNAT in userspace, touches no system state, and is
what FreeBSD has always used, so keep it as the default. The kernel path
can be opted into with TS_DEBUG_NETSTACK_SUBNETS=false; only that path
can serve --snat-subnet-routes=false, which netstack cannot do because
it must rewrite the source address.
With this, TestSubnetRouterFreeBSD passes.
Updates #5573
Signed-off-by: Martin Minkus <martin.minkus@sonic.com>
The existing TestSubnetRouterFreeBSD makes a single HTTP request, which cannot catch a NAT rule whose translation address is wrong on average but right occasionally: with a PF "-> (self)" rule, pf round-robins new states across every address on the machine, so one request has decent odds of drawing the working address while most flows hang at SYN. That made the single-flow test an unreproducible coin flip rather than a regression gate. Open several fresh flows and require that all of them complete and that the backend sees exactly one source address. PF rule counters and the state table are dumped along the way, so a failure shows which address each flow was translated to. Fails 4/8 (alternating) against a "-> (self)" NAT rule, with the state table showing the dead flows translated to the QEMU debug NIC's address and to tailscale0's own address. Passes 8/8 with per-egress-interface rules, and under netstack subnet routing. Updates #5573 Change-Id: I1739ceefbab7764f1db8d07424832947b1d962a3 Signed-off-by: Martin Minkus <martin.minkus@sonic.com>
From Go 1.27.0 to Go 1.27.0 + latest upstream release branches, plus a cherry-pick of an x/net http2 hpack memory optimization that didn't make Go 1.27 (https://go.dev/cl/807260) Updates #29053 Change-Id: I5c694d8c4aebf4854773ea2856177aaebb2c39a4 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Use whatever traffic steering's notion of the best connector for the client is, rather than picking arbitrarily. Fixes tailscale/corp#46766 Signed-off-by: Fran Bull <fran@tailscale.com>
When receiving disco traffic from a node, mark that node as having been seen. Should that disco key not be the active use disco key, switch to that one as being the active key. Additionally, clear states on the magicsock connection and prepare for sending a new WG handshake whenever user data is transmitted. Sets up for: - Routing TSMP keys directly into magicsock - Switching the active connection reset mechanism to the optimistic handshake - Cleaning up paths into controlClient Updates #20494 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
When the wasmbuild is run from external workflows, it can't derive the version stamps from its build context. Allow setting the ProdLDFlags version.longStamp and version.shortStamp from the VERSION_LONG and VERSION_SHORT environment variables when present. This way, if the wasmbuild caller already knows them (e.g. from mkversion), it can pass them in. This avoids "x.y.z-ERR-BuildInfo" showing up in the admin console's machine version column. Updates #19707 Signed-off-by: Gesa Stupperich <gesa@tailscale.com>
Prior to this change there were two problems with our fuzzing for oss-fuzz: 1. There was an issue if the fuzzing spanned two files (mingled with the testing). 2. The fuzzing needs to be part of the implementation package (no _test packages). This change fixes that by moving all package fuzzing into a common `fuzz_test.go` within the package. Updates tailscale/corp#46608 Change-Id: I0b95edcd0df946f723eea32f575c679214c0b202 Signed-off-by: Mike Jensen <mikej@tailscale.com>
The golang:N-alpine Docker image lags behind Go minor releases by a day or two. When we bump go.mod to a new minor version before the image catches up, the required "Build Docker image" CI check fails with "go.mod requires go >= 1.27.1 (running go 1.27.0; GOTOOLCHAIN=local)" and blocks the toolchain bump from merging. Instead, base the build stage on plain alpine and download the Tailscale Go toolchain release for the revision in go.toolchain.rev, matching how everything else in this repo is built. Fixes #21072 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I1ccb77fa3c7a49532ea87dbdbf9e3340880ec94e
Updates #bump Change-Id: I5ad390397062bf9887962c34a8f3a047ea9586e9 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
MikroTik routers only support permanent UPnP leases. Previously, a mapping attempt could proceed as follows: 1. Add a temporary mapping. 2. Retry with a permanent mapping after error 725. 3. Successfully create the permanent mapping. 4. Fail to query the external IP. 5. Forget the mapping and retry with another random port. Each retry left another permanent NAT rule behind. To prevent this, query and validate the external IP before creating the mapping. When service selection has already queried the address, reuse that result. This leaves no fallible network request after AddPortMapping succeeds. I tested this on my own MikroTik router running RouterOS 7.23.2. A successful mapping queried the external IP before creating the permanent rule, and a forced external-IP failure created no rule. Updates #10602 RELNOTE: Prevent UPnP rule accumulation on MikroTik routers. Change-Id: Id925ed9cc3a3da6ecb06fc892f2a934addfac37b Signed-off-by: Jake Bailey <jacob.b.bailey@gmail.com>
…uilds (#21082) go-118-fuzz-build (fc5dc53b) overlays every sibling _test.go in the fuzzer's directory onto a non-test path (<base>_libFuzzer.go). Sibling test files declaring an external test package (package foo_test) then collide with the fuzzer's package, failing the build with "found packages foo and foo_test". One possible fix would be to stop using external _test package for our tests, but this change attempts to address this issue without changing our test packaging structure. This change wraps each compile_native_go_fuzzer_v2 call in build_fuzzer, which hides the files in `go list .XTestGoFiles` for the build. Internal test files stay visible since the fuzz target may use their helpers. Updates tailscale/corp#46608 Change-Id: Ic6805854f76c597a5edff60674b5ea05b2d18ea9 Signed-off-by: Mike Jensen <mikej@tailscale.com>
Add a workflow that checks out tailscale/tailcat alongside this repo and runs its tests in a go.work workspace where tailscale.com resolves to the tailscale.com repo at head instead of tailcat's pinned version. This gives us an early warning when a change here breaks tailcat's API or behavior expectations. Such a failure might be fine if the change is intentional and coordinated with a tailcat fix, but the goal is to catch accidents. Updates tailscale/corp#24454 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I0566437ee86bd0403c708b2f44e7ef169abf2570
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.