mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-11-04 00:55:11 +00:00 
			
		
		
		
	This is not valid in many situations, specifically when running a local astro site that listens on localhost, but ignores 127.0.0.1 Fixes: https://github.com/tailscale/tailscale/issues/12201 Signed-off-by: Josh McKinney <joshka@users.noreply.github.com>
		
			
				
	
	
		
			185 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) Tailscale Inc & AUTHORS
 | 
						|
// SPDX-License-Identifier: BSD-3-Clause
 | 
						|
package ipn
 | 
						|
 | 
						|
import (
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"tailscale.com/ipn/ipnstate"
 | 
						|
	"tailscale.com/tailcfg"
 | 
						|
)
 | 
						|
 | 
						|
func TestCheckFunnelAccess(t *testing.T) {
 | 
						|
	caps := func(c ...tailcfg.NodeCapability) []tailcfg.NodeCapability { return c }
 | 
						|
	const portAttr tailcfg.NodeCapability = "https://tailscale.com/cap/funnel-ports?ports=443,8080-8090,8443,"
 | 
						|
	tests := []struct {
 | 
						|
		port    uint16
 | 
						|
		caps    []tailcfg.NodeCapability
 | 
						|
		wantErr bool
 | 
						|
	}{
 | 
						|
		{443, caps(portAttr), true}, // No "funnel" attribute
 | 
						|
		{443, caps(portAttr, tailcfg.NodeAttrFunnel), true},
 | 
						|
		{443, caps(portAttr, tailcfg.CapabilityHTTPS, tailcfg.NodeAttrFunnel), false},
 | 
						|
		{8443, caps(portAttr, tailcfg.CapabilityHTTPS, tailcfg.NodeAttrFunnel), false},
 | 
						|
		{8321, caps(portAttr, tailcfg.CapabilityHTTPS, tailcfg.NodeAttrFunnel), true},
 | 
						|
		{8083, caps(portAttr, tailcfg.CapabilityHTTPS, tailcfg.NodeAttrFunnel), false},
 | 
						|
		{8091, caps(portAttr, tailcfg.CapabilityHTTPS, tailcfg.NodeAttrFunnel), true},
 | 
						|
		{3000, caps(portAttr, tailcfg.CapabilityHTTPS, tailcfg.NodeAttrFunnel), true},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		cm := tailcfg.NodeCapMap{}
 | 
						|
		for _, c := range tt.caps {
 | 
						|
			cm[c] = nil
 | 
						|
		}
 | 
						|
		err := CheckFunnelAccess(tt.port, &ipnstate.PeerStatus{CapMap: cm})
 | 
						|
		switch {
 | 
						|
		case err != nil && tt.wantErr,
 | 
						|
			err == nil && !tt.wantErr:
 | 
						|
			continue
 | 
						|
		case tt.wantErr:
 | 
						|
			t.Fatalf("got no error, want error")
 | 
						|
		case !tt.wantErr:
 | 
						|
			t.Fatalf("got error %v, want no error", err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestHasPathHandler(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name string
 | 
						|
		cfg  ServeConfig
 | 
						|
		want bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "empty-config",
 | 
						|
			cfg:  ServeConfig{},
 | 
						|
			want: false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "with-bg-path-handler",
 | 
						|
			cfg: ServeConfig{
 | 
						|
				TCP: map[uint16]*TCPPortHandler{80: {HTTP: true}},
 | 
						|
				Web: map[HostPort]*WebServerConfig{
 | 
						|
					"foo.test.ts.net:80": {Handlers: map[string]*HTTPHandler{
 | 
						|
						"/": {Path: "/tmp"},
 | 
						|
					}},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			want: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "with-fg-path-handler",
 | 
						|
			cfg: ServeConfig{
 | 
						|
				TCP: map[uint16]*TCPPortHandler{
 | 
						|
					443: {HTTPS: true},
 | 
						|
				},
 | 
						|
				Foreground: map[string]*ServeConfig{
 | 
						|
					"abc123": {
 | 
						|
						TCP: map[uint16]*TCPPortHandler{80: {HTTP: true}},
 | 
						|
						Web: map[HostPort]*WebServerConfig{
 | 
						|
							"foo.test.ts.net:80": {Handlers: map[string]*HTTPHandler{
 | 
						|
								"/": {Path: "/tmp"},
 | 
						|
							}},
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			want: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "with-no-bg-path-handler",
 | 
						|
			cfg: ServeConfig{
 | 
						|
				TCP: map[uint16]*TCPPortHandler{443: {HTTPS: true}},
 | 
						|
				Web: map[HostPort]*WebServerConfig{
 | 
						|
					"foo.test.ts.net:443": {Handlers: map[string]*HTTPHandler{
 | 
						|
						"/": {Proxy: "http://127.0.0.1:3000"},
 | 
						|
					}},
 | 
						|
				},
 | 
						|
				AllowFunnel: map[HostPort]bool{"foo.test.ts.net:443": true},
 | 
						|
			},
 | 
						|
			want: false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "with-no-fg-path-handler",
 | 
						|
			cfg: ServeConfig{
 | 
						|
				Foreground: map[string]*ServeConfig{
 | 
						|
					"abc123": {
 | 
						|
						TCP: map[uint16]*TCPPortHandler{443: {HTTPS: true}},
 | 
						|
						Web: map[HostPort]*WebServerConfig{
 | 
						|
							"foo.test.ts.net:443": {Handlers: map[string]*HTTPHandler{
 | 
						|
								"/": {Proxy: "http://127.0.0.1:3000"},
 | 
						|
							}},
 | 
						|
						},
 | 
						|
						AllowFunnel: map[HostPort]bool{"foo.test.ts.net:443": true},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			want: false,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			got := tt.cfg.HasPathHandler()
 | 
						|
			if tt.want != got {
 | 
						|
				t.Errorf("HasPathHandler() = %v, want %v", got, tt.want)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestExpandProxyTargetDev(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name             string
 | 
						|
		input            string
 | 
						|
		defaultScheme    string
 | 
						|
		supportedSchemes []string
 | 
						|
		expected         string
 | 
						|
		wantErr          bool
 | 
						|
	}{
 | 
						|
		{name: "port-only", input: "8080", expected: "http://127.0.0.1:8080"},
 | 
						|
		{name: "hostname+port", input: "localhost:8080", expected: "http://localhost:8080"},
 | 
						|
		{name: "no-change", input: "http://127.0.0.1:8080", expected: "http://127.0.0.1:8080"},
 | 
						|
		{name: "include-path", input: "http://127.0.0.1:8080/foo", expected: "http://127.0.0.1:8080/foo"},
 | 
						|
		{name: "https-scheme", input: "https://localhost:8080", expected: "https://localhost:8080"},
 | 
						|
		{name: "https+insecure-scheme", input: "https+insecure://localhost:8080", expected: "https+insecure://localhost:8080"},
 | 
						|
		{name: "change-default-scheme", input: "localhost:8080", defaultScheme: "https", expected: "https://localhost:8080"},
 | 
						|
		{name: "change-supported-schemes", input: "localhost:8080", defaultScheme: "tcp", supportedSchemes: []string{"tcp"}, expected: "tcp://localhost:8080"},
 | 
						|
 | 
						|
		// errors
 | 
						|
		{name: "invalid-port", input: "localhost:9999999", wantErr: true},
 | 
						|
		{name: "unsupported-scheme", input: "ftp://localhost:8080", expected: "", wantErr: true},
 | 
						|
		{name: "not-localhost", input: "https://tailscale.com:8080", expected: "", wantErr: true},
 | 
						|
		{name: "empty-input", input: "", expected: "", wantErr: true},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		defaultScheme := "http"
 | 
						|
		supportedSchemes := []string{"http", "https", "https+insecure"}
 | 
						|
 | 
						|
		if tt.supportedSchemes != nil {
 | 
						|
			supportedSchemes = tt.supportedSchemes
 | 
						|
		}
 | 
						|
		if tt.defaultScheme != "" {
 | 
						|
			defaultScheme = tt.defaultScheme
 | 
						|
		}
 | 
						|
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			actual, err := ExpandProxyTargetValue(tt.input, supportedSchemes, defaultScheme)
 | 
						|
 | 
						|
			if tt.wantErr == true && err == nil {
 | 
						|
				t.Errorf("Expected an error but got none")
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			if tt.wantErr == false && err != nil {
 | 
						|
				t.Errorf("Got an error, but didn't expect one: %v", err)
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			if actual != tt.expected {
 | 
						|
				t.Errorf("Got: %q; expected: %q", actual, tt.expected)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |