cmd/tailscale/cli: allow remote target as service destination (#17607)

This commit enables user to set service backend to remote destinations, that can be a partial
URL or a full URL. The commit also prevents user to set remote destinations on linux system
when socket mark is not working. For user on any version of mac extension they can't serve a
service either. The socket mark usability is determined by a new local api.

Fixes tailscale/corp#24783

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>
This commit is contained in:
KevinLiang10
2025-11-19 12:29:08 -05:00
committed by GitHub
parent 12c598de28
commit a0d059d74c
10 changed files with 221 additions and 44 deletions

View File

@@ -35,6 +35,7 @@ import (
"tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/ipnstate"
"tailscale.com/logtail"
"tailscale.com/net/netns"
"tailscale.com/net/netutil"
"tailscale.com/tailcfg"
"tailscale.com/tstime"
@@ -72,20 +73,21 @@ var handler = map[string]LocalAPIHandler{
// The other /localapi/v0/NAME handlers are exact matches and contain only NAME
// without a trailing slash:
"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,
"check-prefs": (*Handler).serveCheckPrefs,
"check-so-mark-in-use": (*Handler).serveCheckSOMarkInUse,
"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() {
@@ -760,6 +762,23 @@ func (h *Handler) serveCheckIPForwarding(w http.ResponseWriter, r *http.Request)
})
}
// serveCheckSOMarkInUse reports whether SO_MARK is in use on the linux while
// running without TUN. For any other OS, it reports false.
func (h *Handler) serveCheckSOMarkInUse(w http.ResponseWriter, r *http.Request) {
if !h.PermitRead {
http.Error(w, "SO_MARK check access denied", http.StatusForbidden)
return
}
usingSOMark := netns.UseSocketMark()
usingUserspaceNetworking := h.b.Sys().IsNetstack()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(struct {
UseSOMark bool
}{
UseSOMark: usingSOMark || usingUserspaceNetworking,
})
}
func (h *Handler) serveCheckReversePathFiltering(w http.ResponseWriter, r *http.Request) {
if !h.PermitRead {
http.Error(w, "reverse path filtering check access denied", http.StatusForbidden)