lanscaping: remove appconnectors, more posture

-rwxr-xr-x@ 1 bradfitz  staff  13992850 Jan 10 21:35 /Users/bradfitz/bin/tailscaled.min
-rwxr-xr-x@ 1 bradfitz  staff  14942360 Jan 10 21:35 /Users/bradfitz/bin/tailscaled.minlinux

Change-Id: I63b6a8d459e0b88d092b2c793f8b88d3c976889a
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2025-01-10 21:35:51 -08:00
parent ccd498f266
commit d086f952b9
5 changed files with 12 additions and 319 deletions

View File

@ -4,7 +4,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
L filippo.io/edwards25519/field from filippo.io/edwards25519
github.com/bits-and-blooms/bitset from github.com/gaissmai/bart
L github.com/coreos/go-iptables/iptables from tailscale.com/util/linuxfw
L github.com/digitalocean/go-smbios/smbios from tailscale.com/posture
github.com/gaissmai/bart from tailscale.com/net/ipset+
github.com/go-json-experiment/json from tailscale.com/types/opt+
github.com/go-json-experiment/json/internal from github.com/go-json-experiment/json+
@ -53,7 +52,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
💣 go4.org/mem from tailscale.com/control/controlbase+
go4.org/netipx from tailscale.com/ipn/ipnlocal+
tailscale.com from tailscale.com/version
tailscale.com/appc from tailscale.com/ipn/ipnlocal
tailscale.com/atomicfile from tailscale.com/ipn+
tailscale.com/client/tailscale/apitype from tailscale.com/ipn/ipnlocal+
tailscale.com/clientupdate from tailscale.com/ipn/ipnlocal+
@ -131,7 +129,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/omit from tailscale.com/ipn/conffile
tailscale.com/paths from tailscale.com/cmd/tailscaled+
💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal
tailscale.com/posture from tailscale.com/ipn/ipnlocal
tailscale.com/proxymap from tailscale.com/tsd
tailscale.com/safesocket from tailscale.com/cmd/tailscaled+
tailscale.com/syncs from tailscale.com/cmd/tailscaled+
@ -143,14 +140,13 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/tstime/mono from tailscale.com/net/tstun+
tailscale.com/tstime/rate from tailscale.com/derp+
tailscale.com/tsweb/varz from tailscale.com/cmd/tailscaled+
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal
tailscale.com/types/dnstype from tailscale.com/client/tailscale/apitype+
tailscale.com/types/empty from tailscale.com/ipn+
tailscale.com/types/flagtype from tailscale.com/cmd/tailscaled
tailscale.com/types/ipproto from tailscale.com/ipn+
tailscale.com/types/key from tailscale.com/cmd/tailscaled+
tailscale.com/types/lazy from tailscale.com/util/cloudenv+
tailscale.com/types/logger from tailscale.com/appc+
tailscale.com/types/logger from tailscale.com/clientupdate+
tailscale.com/types/logid from tailscale.com/cmd/tailscaled+
tailscale.com/types/netlogtype from tailscale.com/net/connstats+
tailscale.com/types/netmap from tailscale.com/control/controlclient+
@ -162,16 +158,16 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/types/result from tailscale.com/util/lineiter
tailscale.com/types/structs from tailscale.com/control/controlclient+
tailscale.com/types/tkatype from tailscale.com/control/controlclient+
tailscale.com/types/views from tailscale.com/appc+
tailscale.com/types/views from tailscale.com/control/controlclient+
tailscale.com/util/cibuild from tailscale.com/health
tailscale.com/util/clientmetric from tailscale.com/appc+
tailscale.com/util/clientmetric from tailscale.com/cmd/tailscaled+
tailscale.com/util/cloudenv from tailscale.com/hostinfo+
tailscale.com/util/cmpver from tailscale.com/clientupdate+
tailscale.com/util/ctxkey from tailscale.com/derp+
💣 tailscale.com/util/deephash from tailscale.com/ipn/ipnlocal+
L 💣 tailscale.com/util/dirwalk from tailscale.com/metrics+
tailscale.com/util/dnsname from tailscale.com/appc+
tailscale.com/util/execqueue from tailscale.com/appc+
tailscale.com/util/dnsname from tailscale.com/hostinfo+
tailscale.com/util/execqueue from tailscale.com/control/controlclient
tailscale.com/util/goroutines from tailscale.com/ipn/ipnlocal
tailscale.com/util/groupmember from tailscale.com/ipn/ipnauth
💣 tailscale.com/util/hashx from tailscale.com/util/deephash
@ -179,7 +175,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/util/httpm from tailscale.com/clientupdate/distsign+
tailscale.com/util/lineiter from tailscale.com/hostinfo+
L tailscale.com/util/linuxfw from tailscale.com/net/netns+
tailscale.com/util/mak from tailscale.com/appc+
tailscale.com/util/mak from tailscale.com/control/controlclient+
tailscale.com/util/multierr from tailscale.com/cmd/tailscaled+
tailscale.com/util/must from tailscale.com/clientupdate/distsign+
tailscale.com/util/nocasemaps from tailscale.com/types/ipproto
@ -193,7 +189,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/util/ringbuffer from tailscale.com/wgengine/magicsock
tailscale.com/util/set from tailscale.com/control/controlclient+
tailscale.com/util/singleflight from tailscale.com/control/controlclient+
tailscale.com/util/slicesx from tailscale.com/appc+
tailscale.com/util/slicesx from tailscale.com/control/controlclient+
tailscale.com/util/syspolicy from tailscale.com/control/controlclient+
tailscale.com/util/syspolicy/internal from tailscale.com/util/syspolicy+
tailscale.com/util/syspolicy/internal/loggerx from tailscale.com/util/syspolicy+
@ -309,7 +305,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
html from net/http/pprof+
io from archive/tar+
io/fs from archive/tar+
L io/ioutil from github.com/digitalocean/go-smbios/smbios+
L io/ioutil from github.com/godbus/dbus/v5+
iter from github.com/go-json-experiment/json/jsontext+
log from expvar+
log/internal from log

