Browse Source

ipn/localapi: dead code eliminate unreachable/useless LocalAPI handlers when disabled

Saves ~94 KB from the min build.

Updates #12614

Change-Id: I3b0b8a47f80b9fd3b1038c2834b60afa55bf02c2
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 4 months ago
parent
commit
5c1e26b42f
3 changed files with 66 additions and 53 deletions
  1. 3 0
      client/local/local.go
  2. 4 1
      ipn/ipnlocal/local.go
  3. 59 52
      ipn/localapi/localapi.go

+ 3 - 0
client/local/local.go

@@ -381,6 +381,9 @@ func (lc *Client) UserMetrics(ctx context.Context) ([]byte, error) {
 //
 // IncrementCounter does not support gauge metrics or negative delta values.
 func (lc *Client) IncrementCounter(ctx context.Context, name string, delta int) error {
+	if !buildfeatures.HasClientMetrics {
+		return nil
+	}
 	type metricUpdate struct {
 		Name  string `json:"name"`
 		Type  string `json:"type"`

+ 4 - 1
ipn/ipnlocal/local.go

@@ -4621,7 +4621,7 @@ func (b *LocalBackend) setPrefsLockedOnEntry(newp *ipn.Prefs, unlock unlockOnce)
 
 	b.updateFilterLocked(newp.View())
 
-	if oldp.ShouldSSHBeRunning() && !newp.ShouldSSHBeRunning() {
+	if buildfeatures.HasSSH && oldp.ShouldSSHBeRunning() && !newp.ShouldSSHBeRunning() {
 		if b.sshServer != nil {
 			b.goTracker.Go(b.sshServer.Shutdown)
 			b.sshServer = nil
@@ -5917,6 +5917,9 @@ func (b *LocalBackend) setWebClientAtomicBoolLocked(nm *netmap.NetworkMap) {
 //
 // b.mu must be held.
 func (b *LocalBackend) setExposeRemoteWebClientAtomicBoolLocked(prefs ipn.PrefsView) {
+	if !buildfeatures.HasWebClient {
+		return
+	}
 	shouldExpose := prefs.Valid() && prefs.RunWebClient()
 	b.exposeRemoteWebClientAtomicBool.Store(shouldExpose)
 }

+ 59 - 52
ipn/localapi/localapi.go

@@ -71,36 +71,20 @@ var handler = map[string]LocalAPIHandler{
 
 	// The other /localapi/v0/NAME handlers are exact matches and contain only NAME
 	// without a trailing slash:
-	"alpha-set-device-attrs":       (*Handler).serveSetDeviceAttrs, // see tailscale/corp#24690
-	"check-prefs":                  (*Handler).serveCheckPrefs,
-	"check-reverse-path-filtering": (*Handler).serveCheckReversePathFiltering,
-	"check-udp-gro-forwarding":     (*Handler).serveCheckUDPGROForwarding,
-	"derpmap":                      (*Handler).serveDERPMap,
-	"dial":                         (*Handler).serveDial,
-	"disconnect-control":           (*Handler).disconnectControl,
-	"goroutines":                   (*Handler).serveGoroutines,
-	"handle-push-message":          (*Handler).serveHandlePushMessage,
-	"id-token":                     (*Handler).serveIDToken,
-	"login-interactive":            (*Handler).serveLoginInteractive,
-	"logout":                       (*Handler).serveLogout,
-	"logtap":                       (*Handler).serveLogTap,
-	"metrics":                      (*Handler).serveMetrics,
-	"ping":                         (*Handler).servePing,
-	"prefs":                        (*Handler).servePrefs,
-	"query-feature":                (*Handler).serveQueryFeature,
-	"reload-config":                (*Handler).reloadConfig,
-	"reset-auth":                   (*Handler).serveResetAuth,
-	"set-expiry-sooner":            (*Handler).serveSetExpirySooner,
-	"set-gui-visible":              (*Handler).serveSetGUIVisible,
-	"set-push-device-token":        (*Handler).serveSetPushDeviceToken,
-	"set-udp-gro-forwarding":       (*Handler).serveSetUDPGROForwarding,
-	"shutdown":                     (*Handler).serveShutdown,
-	"start":                        (*Handler).serveStart,
-	"status":                       (*Handler).serveStatus,
-	"update/check":                 (*Handler).serveUpdateCheck,
-	"upload-client-metrics":        (*Handler).serveUploadClientMetrics,
-	"watch-ipn-bus":                (*Handler).serveWatchIPNBus,
-	"whois":                        (*Handler).serveWhoIs,
+	"check-prefs":       (*Handler).serveCheckPrefs,
+	"derpmap":           (*Handler).serveDERPMap,
+	"goroutines":        (*Handler).serveGoroutines,
+	"login-interactive": (*Handler).serveLoginInteractive,
+	"logout":            (*Handler).serveLogout,
+	"ping":              (*Handler).servePing,
+	"prefs":             (*Handler).servePrefs,
+	"reload-config":     (*Handler).reloadConfig,
+	"reset-auth":        (*Handler).serveResetAuth,
+	"set-expiry-sooner": (*Handler).serveSetExpirySooner,
+	"shutdown":          (*Handler).serveShutdown,
+	"start":             (*Handler).serveStart,
+	"status":            (*Handler).serveStatus,
+	"whois":             (*Handler).serveWhoIs,
 }
 
 func init() {
@@ -109,6 +93,17 @@ func init() {
 	}
 	if buildfeatures.HasAdvertiseRoutes {
 		Register("check-ip-forwarding", (*Handler).serveCheckIPForwarding)
+		Register("check-udp-gro-forwarding", (*Handler).serveCheckUDPGROForwarding)
+		Register("set-udp-gro-forwarding", (*Handler).serveSetUDPGROForwarding)
+	}
+	if buildfeatures.HasUseExitNode && runtime.GOOS == "linux" {
+		Register("check-reverse-path-filtering", (*Handler).serveCheckReversePathFiltering)
+	}
+	if buildfeatures.HasClientMetrics {
+		Register("upload-client-metrics", (*Handler).serveUploadClientMetrics)
+	}
+	if buildfeatures.HasClientUpdate {
+		Register("update/check", (*Handler).serveUpdateCheck)
 	}
 	if buildfeatures.HasUseExitNode {
 		Register("suggest-exit-node", (*Handler).serveSuggestExitNode)
@@ -121,6 +116,9 @@ func init() {
 		Register("bugreport", (*Handler).serveBugReport)
 		Register("pprof", (*Handler).servePprof)
 	}
+	if buildfeatures.HasDebug || buildfeatures.HasServe {
+		Register("watch-ipn-bus", (*Handler).serveWatchIPNBus)
+	}
 	if buildfeatures.HasDNS {
 		Register("dns-osconfig", (*Handler).serveDNSOSConfig)
 		Register("dns-query", (*Handler).serveDNSQuery)
@@ -128,6 +126,36 @@ func init() {
 	if buildfeatures.HasUserMetrics {
 		Register("usermetrics", (*Handler).serveUserMetrics)
 	}
+	if buildfeatures.HasServe {
+		Register("query-feature", (*Handler).serveQueryFeature)
+	}
+	if buildfeatures.HasOutboundProxy || buildfeatures.HasSSH {
+		Register("dial", (*Handler).serveDial)
+	}
+	if buildfeatures.HasClientMetrics || buildfeatures.HasDebug {
+		Register("metrics", (*Handler).serveMetrics)
+	}
+	if buildfeatures.HasDebug || buildfeatures.HasAdvertiseRoutes {
+		Register("disconnect-control", (*Handler).disconnectControl)
+	}
+	// Alpha/experimental/debug features. These should be moved to
+	// their own features if/when they graduate.
+	if buildfeatures.HasDebug {
+		Register("id-token", (*Handler).serveIDToken)
+		Register("alpha-set-device-attrs", (*Handler).serveSetDeviceAttrs) // see tailscale/corp#24690
+		Register("handle-push-message", (*Handler).serveHandlePushMessage)
+		Register("set-push-device-token", (*Handler).serveSetPushDeviceToken)
+	}
+	if buildfeatures.HasDebug || runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
+		Register("set-gui-visible", (*Handler).serveSetGUIVisible)
+	}
+	if buildfeatures.HasLogTail {
+		// TODO(bradfitz): separate out logtail tap functionality from upload
+		// functionality to make this possible? But seems unlikely people would
+		// want just this. They could "tail -f" or "journalctl -f" their logs
+		// themselves.
+		Register("logtap", (*Handler).serveLogTap)
+	}
 }
 
 // Register registers a new LocalAPI handler for the given name.
@@ -580,15 +608,6 @@ func (h *Handler) serveGoroutines(w http.ResponseWriter, r *http.Request) {
 func (h *Handler) serveLogTap(w http.ResponseWriter, r *http.Request) {
 	ctx := r.Context()
 
-	if !buildfeatures.HasLogTail {
-		// TODO(bradfitz): separate out logtail tap functionality from upload
-		// functionality to make this possible? But seems unlikely people would
-		// want just this. They could "tail -f" or "journalctl -f" their logs
-		// themselves.
-		http.Error(w, "logtap not supported in this build", http.StatusNotImplemented)
-		return
-	}
-
 	// Require write access (~root) as the logs could contain something
 	// sensitive.
 	if !h.PermitWrite {
@@ -662,7 +681,7 @@ func (h *Handler) servePprof(w http.ResponseWriter, r *http.Request) {
 
 // disconnectControl is the handler for local API /disconnect-control endpoint that shuts down control client, so that
 // node no longer communicates with control. Doing this makes control consider this node inactive. This can be used
-// before shutting down a replica of HA subnet  router or app connector deployments to ensure that control tells the
+// before shutting down a replica of HA subnet router or app connector deployments to ensure that control tells the
 // peers to switch over to another replica whilst still maintaining th existing peer connections.
 func (h *Handler) disconnectControl(w http.ResponseWriter, r *http.Request) {
 	if !h.PermitWrite {
@@ -1230,11 +1249,6 @@ func (h *Handler) serveHandlePushMessage(w http.ResponseWriter, r *http.Request)
 }
 
 func (h *Handler) serveUploadClientMetrics(w http.ResponseWriter, r *http.Request) {
-	if !buildfeatures.HasClientMetrics {
-		w.Header().Set("Content-Type", "application/json")
-		json.NewEncoder(w).Encode(struct{}{})
-		return
-	}
 	if r.Method != httpm.POST {
 		http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
 		return
@@ -1498,13 +1512,6 @@ func (h *Handler) serveUpdateCheck(w http.ResponseWriter, r *http.Request) {
 		http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
 		return
 	}
-
-	if !feature.CanAutoUpdate() {
-		// if we don't support auto-update, just say that we're up to date
-		json.NewEncoder(w).Encode(tailcfg.ClientVersion{RunningLatest: true})
-		return
-	}
-
 	cv := h.b.StatusWithoutPeers().ClientVersion
 	// ipnstate.Status documentation notes that ClientVersion may be nil on some
 	// platforms where this information is unavailable. In that case, return a