Compare commits
1 Commits
awly/versi
...
tyler/serv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae8a052c5f |
@@ -54,7 +54,7 @@ func newFunnelCommand(e *serveEnv) *ffcli.Command {
|
||||
Subcommands: []*ffcli.Command{
|
||||
{
|
||||
Name: "status",
|
||||
Exec: e.runServeStatus,
|
||||
Exec: e.runLegacyServeStatus,
|
||||
ShortHelp: "show current serve/funnel status",
|
||||
FlagSet: e.newFlags("funnel-status", func(fs *flag.FlagSet) {
|
||||
fs.BoolVar(&e.json, "json", false, "output JSON")
|
||||
|
||||
@@ -97,7 +97,7 @@ EXAMPLES
|
||||
Subcommands: []*ffcli.Command{
|
||||
{
|
||||
Name: "status",
|
||||
Exec: e.runServeStatus,
|
||||
Exec: e.runLegacyServeStatus,
|
||||
ShortHelp: "show current serve/funnel status",
|
||||
FlagSet: e.newFlags("serve-status", func(fs *flag.FlagSet) {
|
||||
fs.BoolVar(&e.json, "json", false, "output JSON")
|
||||
@@ -635,13 +635,13 @@ func (e *serveEnv) handleTCPServeRemove(ctx context.Context, src uint16) error {
|
||||
return errors.New("error: serve config does not exist")
|
||||
}
|
||||
|
||||
// runServeStatus is the entry point for the "serve status"
|
||||
// runLegacyServeStatus is the entry point for the "serve status"
|
||||
// subcommand and prints the current serve config.
|
||||
//
|
||||
// Examples:
|
||||
// - tailscale status
|
||||
// - tailscale status --json
|
||||
func (e *serveEnv) runServeStatus(ctx context.Context, args []string) error {
|
||||
func (e *serveEnv) runLegacyServeStatus(ctx context.Context, args []string) error {
|
||||
sc, err := e.lc.GetServeConfig(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -665,13 +665,13 @@ func (e *serveEnv) runServeStatus(ctx context.Context, args []string) error {
|
||||
return err
|
||||
}
|
||||
if sc.IsTCPForwardingAny() {
|
||||
if err := printTCPStatusTree(ctx, sc, st); err != nil {
|
||||
if err := printLegacyTCPStatusTree(ctx, sc, st); err != nil {
|
||||
return err
|
||||
}
|
||||
printf("\n")
|
||||
}
|
||||
for hp := range sc.Web {
|
||||
err := e.printWebStatusTree(sc, hp)
|
||||
err := e.printLegacyWebStatusTree(sc, hp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -688,7 +688,7 @@ func (e *serveEnv) stdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
func printTCPStatusTree(ctx context.Context, sc *ipn.ServeConfig, st *ipnstate.Status) error {
|
||||
func printLegacyTCPStatusTree(ctx context.Context, sc *ipn.ServeConfig, st *ipnstate.Status) error {
|
||||
dnsName := strings.TrimSuffix(st.Self.DNSName, ".")
|
||||
for p, h := range sc.TCP {
|
||||
if h.TCPForward == "" {
|
||||
@@ -713,7 +713,7 @@ func printTCPStatusTree(ctx context.Context, sc *ipn.ServeConfig, st *ipnstate.S
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *serveEnv) printWebStatusTree(sc *ipn.ServeConfig, hp ipn.HostPort) error {
|
||||
func (e *serveEnv) printLegacyWebStatusTree(sc *ipn.ServeConfig, hp ipn.HostPort) error {
|
||||
// No-op if no serve config
|
||||
if sc == nil {
|
||||
return nil
|
||||
|
||||
@@ -132,7 +132,7 @@ func newServeV2Command(e *serveEnv, subcmd serveMode) *ffcli.Command {
|
||||
Subcommands: []*ffcli.Command{
|
||||
{
|
||||
Name: "status",
|
||||
Exec: e.runServeStatus,
|
||||
Exec: e.runServeStatus(subcmd),
|
||||
ShortHelp: "view current proxy configuration",
|
||||
FlagSet: e.newFlags("serve-status", func(fs *flag.FlagSet) {
|
||||
fs.BoolVar(&e.json, "json", false, "output JSON")
|
||||
@@ -445,34 +445,12 @@ func (e *serveEnv) messageForPort(sc *ipn.ServeConfig, st *ipnstate.Status, dnsN
|
||||
portPart = ""
|
||||
}
|
||||
|
||||
srvTypeAndDesc := func(h *ipn.HTTPHandler) (string, string) {
|
||||
switch {
|
||||
case h.Path != "":
|
||||
return "path", h.Path
|
||||
case h.Proxy != "":
|
||||
return "proxy", h.Proxy
|
||||
case h.Text != "":
|
||||
return "text", "\"" + elipticallyTruncate(h.Text, 20) + "\""
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
if sc.Web[hp] != nil {
|
||||
var mounts []string
|
||||
|
||||
for k := range sc.Web[hp].Handlers {
|
||||
mounts = append(mounts, k)
|
||||
}
|
||||
sort.Slice(mounts, func(i, j int) bool {
|
||||
return len(mounts[i]) < len(mounts[j])
|
||||
})
|
||||
|
||||
for _, m := range mounts {
|
||||
h := sc.Web[hp].Handlers[m]
|
||||
t, d := srvTypeAndDesc(h)
|
||||
output.WriteString(fmt.Sprintf("%s://%s%s%s\n", scheme, dnsName, portPart, m))
|
||||
output.WriteString(fmt.Sprintf("%s %-5s %s\n\n", "|--", t, d))
|
||||
webTree, err := e.webStatusTree(sc, st, hp)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
output.WriteString(webTree)
|
||||
} else if sc.TCP[srvPort] != nil {
|
||||
h := sc.TCP[srvPort]
|
||||
|
||||
@@ -868,6 +846,147 @@ func (e *serveEnv) removeTCPServe(sc *ipn.ServeConfig, src uint16) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// runServeStatus is the entry point for the "serve status"
|
||||
// subcommand and prints the current serve config.
|
||||
//
|
||||
// Examples:
|
||||
// - tailscale status
|
||||
// - tailscale status --json
|
||||
func (e *serveEnv) runServeStatus(subcmd serveMode) execFunc {
|
||||
e.subcmd = subcmd
|
||||
|
||||
return func(ctx context.Context, args []string) error {
|
||||
sc, err := e.lc.GetServeConfig(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if e.json {
|
||||
j, err := json.MarshalIndent(sc, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
j = append(j, '\n')
|
||||
e.stdout().Write(j)
|
||||
return nil
|
||||
}
|
||||
|
||||
if sc == nil || (len(sc.TCP) == 0 && len(sc.Web) == 0 && len(sc.AllowFunnel) == 0) {
|
||||
fmt.Printf("No %s config\n", infoMap[e.subcmd].Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
st, err := e.getLocalClientStatusWithoutPeers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sc.IsTCPForwardingAny() {
|
||||
tree := e.tcpStatusTree(sc, st)
|
||||
printf(tree)
|
||||
}
|
||||
for hp := range sc.Web {
|
||||
tree, err := e.webStatusTree(sc, st, hp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printf(tree)
|
||||
}
|
||||
printFunnelWarning(sc)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *serveEnv) webStatusTree(sc *ipn.ServeConfig, st *ipnstate.Status, hp ipn.HostPort) (string, error) {
|
||||
var output strings.Builder
|
||||
|
||||
// No-op if no serve config
|
||||
if sc == nil {
|
||||
return "", nil
|
||||
}
|
||||
fStatus := "tailnet only"
|
||||
if sc.AllowFunnel[hp] {
|
||||
fStatus = "public"
|
||||
}
|
||||
_, portStr, _ := net.SplitHostPort(string(hp))
|
||||
|
||||
port, err := parseServePort(portStr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid port %q: %w", portStr, err)
|
||||
}
|
||||
|
||||
scheme := "https"
|
||||
if sc.IsServingHTTP(port) {
|
||||
scheme = "http"
|
||||
}
|
||||
|
||||
portPart := ":" + portStr
|
||||
if scheme == "http" && portStr == "80" ||
|
||||
scheme == "https" && portStr == "443" {
|
||||
portPart = ""
|
||||
}
|
||||
|
||||
srvTypeAndDesc := func(h *ipn.HTTPHandler) (string, string) {
|
||||
switch {
|
||||
case h.Path != "":
|
||||
return "path", h.Path
|
||||
case h.Proxy != "":
|
||||
return "proxy", h.Proxy
|
||||
case h.Text != "":
|
||||
return "text", "\"" + elipticallyTruncate(h.Text, 20) + "\""
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
var mounts []string
|
||||
|
||||
for k := range sc.Web[hp].Handlers {
|
||||
mounts = append(mounts, k)
|
||||
}
|
||||
sort.Slice(mounts, func(i, j int) bool {
|
||||
return len(mounts[i]) < len(mounts[j])
|
||||
})
|
||||
|
||||
dnsName := strings.TrimSuffix(st.Self.DNSName, ".")
|
||||
|
||||
for _, m := range mounts {
|
||||
h := sc.Web[hp].Handlers[m]
|
||||
t, d := srvTypeAndDesc(h)
|
||||
|
||||
output.WriteString(fmt.Sprintf("%s://%s%s%s (%s)\n", scheme, dnsName, portPart, m, fStatus))
|
||||
output.WriteString(fmt.Sprintf("%s %-5s %s\n\n", "|--", t, d))
|
||||
}
|
||||
|
||||
return output.String(), nil
|
||||
}
|
||||
|
||||
func (e *serveEnv) tcpStatusTree(sc *ipn.ServeConfig, st *ipnstate.Status) string {
|
||||
var output strings.Builder
|
||||
|
||||
dnsName := strings.TrimSuffix(st.Self.DNSName, ".")
|
||||
for p, h := range sc.TCP {
|
||||
if h.TCPForward == "" {
|
||||
continue
|
||||
}
|
||||
hp := ipn.HostPort(net.JoinHostPort(dnsName, strconv.Itoa(int(p))))
|
||||
tlsStatus := "TLS over TCP"
|
||||
if h.TerminateTLS != "" {
|
||||
tlsStatus = "TLS terminated"
|
||||
}
|
||||
fStatus := "tailnet only"
|
||||
if sc.AllowFunnel[hp] {
|
||||
fStatus = "public"
|
||||
}
|
||||
output.WriteString(fmt.Sprintf("tcp://%s (%s, %s)\n", hp, tlsStatus, fStatus))
|
||||
for _, a := range st.TailscaleIPs {
|
||||
ipp := net.JoinHostPort(a.String(), strconv.Itoa(int(p)))
|
||||
output.WriteString(fmt.Sprintf("|-- tcp://%s\n", ipp))
|
||||
}
|
||||
output.WriteString(fmt.Sprintf("|--> tcp://%s\n\n", h.TCPForward))
|
||||
}
|
||||
return output.String()
|
||||
}
|
||||
|
||||
// expandProxyTargetDev expands the supported target values to be proxied
|
||||
// allowing for input values to be a port number, a partial URL, or a full URL
|
||||
// including a path.
|
||||
|
||||
Reference in New Issue
Block a user