View File

@ -24,12 +24,10 @@ import (
"tailscale.com/envknob"
"tailscale.com/ipn"
"tailscale.com/net/sockstats"
"tailscale.com/posture"
"tailscale.com/tailcfg"
"tailscale.com/util/clientmetric"
"tailscale.com/util/goroutines"
"tailscale.com/util/set"
"tailscale.com/util/syspolicy"
"tailscale.com/version"
"tailscale.com/version/distro"
)
@ -63,12 +61,6 @@ var c2nHandlers = map[methodAndPath]c2nHandler{
req("GET /update"): handleC2NUpdateGet,
req("POST /update"): handleC2NUpdatePost,
// Device posture.
req("GET /posture/identity"): handleC2NPostureIdentityGet,
// App Connectors.
req("GET /appconnector/routes"): handleC2NAppConnectorDomainRoutesGet,
// Linux netfilter.
req("POST /netfilter-kind"): handleC2NSetNetfilterKind,
@ -220,26 +212,6 @@ func handleC2NSockStats(b *LocalBackend, w http.ResponseWriter, r *http.Request)
fmt.Fprintf(w, "debug info: %v\n", sockstats.DebugInfo())
}
// handleC2NAppConnectorDomainRoutesGet handles returning the domains
// that the app connector is responsible for, as well as the resolved
// IP addresses for each domain. If the node is not configured as
// an app connector, an empty map is returned.
func handleC2NAppConnectorDomainRoutesGet(b *LocalBackend, w http.ResponseWriter, r *http.Request) {
b.logf("c2n: GET /appconnector/routes received")
var res tailcfg.C2NAppConnectorDomainRoutesResponse
if b.appConnector == nil {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(res)
return
}
res.Domains = b.appConnector.DomainRoutes()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(res)
}
func handleC2NSetNetfilterKind(b *LocalBackend, w http.ResponseWriter, r *http.Request) {
b.logf("c2n: POST /netfilter-kind received")
@ -320,49 +292,6 @@ func handleC2NUpdatePost(b *LocalBackend, w http.ResponseWriter, r *http.Request
res.Started = true
}
func handleC2NPostureIdentityGet(b *LocalBackend, w http.ResponseWriter, r *http.Request) {
b.logf("c2n: GET /posture/identity received")
res := tailcfg.C2NPostureIdentityResponse{}
// Only collect posture identity if enabled on the client,
// this will first check syspolicy, MDM settings like Registry
// on Windows or defaults on macOS. If they are not set, it falls
// back to the cli-flag, `--posture-checking`.
choice, err := syspolicy.GetPreferenceOption(syspolicy.PostureChecking)
if err != nil {
b.logf(
"c2n: failed to read PostureChecking from syspolicy, returning default from CLI: %s; got error: %s",
b.Prefs().PostureChecking(),
err,
)
}
if choice.ShouldEnable(b.Prefs().PostureChecking()) {
res.SerialNumbers, err = posture.GetSerialNumbers(b.logf)
if err != nil {
b.logf("c2n: GetSerialNumbers returned error: %v", err)
}
// TODO(tailscale/corp#21371, 2024-07-10): once this has landed in a stable release
// and looks good in client metrics, remove this parameter and always report MAC
// addresses.
if r.FormValue("hwaddrs") == "true" {
res.IfaceHardwareAddrs, err = posture.GetHardwareAddrs()
if err != nil {
b.logf("c2n: GetHardwareAddrs returned error: %v", err)
}
}
} else {
res.PostureDisabled = true
}
b.logf("c2n: posture identity disabled=%v reported %d serials %d hwaddrs", res.PostureDisabled, len(res.SerialNumbers), len(res.IfaceHardwareAddrs))
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(res)
}
func (b *LocalBackend) newC2NUpdateResponse() tailcfg.C2NUpdateResponse {
// If NewUpdater does not return an error, we can update the installation.
//

View File

@ -38,7 +38,6 @@ import (
"go4.org/netipx"
"golang.org/x/net/dns/dnsmessage"
"tailscale.com/appc"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/clientupdate"
"tailscale.com/control/controlclient"
@ -78,7 +77,6 @@ import (
"tailscale.com/taildrop"
"tailscale.com/tsd"
"tailscale.com/tstime"
"tailscale.com/types/appctype"
"tailscale.com/types/dnstype"
"tailscale.com/types/empty"
"tailscale.com/types/key"
@ -238,10 +236,9 @@ type LocalBackend struct {
conf *conffile.Config // latest parsed config, or nil if not in declarative mode
pm *profileManager // mu guards access
filterHash deephash.Sum
httpTestClient *http.Client // for controlclient. nil by default, used by tests.
ccGen clientGen // function for producing controlclient; lazily populated
sshServer SSHServer // or nil, initialized lazily.
appConnector *appc.AppConnector // or nil, initialized when configured.
httpTestClient *http.Client // for controlclient. nil by default, used by tests.
ccGen clientGen // function for producing controlclient; lazily populated
sshServer SSHServer // or nil, initialized lazily.
// notifyCancel cancels notifications to the current SetNotifyCallback.
notifyCancel context.CancelFunc
cc controlclient.Client
@ -2107,7 +2104,6 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
hostinfo.FrontendLogID = opts.FrontendLogID
hostinfo.Userspace.Set(b.sys.IsNetstack())
hostinfo.UserspaceRouter.Set(b.sys.IsNetstackRouter())
hostinfo.AppConnector.Set(b.appConnector != nil)
b.logf.JSON(1, "Hostinfo", hostinfo)
// TODO(apenwarr): avoid the need to reinit controlclient.
@ -3782,19 +3778,6 @@ func (b *LocalBackend) SetUseExitNodeEnabled(v bool) (ipn.PrefsView, error) {
return b.editPrefsLockedOnEntry(mp, unlock)
}
// MaybeClearAppConnector clears the routes from any AppConnector if
// AdvertiseRoutes has been set in the MaskedPrefs.
func (b *LocalBackend) MaybeClearAppConnector(mp *ipn.MaskedPrefs) error {
var err error
if b.appConnector != nil && mp.AdvertiseRoutesSet {
err = b.appConnector.ClearRoutes()
if err != nil {
b.logf("appc: clear routes error: %v", err)
}
}
return err
}
func (b *LocalBackend) EditPrefs(mp *ipn.MaskedPrefs) (ipn.PrefsView, error) {
if mp.SetsInternal() {
return ipn.PrefsView{}, errors.New("can't set Internal fields")
@ -4103,76 +4086,6 @@ func (b *LocalBackend) blockEngineUpdates(block bool) {
b.mu.Unlock()
}
// reconfigAppConnectorLocked updates the app connector state based on the
// current network map and preferences.
// b.mu must be held.
func (b *LocalBackend) reconfigAppConnectorLocked(nm *netmap.NetworkMap, prefs ipn.PrefsView) {
const appConnectorCapName = "tailscale.com/app-connectors"
defer func() {
if b.hostinfo != nil {
b.hostinfo.AppConnector.Set(b.appConnector != nil)
}
}()
if !prefs.AppConnector().Advertise {
b.appConnector = nil
return
}
shouldAppCStoreRoutes := b.ControlKnobs().AppCStoreRoutes.Load()
if b.appConnector == nil || b.appConnector.ShouldStoreRoutes() != shouldAppCStoreRoutes {
var ri *appc.RouteInfo
var storeFunc func(*appc.RouteInfo) error
if shouldAppCStoreRoutes {
var err error
ri, err = b.readRouteInfoLocked()
if err != nil {
ri = &appc.RouteInfo{}
if err != ipn.ErrStateNotExist {
b.logf("Unsuccessful Read RouteInfo: ", err)
}
}
storeFunc = b.storeRouteInfo
}
b.appConnector = appc.NewAppConnector(b.logf, b, ri, storeFunc)
}
if nm == nil {
return
}
// TODO(raggi): rework the view infrastructure so the large deep clone is no
// longer required
sn := nm.SelfNode.AsStruct()
attrs, err := tailcfg.UnmarshalNodeCapJSON[appctype.AppConnectorAttr](sn.CapMap, appConnectorCapName)
if err != nil {
b.logf("[unexpected] error parsing app connector mapcap: %v", err)
return
}
// Geometric cost, assumes that the number of advertised tags is small
selfHasTag := func(attrTags []string) bool {
return nm.SelfNode.Tags().ContainsFunc(func(tag string) bool {
return slices.Contains(attrTags, tag)
})
}
var (
domains []string
routes []netip.Prefix
)
for _, attr := range attrs {
if slices.Contains(attr.Connectors, "*") || selfHasTag(attr.Connectors) {
domains = append(domains, attr.Domains...)
routes = append(routes, attr.Routes...)
}
}
slices.Sort(domains)
slices.SortFunc(routes, func(i, j netip.Prefix) int { return i.Addr().Compare(j.Addr()) })
domains = slices.Compact(domains)
routes = slices.Compact(routes)
b.appConnector.UpdateDomainsAndRoutes(domains, routes)
}
// authReconfig pushes a new configuration into wgengine, if engine
// updates are not currently blocked, based on the cached netmap and
// user prefs.
@ -4187,7 +4100,6 @@ func (b *LocalBackend) authReconfig() {
dohURL, dohURLOK := exitNodeCanProxyDNS(nm, b.peers, prefs.ExitNodeID())
dcfg := dnsConfigForNetmap(nm, b.peers, prefs, b.keyExpired, b.logf, version.OS())
// If the current node is an app connector, ensure the app connector machine is started
b.reconfigAppConnectorLocked(nm, prefs)
closing := b.shutdownCalled
b.mu.Unlock()
@ -6085,14 +5997,6 @@ func (b *LocalBackend) OfferingExitNode() bool {
return def4 && def6
}
// OfferingAppConnector reports whether b is currently offering app
// connector services.
func (b *LocalBackend) OfferingAppConnector() bool {
b.mu.Lock()
defer b.mu.Unlock()
return b.appConnector != nil
}
// allowExitNodeDNSProxyToServeName reports whether the Exit Node DNS
// proxy is allowed to serve responses for the provided DNS name.
func (b *LocalBackend) allowExitNodeDNSProxyToServeName(name string) bool {
@ -6722,103 +6626,9 @@ func (b *LocalBackend) DoSelfUpdate() {
}
}
// ObserveDNSResponse passes a DNS response from the PeerAPI DNS server to the
// App Connector to enable route discovery.
func (b *LocalBackend) ObserveDNSResponse(res []byte) {
var appConnector *appc.AppConnector
b.mu.Lock()
if b.appConnector == nil {
b.mu.Unlock()
return
}
appConnector = b.appConnector
b.mu.Unlock()
appConnector.ObserveDNSResponse(res)
}
// ErrDisallowedAutoRoute is returned by AdvertiseRoute when a route that is not allowed is requested.
var ErrDisallowedAutoRoute = errors.New("route is not allowed")
// AdvertiseRoute implements the appc.RouteAdvertiser interface. It sets a new
// route advertisement if one is not already present in the existing routes.
// If the route is disallowed, ErrDisallowedAutoRoute is returned.
func (b *LocalBackend) AdvertiseRoute(ipps ...netip.Prefix) error {
finalRoutes := b.Prefs().AdvertiseRoutes().AsSlice()
newRoutes := false
for _, ipp := range ipps {
if !allowedAutoRoute(ipp) {
continue
}
if slices.Contains(finalRoutes, ipp) {
continue
}
// If the new prefix is already contained by existing routes, skip it.
if coveredRouteRangeNoDefault(finalRoutes, ipp) {
continue
}
finalRoutes = append(finalRoutes, ipp)
newRoutes = true
}
if !newRoutes {
return nil
}
_, err := b.EditPrefs(&ipn.MaskedPrefs{
Prefs: ipn.Prefs{
AdvertiseRoutes: finalRoutes,
},
AdvertiseRoutesSet: true,
})
return err
}
// coveredRouteRangeNoDefault checks if a route is already included in a slice of
// prefixes, ignoring default routes in the range.
func coveredRouteRangeNoDefault(finalRoutes []netip.Prefix, ipp netip.Prefix) bool {
for _, r := range finalRoutes {
if r == tsaddr.AllIPv4() || r == tsaddr.AllIPv6() {
continue
}
if ipp.IsSingleIP() {
if r.Contains(ipp.Addr()) {
return true
}
} else {
if r.Contains(ipp.Addr()) && r.Contains(netipx.PrefixLastIP(ipp)) {
return true
}
}
}
return false
}
// UnadvertiseRoute implements the appc.RouteAdvertiser interface. It removes
// a route advertisement if one is present in the existing routes.
func (b *LocalBackend) UnadvertiseRoute(toRemove ...netip.Prefix) error {
currentRoutes := b.Prefs().AdvertiseRoutes().AsSlice()
finalRoutes := currentRoutes[:0]
for _, ipp := range currentRoutes {
if slices.Contains(toRemove, ipp) {
continue
}
finalRoutes = append(finalRoutes, ipp)
}
_, err := b.EditPrefs(&ipn.MaskedPrefs{
Prefs: ipn.Prefs{
AdvertiseRoutes: finalRoutes,
},
AdvertiseRoutesSet: true,
})
return err
}
// namespace a key with the profile manager's current profile key, if any
func namespaceKeyForCurrentProfile(pm *profileManager, key ipn.StateKey) ipn.StateKey {
return pm.CurrentProfile().Key + "||" + key
@ -6826,36 +6636,6 @@ func namespaceKeyForCurrentProfile(pm *profileManager, key ipn.StateKey) ipn.Sta
const routeInfoStateStoreKey ipn.StateKey = "_routeInfo"
func (b *LocalBackend) storeRouteInfo(ri *appc.RouteInfo) error {
b.mu.Lock()
defer b.mu.Unlock()
if b.pm.CurrentProfile().ID == "" {
return nil
}
key := namespaceKeyForCurrentProfile(b.pm, routeInfoStateStoreKey)
bs, err := json.Marshal(ri)
if err != nil {
return err
}
return b.pm.WriteState(key, bs)
}
func (b *LocalBackend) readRouteInfoLocked() (*appc.RouteInfo, error) {
if b.pm.CurrentProfile().ID == "" {
return &appc.RouteInfo{}, nil
}
key := namespaceKeyForCurrentProfile(b.pm, routeInfoStateStoreKey)
bs, err := b.pm.Store().ReadState(key)
ri := &appc.RouteInfo{}
if err != nil {
return nil, err
}
if err := json.Unmarshal(bs, ri); err != nil {
return nil, err
}
return ri, nil
}
// seamlessRenewalEnabled reports whether seamless key renewals are enabled
// (i.e. we saw our self node with the SeamlessKeyRenewal attr in a netmap).
// This enables beta functionality of renewing node keys without breaking

View File

@ -522,7 +522,7 @@ func (h *peerAPIHandler) replyToDNSQueries() bool {
return true
}
b := h.ps.b
if !b.OfferingExitNode() && !b.OfferingAppConnector() {
if !b.OfferingExitNode() {
// If we're not an exit node or app connector, there's
// no point to being a DNS server for somebody.
return false
@ -605,12 +605,6 @@ func (h *peerAPIHandler) handleDNSQuery(w http.ResponseWriter, r *http.Request)
}
return
}
// TODO(raggi): consider pushing the integration down into the resolver
// instead to avoid re-parsing the DNS response for improved performance in
// the future.
if h.ps.b.OfferingAppConnector() {
h.ps.b.ObserveDNSResponse(res)
}
if pretty {
// Non-standard response for interactive debugging.

View File

@ -1139,12 +1139,6 @@ func (h *Handler) servePrefs(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := h.b.MaybeClearAppConnector(mp); err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(resJSON{Error: err.Error()})
return
}
var err error
prefs, err = h.b.EditPrefs(mp)
if err != nil {