diff --git a/cmd/tailscale/cli/serve_legacy.go b/cmd/tailscale/cli/serve_legacy.go index 7f5146511..c4bbc542f 100644 --- a/cmd/tailscale/cli/serve_legacy.go +++ b/cmd/tailscale/cli/serve_legacy.go @@ -358,16 +358,12 @@ func (e *serveEnv) handleWebServe(ctx context.Context, srvPort uint16, useTLS bo if err != nil { return err } - if sc.IsTCPForwardingOnPort(srvPort, dnsName) { + if sc.IsTCPForwardingOnPort(dnsName, srvPort) { fmt.Fprintf(Stderr, "error: cannot serve web; already serving TCP\n") return errHelp } - st, err := e.getLocalClientStatusWithoutPeers(ctx) - if err != nil { - return fmt.Errorf("getting client status: %w", err) - } - sc.SetWebHandler(st, h, dnsName, srvPort, mount, useTLS) + sc.SetWebHandler(h, dnsName, srvPort, mount, useTLS, nil) if !reflect.DeepEqual(cursc, sc) { if err := e.lc.SetServeConfig(ctx, sc); err != nil { @@ -419,7 +415,7 @@ func (e *serveEnv) handleWebServeRemove(ctx context.Context, srvPort uint16, mou if err != nil { return err } - if sc.IsTCPForwardingOnPort(srvPort, dnsName) { + if sc.IsTCPForwardingOnPort(dnsName, srvPort) { return errors.New("cannot remove web handler; currently serving TCP") } hp := ipn.HostPort(net.JoinHostPort(dnsName, strconv.Itoa(int(srvPort)))) diff --git a/cmd/tailscale/cli/serve_v2.go b/cmd/tailscale/cli/serve_v2.go index d86bd8003..f5d44e697 100644 --- a/cmd/tailscale/cli/serve_v2.go +++ b/cmd/tailscale/cli/serve_v2.go @@ -527,16 +527,16 @@ func (e *serveEnv) setServe(sc *ipn.ServeConfig, st *ipnstate.Status, dnsName st } var ( - msgFunnelAvailable = "Available on the internet:" - msgServeAvailable = "Available within your tailnet:" - msgServiceIPNotAssigned = "This service %s is being served by this machine, but is not approved to have VIPs assigned yet. Once approved, it will be available in your Tailnet as:" - msgRunningInBackground = "%s started and running in the background." - msgRunningTunService = "IPv4 and IPv6 traffic to %s is being routed to your operating system." - msgDisableProxy = "To disable the proxy, run: tailscale %s --%s=%d off" - msgDisableServiceProxy = "To disable the proxy, run: tailscale serve --service=%s --%s=%d off" - msgDisableServiceTun = "To disable the service in TUN mode, run: tailscale serve --service=%s --tun off" - msgDisableService = "To remove config for the service, run: tailscale serve clear --service=%s" - msgToExit = "Press Ctrl+C to exit." + msgFunnelAvailable = "Available on the internet:" + msgServeAvailable = "Available within your tailnet:" + msgServiceWaitingApproval = "This machine is configured as a service proxy for %s, but approval from an admin is required. Once approved, it will be available in your Tailnet as:" + msgRunningInBackground = "%s started and running in the background." + msgRunningTunService = "IPv4 and IPv6 traffic to %s is being routed to your operating system." + msgDisableProxy = "To disable the proxy, run: tailscale %s --%s=%d off" + msgDisableServiceProxy = "To disable the proxy, run: tailscale serve --service=%s --%s=%d off" + msgDisableServiceTun = "To disable the service in TUN mode, run: tailscale serve --service=%s --tun off" + msgDisableService = "To remove config for the service, run: tailscale serve clear --service=%s" + msgToExit = "Press Ctrl+C to exit." ) // messageForPort returns a message for the given port based on the @@ -581,7 +581,7 @@ func (e *serveEnv) messageForPort(sc *ipn.ServeConfig, st *ipnstate.Status, dnsN if err != nil || len(serviceIPMaps) == 0 || serviceIPMaps[0][svcName] == nil { // The capmap does not contain IPs for this service yet. Usually this means // the service hasn't been added to prefs and sent to control yet. - output.WriteString(fmt.Sprintf(msgServiceIPNotAssigned, svcName.String())) + output.WriteString(fmt.Sprintf(msgServiceWaitingApproval, svcName.String())) ips = nil } else { output.WriteString(msgServeAvailable) @@ -698,11 +698,11 @@ func (e *serveEnv) applyWebServe(sc *ipn.ServeConfig, st *ipnstate.Status, dnsNa } // TODO: validation needs to check nested foreground configs - if sc.IsTCPForwardingOnPort(srvPort, dnsName) { + if sc.IsTCPForwardingOnPort(dnsName, srvPort) { return errors.New("cannot serve web; already serving TCP") } - sc.SetWebHandler(st, h, dnsName, srvPort, mount, useTLS) + sc.SetWebHandler(h, dnsName, srvPort, mount, useTLS, st) return nil } @@ -938,7 +938,7 @@ func (e *serveEnv) removeWebServe(sc *ipn.ServeConfig, st *ipnstate.Status, dnsN hp := ipn.HostPort(net.JoinHostPort(hostName, portStr)) - if sc.IsTCPForwardingOnPort(srvPort, dnsName) { + if sc.IsTCPForwardingOnPort(dnsName, srvPort) { return errors.New("cannot remove web handler; currently serving TCP") } var targetExists bool diff --git a/cmd/tailscale/cli/serve_v2_test.go b/cmd/tailscale/cli/serve_v2_test.go index 15ceb2ea6..79f0dc179 100644 --- a/cmd/tailscale/cli/serve_v2_test.go +++ b/cmd/tailscale/cli/serve_v2_test.go @@ -1389,7 +1389,7 @@ func TestMessageForPort(t *testing.T) { srvType: serveTypeHTTP, srvPort: 80, expected: strings.Join([]string{ - fmt.Sprintf(msgServiceIPNotAssigned, "svc:bar"), + fmt.Sprintf(msgServiceWaitingApproval, "svc:bar"), "", "http://bar.test.ts.net/", "|-- proxy http://localhost:3000", diff --git a/cmd/tailscale/cli/status.go b/cmd/tailscale/cli/status.go index f6ec0d75d..90166d0f8 100644 --- a/cmd/tailscale/cli/status.go +++ b/cmd/tailscale/cli/status.go @@ -260,7 +260,7 @@ func printFunnelStatus(ctx context.Context) { } sni, portStr, _ := net.SplitHostPort(string(hp)) p, _ := strconv.ParseUint(portStr, 10, 16) - isTCP := sc.IsTCPForwardingOnPort(uint16(p), sni) + isTCP := sc.IsTCPForwardingOnPort(sni, uint16(p)) url := "https://" if isTCP { url = "tcp://" diff --git a/cmd/tsidp/tsidp.go b/cmd/tsidp/tsidp.go index e5fef97dd..2ffb41dd4 100644 --- a/cmd/tsidp/tsidp.go +++ b/cmd/tsidp/tsidp.go @@ -266,9 +266,9 @@ func serveOnLocalTailscaled(ctx context.Context, lc *local.Client, st *ipnstate. fmt.Printf("setting funnel for %s:%v\n", serverURL, dstPort) foregroundSc.SetFunnel(serverURL, dstPort, shouldFunnel) - foregroundSc.SetWebHandler(st, &ipn.HTTPHandler{ + foregroundSc.SetWebHandler(&ipn.HTTPHandler{ Proxy: fmt.Sprintf("https://%s", net.JoinHostPort(serverURL, strconv.Itoa(int(dstPort)))), - }, serverURL, uint16(*flagPort), "/", true) + }, serverURL, uint16(*flagPort), "/", true, st) err = lc.SetServeConfig(ctx, sc) if err != nil { return nil, watcherChan, fmt.Errorf("could not set serve config: %v", err) diff --git a/ipn/serve.go b/ipn/serve.go index d33372940..6df181cbb 100644 --- a/ipn/serve.go +++ b/ipn/serve.go @@ -247,7 +247,7 @@ func (sc *ServeConfig) IsTCPForwardingAny() bool { // IsTCPForwardingOnPort reports whether ServeConfig is currently forwarding // in TCPForward mode on the given port for a DNSName. DNSName will be either node's DNSName, or a // serviceName for service hosted on node. This is exclusive of Web/HTTPS serving. -func (sc *ServeConfig) IsTCPForwardingOnPort(port uint16, dnsName string) bool { +func (sc *ServeConfig) IsTCPForwardingOnPort(dnsName string, port uint16) bool { if sc == nil { return false } @@ -338,8 +338,9 @@ func (sc *ServeConfig) FindConfig(port uint16) (*ServeConfig, bool) { // SetWebHandler sets the given HTTPHandler at the specified host, port, // and mount in the serve config. sc.TCP is also updated to reflect web -// serving usage of the given port. -func (sc *ServeConfig) SetWebHandler(st *ipnstate.Status, handler *HTTPHandler, host string, port uint16, mount string, useTLS bool) { +// serving usage of the given port. The st argument is needed when setting +// a web handler for a service, other wise it can be nil. +func (sc *ServeConfig) SetWebHandler(handler *HTTPHandler, host string, port uint16, mount string, useTLS bool, st *ipnstate.Status) { if sc == nil { sc = new(ServeConfig) } diff --git a/ipn/serve_test.go b/ipn/serve_test.go index b7916dd68..8b66a1c69 100644 --- a/ipn/serve_test.go +++ b/ipn/serve_test.go @@ -235,7 +235,7 @@ func TestIsTCPForwardingOnPort(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := tt.cfg.IsTCPForwardingOnPort(tt.port, tt.dns) + got := tt.cfg.IsTCPForwardingOnPort(tt.dns, tt.port) if tt.want != got { t.Errorf("IsTCPForwardingOnPort() = %v, want %v", got, tt.want) }