diff --git a/cmd/tailscale/cli/serve_v2.go b/cmd/tailscale/cli/serve_v2.go index 74458a950..9c07f8a8b 100644 --- a/cmd/tailscale/cli/serve_v2.go +++ b/cmd/tailscale/cli/serve_v2.go @@ -966,7 +966,7 @@ func (e *serveEnv) setServe(sc *ipn.ServeConfig, dnsName string, srvType serveTy if e.setPath != "" { return fmt.Errorf("cannot mount a path for TCP serve") } - err := e.applyTCPServe(sc, dnsName, srvType, srvPort, target) + err := e.applyTCPServe(sc, dnsName, srvType, srvPort, target, mds) if err != nil { return fmt.Errorf("failed to apply TCP serve: %w", err) } @@ -1170,7 +1170,7 @@ func (e *serveEnv) applyWebServe(sc *ipn.ServeConfig, dnsName string, srvPort ui return nil } -func (e *serveEnv) applyTCPServe(sc *ipn.ServeConfig, dnsName string, srcType serveType, srcPort uint16, target string) error { +func (e *serveEnv) applyTCPServe(sc *ipn.ServeConfig, dnsName string, srcType serveType, srcPort uint16, target string, mds string) error { var terminateTLS bool switch srcType { case serveTypeTCP: @@ -1192,9 +1192,11 @@ func (e *serveEnv) applyTCPServe(sc *ipn.ServeConfig, dnsName string, srcType se } // TODO: needs to account for multiple configs from foreground mode - svcName := tailcfg.AsServiceName(dnsName) - if sc.IsServingWeb(srcPort, svcName) { - return fmt.Errorf("cannot serve TCP; already serving web on %d for %s", srcPort, dnsName) + if svcName := tailcfg.AsServiceName(dnsName); svcName != "" { + if sc.IsServingWeb(srcPort, svcName) { + return fmt.Errorf("cannot serve TCP; already serving web on %d for %s", srcPort, dnsName) + } + sc.SetTCPForwardingForService(srcPort, dstURL.Host, terminateTLS, svcName, mds) } sc.SetTCPForwarding(srcPort, dstURL.Host, terminateTLS, dnsName) diff --git a/ipn/serve.go b/ipn/serve.go index 2ac37a141..d3f38ec6b 100644 --- a/ipn/serve.go +++ b/ipn/serve.go @@ -408,19 +408,30 @@ func (sc *ServeConfig) SetTCPForwarding(port uint16, fwdAddr string, terminateTL if sc == nil { sc = new(ServeConfig) } - tcpPortHandler := &sc.TCP - if svcName := tailcfg.AsServiceName(host); svcName != "" { - svcConfig, ok := sc.Services[svcName] - if !ok { - svcConfig = new(ServiceConfig) - mak.Set(&sc.Services, svcName, svcConfig) - } - tcpPortHandler = &svcConfig.TCP + mak.Set(&sc.TCP, port, &TCPPortHandler{TCPForward: fwdAddr}) + + if terminateTLS { + sc.TCP[port].TerminateTLS = host + } +} + +// SetTCPForwardingForService is sets the fwdAddr (IP:port form) to which to +// forward connections from the given port on the service. If terminateTLS +// is true, TLS connections are terminated, with only the FQDN that corresponds +// to the given service being permitted, before passing them to the fwdAddr. +func (sc *ServeConfig) SetTCPForwardingForService(port uint16, fwdAddr string, terminateTLS bool, svcName tailcfg.ServiceName, magicDNSSuffix string) { + if sc == nil { + sc = new(ServeConfig) + } + svcConfig, ok := sc.Services[svcName] + if !ok { + svcConfig = new(ServiceConfig) + mak.Set(&sc.Services, svcName, svcConfig) } - mak.Set(tcpPortHandler, port, &TCPPortHandler{TCPForward: fwdAddr}) + mak.Set(&svcConfig.TCP, port, &TCPPortHandler{TCPForward: fwdAddr}) if terminateTLS { - (*tcpPortHandler)[port].TerminateTLS = host + svcConfig.TCP[port].TerminateTLS = fmt.Sprintf("%s.%s", svcName.WithoutPrefix(), magicDNSSuffix) } }