cmd/tailscale/cli: change parameter of IsTCPForwardingOnPort

This commit changes the dnsName string parameter for IsTCPForwardingOnPort to
svcName tailcfg.ServiceName. This change is made to reduce ambiguity when
a single service might have different dnsNames

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>
This commit is contained in:
KevinLiang10 2025-06-27 17:56:09 -04:00
parent d8eeceabf8
commit b4eb836c80
5 changed files with 65 additions and 62 deletions

View File

@ -358,7 +358,7 @@ func (e *serveEnv) handleWebServe(ctx context.Context, srvPort uint16, useTLS bo
if err != nil { if err != nil {
return err return err
} }
if sc.IsTCPForwardingOnPort(dnsName, srvPort) { if sc.IsTCPForwardingOnPort(srvPort, "") {
fmt.Fprintf(Stderr, "error: cannot serve web; already serving TCP\n") fmt.Fprintf(Stderr, "error: cannot serve web; already serving TCP\n")
return errHelp return errHelp
} }
@ -415,7 +415,7 @@ func (e *serveEnv) handleWebServeRemove(ctx context.Context, srvPort uint16, mou
if err != nil { if err != nil {
return err return err
} }
if sc.IsTCPForwardingOnPort(dnsName, srvPort) { if sc.IsTCPForwardingOnPort(srvPort, "") {
return errors.New("cannot remove web handler; currently serving TCP") return errors.New("cannot remove web handler; currently serving TCP")
} }
hp := ipn.HostPort(net.JoinHostPort(dnsName, strconv.Itoa(int(srvPort)))) hp := ipn.HostPort(net.JoinHostPort(dnsName, strconv.Itoa(int(srvPort))))
@ -559,7 +559,7 @@ func (e *serveEnv) handleTCPServe(ctx context.Context, srcType string, srcPort u
return err return err
} }
if sc.IsServingWeb(srcPort, dnsName) { if sc.IsServingWeb(srcPort, "") {
return fmt.Errorf("cannot serve TCP; already serving web on %d", srcPort) return fmt.Errorf("cannot serve TCP; already serving web on %d", srcPort)
} }
@ -589,7 +589,7 @@ func (e *serveEnv) handleTCPServeRemove(ctx context.Context, src uint16) error {
if err != nil { if err != nil {
return err return err
} }
if sc.IsServingWeb(src, dnsName) { if sc.IsServingWeb(src, "") {
return fmt.Errorf("unable to remove; serving web, not TCP forwarding on serve port %d", src) return fmt.Errorf("unable to remove; serving web, not TCP forwarding on serve port %d", src)
} }
if ph := sc.GetTCPPortHandler(src, dnsName); ph != nil { if ph := sc.GetTCPPortHandler(src, dnsName); ph != nil {
@ -690,7 +690,7 @@ func (e *serveEnv) printWebStatusTree(sc *ipn.ServeConfig, hp ipn.HostPort) erro
} }
scheme := "https" scheme := "https"
if sc.IsServingHTTP(port, host) { if sc.IsServingHTTP(port, "") {
scheme = "http" scheme = "http"
} }

View File

@ -557,7 +557,7 @@ func (e *serveEnv) messageForPort(sc *ipn.ServeConfig, st *ipnstate.Status, dnsN
hp = ipn.HostPort(net.JoinHostPort(host, strconv.Itoa(int(srvPort)))) hp = ipn.HostPort(net.JoinHostPort(host, strconv.Itoa(int(srvPort))))
scheme := "https" scheme := "https"
if sc.IsServingHTTP(srvPort, dnsName) { if sc.IsServingHTTP(srvPort, svcName) {
scheme = "http" scheme = "http"
} }
@ -699,7 +699,7 @@ func (e *serveEnv) applyWebServe(sc *ipn.ServeConfig, st *ipnstate.Status, dnsNa
} }
// TODO: validation needs to check nested foreground configs // TODO: validation needs to check nested foreground configs
if sc.IsTCPForwardingOnPort(dnsName, srvPort) { if sc.IsTCPForwardingOnPort(srvPort, tailcfg.ServiceName(dnsName)) {
return errors.New("cannot serve web; already serving TCP") return errors.New("cannot serve web; already serving TCP")
} }
@ -730,7 +730,7 @@ func (e *serveEnv) applyTCPServe(sc *ipn.ServeConfig, dnsName string, srcType se
} }
// TODO: needs to account for multiple configs from foreground mode // TODO: needs to account for multiple configs from foreground mode
if sc.IsServingWeb(srcPort, dnsName) { if sc.IsServingWeb(srcPort, tailcfg.ServiceName(dnsName)) {
return fmt.Errorf("cannot serve TCP; already serving web on %d for %s", srcPort, dnsName) return fmt.Errorf("cannot serve TCP; already serving web on %d for %s", srcPort, dnsName)
} }
@ -939,7 +939,7 @@ func (e *serveEnv) removeWebServe(sc *ipn.ServeConfig, st *ipnstate.Status, dnsN
hp := ipn.HostPort(net.JoinHostPort(hostName, portStr)) hp := ipn.HostPort(net.JoinHostPort(hostName, portStr))
if sc.IsTCPForwardingOnPort(dnsName, srvPort) { if sc.IsTCPForwardingOnPort(srvPort, tailcfg.ServiceName(dnsName)) {
return errors.New("cannot remove web handler; currently serving TCP") return errors.New("cannot remove web handler; currently serving TCP")
} }
var targetExists bool var targetExists bool
@ -986,7 +986,7 @@ func (e *serveEnv) removeTCPServe(sc *ipn.ServeConfig, dnsName string, src uint1
if sc.GetTCPPortHandler(src, dnsName) == nil { if sc.GetTCPPortHandler(src, dnsName) == nil {
return errors.New("serve config does not exist") return errors.New("serve config does not exist")
} }
if sc.IsServingWeb(src, dnsName) { if sc.IsServingWeb(src, tailcfg.ServiceName(dnsName)) {
return fmt.Errorf("unable to remove; serving web, not TCP forwarding on serve port %d", src) return fmt.Errorf("unable to remove; serving web, not TCP forwarding on serve port %d", src)
} }
sc.RemoveTCPForwarding(dnsName, src) sc.RemoveTCPForwarding(dnsName, src)

View File

@ -260,7 +260,7 @@ func printFunnelStatus(ctx context.Context) {
} }
sni, portStr, _ := net.SplitHostPort(string(hp)) sni, portStr, _ := net.SplitHostPort(string(hp))
p, _ := strconv.ParseUint(portStr, 10, 16) p, _ := strconv.ParseUint(portStr, 10, 16)
isTCP := sc.IsTCPForwardingOnPort(sni, uint16(p)) isTCP := sc.IsTCPForwardingOnPort(uint16(p), "")
url := "https://" url := "https://"
if isTCP { if isTCP {
url = "tcp://" url = "tcp://"

View File

@ -245,14 +245,15 @@ func (sc *ServeConfig) IsTCPForwardingAny() bool {
} }
// IsTCPForwardingOnPort reports whether ServeConfig is currently forwarding // 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 // in TCPForward mode on the given port for local or a service. svcName will
// serviceName for service hosted on node. This is exclusive of Web/HTTPS serving. // either be empty string for local serve or a serviceName for service hosted
func (sc *ServeConfig) IsTCPForwardingOnPort(dnsName string, port uint16) bool { // on node. Notice TCPForwarding is exclusive with Web/HTTPS serving.
func (sc *ServeConfig) IsTCPForwardingOnPort(port uint16, svcName tailcfg.ServiceName) bool {
if sc == nil { if sc == nil {
return false return false
} }
if svcName, ok := tailcfg.AsServiceName(dnsName); ok { if err := svcName.Validate(); err == nil {
svc, ok := sc.Services[svcName] svc, ok := sc.Services[svcName]
if !ok || svc == nil { if !ok || svc == nil {
return false return false
@ -263,25 +264,26 @@ func (sc *ServeConfig) IsTCPForwardingOnPort(dnsName string, port uint16) bool {
} else if sc.TCP[port] == nil { } else if sc.TCP[port] == nil {
return false return false
} }
return !sc.IsServingWeb(port, dnsName) return !sc.IsServingWeb(port, svcName)
} }
// IsServingWeb reports whether ServeConfig is currently serving Web // IsServingWeb reports whether ServeConfig is currently serving Web (HTTP/HTTPS)
// (HTTP/HTTPS) on the given port for a DNSName. DNSName will be either node's DNSName, or a // on the given port for local or a service. DNSName will be either node's DNSName, or a
// serviceName for service hosted on node. This is exclusive of TCPForwarding. // serviceName for service hosted on node. This is exclusive with TCPForwarding.
func (sc *ServeConfig) IsServingWeb(port uint16, dnsName string) bool { func (sc *ServeConfig) IsServingWeb(port uint16, svcName tailcfg.ServiceName) bool {
return sc.IsServingHTTP(port, dnsName) || sc.IsServingHTTPS(port, dnsName) return sc.IsServingHTTP(port, svcName) || sc.IsServingHTTPS(port, svcName)
} }
// IsServingHTTPS reports whether ServeConfig is currently serving HTTPS on // IsServingHTTPS reports whether ServeConfig is currently serving HTTPS on
// the given port for a DNSName. DNSName will be either node's DNSName, or a // the given port for local or a service. svcName will be either empty string
// serviceName for service hosted on node. This is exclusive of HTTP and TCPForwarding. // for local serve, or a serviceName for service hosted on node. This is exclusive
func (sc *ServeConfig) IsServingHTTPS(port uint16, dnsName string) bool { // with HTTP and TCPForwarding.
func (sc *ServeConfig) IsServingHTTPS(port uint16, svcName tailcfg.ServiceName) bool {
if sc == nil { if sc == nil {
return false return false
} }
var tcpHandlers map[uint16]*TCPPortHandler var tcpHandlers map[uint16]*TCPPortHandler
if svcName, ok := tailcfg.AsServiceName(dnsName); ok { if err := svcName.Validate(); err == nil {
if svc := sc.Services[svcName]; svc != nil { if svc := sc.Services[svcName]; svc != nil {
tcpHandlers = svc.TCP tcpHandlers = svc.TCP
} }
@ -297,14 +299,15 @@ func (sc *ServeConfig) IsServingHTTPS(port uint16, dnsName string) bool {
} }
// IsServingHTTP reports whether ServeConfig is currently serving HTTP on the // IsServingHTTP reports whether ServeConfig is currently serving HTTP on the
// given port for a DNSName. DNSName will be either node's DNSName, or a // given port for local or a service. svcName will be either empty string for
// serviceName for service hosted on node. This is exclusive of HTTPS and TCPForwarding. // local serve, or a serviceName for service hosted on node. This is exclusive
func (sc *ServeConfig) IsServingHTTP(port uint16, dnsName string) bool { // with HTTPS and TCPForwarding.
func (sc *ServeConfig) IsServingHTTP(port uint16, svcName tailcfg.ServiceName) bool {
if sc == nil { if sc == nil {
return false return false
} }
if svcName, ok := tailcfg.AsServiceName(dnsName); ok { if err := svcName.Validate(); err == nil {
if svc, ok := sc.Services[svcName]; ok && svc != nil { if svc := sc.Services[svcName]; svc != nil {
if svc.TCP[port] != nil { if svc.TCP[port] != nil {
return svc.TCP[port].HTTP return svc.TCP[port].HTTP
} }

View File

@ -130,45 +130,45 @@ func TestHasPathHandler(t *testing.T) {
func TestIsTCPForwardingOnPort(t *testing.T) { func TestIsTCPForwardingOnPort(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
cfg ServeConfig cfg ServeConfig
dns string svcName tailcfg.ServiceName
port uint16 port uint16
want bool want bool
}{ }{
{ {
name: "empty-config", name: "empty-config",
cfg: ServeConfig{}, cfg: ServeConfig{},
dns: "foo.test.ts.net", svcName: "foo.test.ts.net",
port: 80, port: 80,
want: false, want: false,
}, },
{ {
name: "node-tcp-config-match", name: "node-tcp-config-match",
cfg: ServeConfig{ cfg: ServeConfig{
TCP: map[uint16]*TCPPortHandler{80: {TCPForward: "10.0.0.123:3000"}}, TCP: map[uint16]*TCPPortHandler{80: {TCPForward: "10.0.0.123:3000"}},
}, },
dns: "foo.test.ts.net", svcName: "foo.test.ts.net",
port: 80, port: 80,
want: true, want: true,
}, },
{ {
name: "node-tcp-config-no-match", name: "node-tcp-config-no-match",
cfg: ServeConfig{ cfg: ServeConfig{
TCP: map[uint16]*TCPPortHandler{80: {TCPForward: "10.0.0.123:3000"}}, TCP: map[uint16]*TCPPortHandler{80: {TCPForward: "10.0.0.123:3000"}},
}, },
dns: "foo.test.ts.net", svcName: "foo.test.ts.net",
port: 443, port: 443,
want: false, want: false,
}, },
{ {
name: "node-tcp-config-no-match-with-service", name: "node-tcp-config-no-match-with-service",
cfg: ServeConfig{ cfg: ServeConfig{
TCP: map[uint16]*TCPPortHandler{80: {TCPForward: "10.0.0.123:3000"}}, TCP: map[uint16]*TCPPortHandler{80: {TCPForward: "10.0.0.123:3000"}},
}, },
dns: "svc:bar", svcName: "svc:bar",
port: 80, port: 80,
want: false, want: false,
}, },
{ {
name: "node-web-config-no-match", name: "node-web-config-no-match",
@ -182,9 +182,9 @@ func TestIsTCPForwardingOnPort(t *testing.T) {
}, },
}, },
}, },
dns: "foo.test.ts.net", svcName: "foo.test.ts.net",
port: 80, port: 80,
want: false, want: false,
}, },
{ {
name: "service-tcp-config-match", name: "service-tcp-config-match",
@ -195,9 +195,9 @@ func TestIsTCPForwardingOnPort(t *testing.T) {
}, },
}, },
}, },
dns: "svc:foo", svcName: "svc:foo",
port: 80, port: 80,
want: true, want: true,
}, },
{ {
name: "service-tcp-config-no-match", name: "service-tcp-config-no-match",
@ -208,9 +208,9 @@ func TestIsTCPForwardingOnPort(t *testing.T) {
}, },
}, },
}, },
dns: "svc:bar", svcName: "svc:bar",
port: 80, port: 80,
want: false, want: false,
}, },
{ {
name: "service-web-config-no-match", name: "service-web-config-no-match",
@ -228,14 +228,14 @@ func TestIsTCPForwardingOnPort(t *testing.T) {
}, },
}, },
}, },
dns: "svc:foo", svcName: "svc:foo",
port: 80, port: 80,
want: false, want: false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got := tt.cfg.IsTCPForwardingOnPort(tt.dns, tt.port) got := tt.cfg.IsTCPForwardingOnPort(tt.port, tt.svcName)
if tt.want != got { if tt.want != got {
t.Errorf("IsTCPForwardingOnPort() = %v, want %v", got, tt.want) t.Errorf("IsTCPForwardingOnPort() = %v, want %v", got, tt.want)
} }