From 4c3cf8bb110e3d747c7c84b23d88b5d11d204b3b Mon Sep 17 00:00:00 2001 From: Alex Valiushko Date: Tue, 6 Jan 2026 21:58:52 -0800 Subject: [PATCH] wgengine/magicsock: extract IMDS utilities into a standalone package (#18334) Moves magicksock.cloudInfo into util/cloudinfo with minimal changes. Updates #17796 Change-Id: I83f32473b9180074d5cdbf00fa31e5b3f579f189 Signed-off-by: Alex Valiushko --- cmd/k8s-operator/depaware.txt | 1 + cmd/tailscaled/depaware-min.txt | 1 + cmd/tailscaled/depaware-minbox.txt | 1 + cmd/tailscaled/depaware.txt | 1 + cmd/tsidp/depaware.txt | 1 + tsnet/depaware.txt | 1 + .../magicsock => util/cloudinfo}/cloudinfo.go | 19 +++++++++----- util/cloudinfo/cloudinfo_nocloud.go | 26 +++++++++++++++++++ .../cloudinfo}/cloudinfo_test.go | 6 ++--- wgengine/magicsock/cloudinfo_nocloud.go | 23 ---------------- wgengine/magicsock/magicsock.go | 5 ++-- 11 files changed, 50 insertions(+), 35 deletions(-) rename {wgengine/magicsock => util/cloudinfo}/cloudinfo.go (89%) create mode 100644 util/cloudinfo/cloudinfo_nocloud.go rename {wgengine/magicsock => util/cloudinfo}/cloudinfo_test.go (97%) delete mode 100644 wgengine/magicsock/cloudinfo_nocloud.go diff --git a/cmd/k8s-operator/depaware.txt b/cmd/k8s-operator/depaware.txt index 959a8ca72..ec842651a 100644 --- a/cmd/k8s-operator/depaware.txt +++ b/cmd/k8s-operator/depaware.txt @@ -856,6 +856,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/ tailscale.com/util/cibuild from tailscale.com/health+ tailscale.com/util/clientmetric from tailscale.com/cmd/k8s-operator+ tailscale.com/util/cloudenv from tailscale.com/hostinfo+ + tailscale.com/util/cloudinfo from tailscale.com/wgengine/magicsock LW tailscale.com/util/cmpver from tailscale.com/net/dns+ tailscale.com/util/ctxkey from tailscale.com/client/tailscale/apitype+ 💣 tailscale.com/util/deephash from tailscale.com/util/syspolicy/setting diff --git a/cmd/tailscaled/depaware-min.txt b/cmd/tailscaled/depaware-min.txt index 942c96228..a2d20deda 100644 --- a/cmd/tailscaled/depaware-min.txt +++ b/cmd/tailscaled/depaware-min.txt @@ -149,6 +149,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/util/cibuild from tailscale.com/health+ tailscale.com/util/clientmetric from tailscale.com/appc+ tailscale.com/util/cloudenv from tailscale.com/hostinfo+ + tailscale.com/util/cloudinfo from tailscale.com/wgengine/magicsock tailscale.com/util/ctxkey from tailscale.com/client/tailscale/apitype+ tailscale.com/util/dnsname from tailscale.com/appc+ tailscale.com/util/eventbus from tailscale.com/control/controlclient+ diff --git a/cmd/tailscaled/depaware-minbox.txt b/cmd/tailscaled/depaware-minbox.txt index acc424103..9b761b76d 100644 --- a/cmd/tailscaled/depaware-minbox.txt +++ b/cmd/tailscaled/depaware-minbox.txt @@ -176,6 +176,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/util/cibuild from tailscale.com/health+ tailscale.com/util/clientmetric from tailscale.com/appc+ tailscale.com/util/cloudenv from tailscale.com/hostinfo+ + tailscale.com/util/cloudinfo from tailscale.com/wgengine/magicsock tailscale.com/util/cmpver from tailscale.com/clientupdate tailscale.com/util/ctxkey from tailscale.com/client/tailscale/apitype+ tailscale.com/util/dnsname from tailscale.com/appc+ diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 5a5f0a1b3..13c1f5daf 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -422,6 +422,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/util/cibuild from tailscale.com/health+ tailscale.com/util/clientmetric from tailscale.com/control/controlclient+ tailscale.com/util/cloudenv from tailscale.com/net/dns/resolver+ + tailscale.com/util/cloudinfo from tailscale.com/wgengine/magicsock tailscale.com/util/cmpver from tailscale.com/net/dns+ tailscale.com/util/ctxkey from tailscale.com/ipn/ipnlocal+ 💣 tailscale.com/util/deephash from tailscale.com/util/syspolicy/setting diff --git a/cmd/tsidp/depaware.txt b/cmd/tsidp/depaware.txt index 045986aed..aa5d63346 100644 --- a/cmd/tsidp/depaware.txt +++ b/cmd/tsidp/depaware.txt @@ -260,6 +260,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar tailscale.com/util/cibuild from tailscale.com/health+ tailscale.com/util/clientmetric from tailscale.com/appc+ tailscale.com/util/cloudenv from tailscale.com/hostinfo+ + tailscale.com/util/cloudinfo from tailscale.com/wgengine/magicsock LW tailscale.com/util/cmpver from tailscale.com/net/dns+ tailscale.com/util/ctxkey from tailscale.com/client/tailscale/apitype+ 💣 tailscale.com/util/deephash from tailscale.com/util/syspolicy/setting diff --git a/tsnet/depaware.txt b/tsnet/depaware.txt index 9ef42400f..7702de69d 100644 --- a/tsnet/depaware.txt +++ b/tsnet/depaware.txt @@ -255,6 +255,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware) tailscale.com/util/cibuild from tailscale.com/health+ tailscale.com/util/clientmetric from tailscale.com/appc+ tailscale.com/util/cloudenv from tailscale.com/hostinfo+ + tailscale.com/util/cloudinfo from tailscale.com/wgengine/magicsock LW tailscale.com/util/cmpver from tailscale.com/net/dns+ tailscale.com/util/ctxkey from tailscale.com/client/tailscale/apitype+ 💣 tailscale.com/util/deephash from tailscale.com/util/syspolicy/setting diff --git a/wgengine/magicsock/cloudinfo.go b/util/cloudinfo/cloudinfo.go similarity index 89% rename from wgengine/magicsock/cloudinfo.go rename to util/cloudinfo/cloudinfo.go index 0db56b3f6..2c4a32c03 100644 --- a/wgengine/magicsock/cloudinfo.go +++ b/util/cloudinfo/cloudinfo.go @@ -3,7 +3,8 @@ //go:build !(ios || android || js) -package magicsock +// Package cloudinfo provides cloud metadata utilities. +package cloudinfo import ( "context" @@ -24,7 +25,8 @@ import ( const maxCloudInfoWait = 2 * time.Second -type cloudInfo struct { +// CloudInfo holds state used in querying instance metadata (IMDS) endpoints. +type CloudInfo struct { client http.Client logf logger.Logf @@ -34,7 +36,8 @@ type cloudInfo struct { endpoint string } -func newCloudInfo(logf logger.Logf) *cloudInfo { +// New constructs a new [*CloudInfo] that will log to the provided logger instance. +func New(logf logger.Logf) *CloudInfo { if !buildfeatures.HasCloud { return nil } @@ -45,7 +48,7 @@ func newCloudInfo(logf logger.Logf) *cloudInfo { }).Dial, } - return &cloudInfo{ + return &CloudInfo{ client: http.Client{Transport: tr}, logf: logf, cloud: cloudenv.Get(), @@ -56,7 +59,9 @@ func newCloudInfo(logf logger.Logf) *cloudInfo { // GetPublicIPs returns any public IPs attached to the current cloud instance, // if the tailscaled process is running in a known cloud and there are any such // IPs present. -func (ci *cloudInfo) GetPublicIPs(ctx context.Context) ([]netip.Addr, error) { +// +// Currently supports only AWS. +func (ci *CloudInfo) GetPublicIPs(ctx context.Context) ([]netip.Addr, error) { if !buildfeatures.HasCloud { return nil, nil } @@ -73,7 +78,7 @@ func (ci *cloudInfo) GetPublicIPs(ctx context.Context) ([]netip.Addr, error) { // getAWSMetadata makes a request to the AWS metadata service at the given // path, authenticating with the provided IMDSv2 token. The returned metadata // is split by newline and returned as a slice. -func (ci *cloudInfo) getAWSMetadata(ctx context.Context, token, path string) ([]string, error) { +func (ci *CloudInfo) getAWSMetadata(ctx context.Context, token, path string) ([]string, error) { req, err := http.NewRequestWithContext(ctx, "GET", ci.endpoint+path, nil) if err != nil { return nil, fmt.Errorf("creating request to %q: %w", path, err) @@ -105,7 +110,7 @@ func (ci *cloudInfo) getAWSMetadata(ctx context.Context, token, path string) ([] } // getAWS returns all public IPv4 and IPv6 addresses present in the AWS instance metadata. -func (ci *cloudInfo) getAWS(ctx context.Context) ([]netip.Addr, error) { +func (ci *CloudInfo) getAWS(ctx context.Context) ([]netip.Addr, error) { ctx, cancel := context.WithTimeout(ctx, maxCloudInfoWait) defer cancel() diff --git a/util/cloudinfo/cloudinfo_nocloud.go b/util/cloudinfo/cloudinfo_nocloud.go new file mode 100644 index 000000000..6a525cd2a --- /dev/null +++ b/util/cloudinfo/cloudinfo_nocloud.go @@ -0,0 +1,26 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +//go:build ios || android || js + +package cloudinfo + +import ( + "context" + "net/netip" + + "tailscale.com/types/logger" +) + +// CloudInfo is not available in mobile and JS targets. +type CloudInfo struct{} + +// New construct a no-op CloudInfo stub. +func New(_ logger.Logf) *CloudInfo { + return &CloudInfo{} +} + +// GetPublicIPs always returns nil slice and error. +func (ci *CloudInfo) GetPublicIPs(_ context.Context) ([]netip.Addr, error) { + return nil, nil +} diff --git a/wgengine/magicsock/cloudinfo_test.go b/util/cloudinfo/cloudinfo_test.go similarity index 97% rename from wgengine/magicsock/cloudinfo_test.go rename to util/cloudinfo/cloudinfo_test.go index 15191aeef..38817f47a 100644 --- a/wgengine/magicsock/cloudinfo_test.go +++ b/util/cloudinfo/cloudinfo_test.go @@ -1,7 +1,7 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -package magicsock +package cloudinfo import ( "context" @@ -44,7 +44,7 @@ func TestCloudInfo_AWS(t *testing.T) { srv := httptest.NewServer(fake) defer srv.Close() - ci := newCloudInfo(t.Logf) + ci := New(t.Logf) ci.cloud = cloudenv.AWS ci.endpoint = srv.URL @@ -76,7 +76,7 @@ func TestCloudInfo_AWSNotPublic(t *testing.T) { srv := httptest.NewServer(returns404) defer srv.Close() - ci := newCloudInfo(t.Logf) + ci := New(t.Logf) ci.cloud = cloudenv.AWS ci.endpoint = srv.URL diff --git a/wgengine/magicsock/cloudinfo_nocloud.go b/wgengine/magicsock/cloudinfo_nocloud.go deleted file mode 100644 index b4414d318..000000000 --- a/wgengine/magicsock/cloudinfo_nocloud.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Tailscale Inc & AUTHORS -// SPDX-License-Identifier: BSD-3-Clause - -//go:build ios || android || js - -package magicsock - -import ( - "context" - "net/netip" - - "tailscale.com/types/logger" -) - -type cloudInfo struct{} - -func newCloudInfo(_ logger.Logf) *cloudInfo { - return &cloudInfo{} -} - -func (ci *cloudInfo) GetPublicIPs(_ context.Context) ([]netip.Addr, error) { - return nil, nil -} diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index b8a5f7da2..a19032fb2 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -60,6 +60,7 @@ import ( "tailscale.com/types/nettype" "tailscale.com/types/views" "tailscale.com/util/clientmetric" + "tailscale.com/util/cloudinfo" "tailscale.com/util/eventbus" "tailscale.com/util/mak" "tailscale.com/util/ringlog" @@ -213,7 +214,7 @@ type Conn struct { bind *connBind // cloudInfo is used to query cloud metadata services. - cloudInfo *cloudInfo + cloudInfo *cloudinfo.CloudInfo // ============================================================ // Fields that must be accessed via atomic load/stores. @@ -597,7 +598,7 @@ func newConn(logf logger.Logf) *Conn { peerLastDerp: make(map[key.NodePublic]int), peerMap: newPeerMap(), discoInfo: make(map[key.DiscoPublic]*discoInfo), - cloudInfo: newCloudInfo(logf), + cloudInfo: cloudinfo.New(logf), } c.discoAtomic.Set(discoPrivate) c.bind = &connBind{Conn: c, closed: true}