diff options
| author | Marwan Sulaiman <marwan@tailscale.com> | 2023-09-05 13:51:52 -0400 |
|---|---|---|
| committer | Marwan Sulaiman <marwan@tailscale.com> | 2023-09-05 13:51:52 -0400 |
| commit | ce16658ac0e032e9524bac8f5fc926b11f82a7a7 (patch) | |
| tree | 7ccf2dd7c97b1d5996c4ca709818edc529b34f81 /cmd | |
| parent | a4aa6507fa3afa586dc3cbbf85f2cae852622b9e (diff) | |
| download | tailscale-marwan/postmem.tar.xz tailscale-marwan/postmem.zip | |
ipn, ipn/ipnlocal: add Foreground field for ServeConfigmarwan/postmem
This PR adds a new field to the serve config that can be used to identify which serves are in "foreground mode" and then can also be used to ensure they do not get persisted to disk so that if Tailscaled gets ungracefully shutdown, the reloaded ServeConfig will not have those ports opened.
Updates #8489
Signed-off-by: Marwan Sulaiman <marwan@tailscale.com>
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/tailscale/cli/serve.go | 1 | ||||
| -rw-r--r-- | cmd/tailscale/cli/serve_dev.go | 85 |
2 files changed, 74 insertions, 12 deletions
diff --git a/cmd/tailscale/cli/serve.go b/cmd/tailscale/cli/serve.go index 39c0e106e..ab1a16913 100644 --- a/cmd/tailscale/cli/serve.go +++ b/cmd/tailscale/cli/serve.go @@ -149,7 +149,6 @@ type localServeClient interface { QueryFeature(ctx context.Context, feature string) (*tailcfg.QueryFeatureResponse, error) WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (*tailscale.IPNBusWatcher, error) IncrementCounter(ctx context.Context, name string, delta int) error - StreamServe(ctx context.Context, req ipn.ServeStreamRequest) (io.ReadCloser, error) // TODO: testing :) } // serveEnv is the environment the serve command runs within. All I/O should be diff --git a/cmd/tailscale/cli/serve_dev.go b/cmd/tailscale/cli/serve_dev.go index c2c94cc4a..30aa43119 100644 --- a/cmd/tailscale/cli/serve_dev.go +++ b/cmd/tailscale/cli/serve_dev.go @@ -5,9 +5,10 @@ package cli import ( "context" + "encoding/json" + "errors" "flag" "fmt" - "io" "log" "os" "os/signal" @@ -29,15 +30,15 @@ var infoMap = map[string]commandInfo{ "serve": { ShortHelp: "Serve content and local servers on your tailnet", LongHelp: strings.Join([]string{ - "Serve lets you share a local server securely within your tailnet.", - "To share a local server on the internet, use \"tailscale funnel\"", + `Serve lets you share a local server securely within your tailnet.`, + `To share a local server on the internet, use "tailscale funnel"`, }, "\n"), }, "funnel": { ShortHelp: "Serve content and local servers on the internet", LongHelp: strings.Join([]string{ - "Funnel lets you share a local server on the internet using Tailscale.", - "To share only within your tailnet, use \"tailscale serve\"", + `Funnel lets you share a local server on the internet using Tailscale.`, + `To share only within your tailnet, use "tailscale serve"`, }, "\n"), }, } @@ -134,14 +135,76 @@ func (e *serveEnv) runServeDev(funnel bool) execFunc { } func (e *serveEnv) streamServe(ctx context.Context, req ipn.ServeStreamRequest) error { - stream, err := e.lc.StreamServe(ctx, req) + watcher, err := e.lc.WatchIPNBus(ctx, ipn.NotifyInitialState|ipn.NotifyServeRequest) if err != nil { return err } - defer stream.Close() + defer watcher.Close() + n, err := watcher.Next() + if err != nil { + return err + } + if n.SessionID == "" { + return errors.New("missing session id") + } + sc, err := e.lc.GetServeConfig(ctx) + if err != nil { + return fmt.Errorf("error getting serve config: %w", err) + } + if sc == nil { + sc = &ipn.ServeConfig{} + } + setHandler(sc, req, n.SessionID) + err = e.lc.SetServeConfig(ctx, sc) + if err != nil { + return fmt.Errorf("error setting serve config: %w", err) + } + + fmt.Fprintf(os.Stderr, "Funnel started on \"https://%s\".\n", strings.TrimSuffix(string(req.HostPort), ":443")) + fmt.Fprintf(os.Stderr, "Press Ctrl-C to stop Funnel.\n\n") - fmt.Fprintf(os.Stderr, "Serve started on \"https://%s\".\n", strings.TrimSuffix(string(req.HostPort), ":443")) - fmt.Fprintf(os.Stderr, "Press Ctrl-C to stop.\n\n") - _, err = io.Copy(os.Stdout, stream) - return err + for { + n, err := watcher.Next() + if err != nil { + return fmt.Errorf("error calling next: %w", err) + } + if n.FunnelRequestLog == nil { + continue + } + bts, _ := json.Marshal(n.FunnelRequestLog) + fmt.Printf("%s\n", bts) + } +} + +func setHandler(sc *ipn.ServeConfig, req ipn.ServeStreamRequest, sessionID string) { + if sc.Foreground == nil { + sc.Foreground = make(map[string]*ipn.ServeConfig) + } + if sc.Foreground[sessionID] == nil { + sc.Foreground[sessionID] = &ipn.ServeConfig{} + } + if sc.Foreground[sessionID].TCP == nil { + sc.Foreground[sessionID].TCP = make(map[uint16]*ipn.TCPPortHandler) + } + if _, ok := sc.Foreground[sessionID].TCP[443]; !ok { + sc.Foreground[sessionID].TCP[443] = &ipn.TCPPortHandler{HTTPS: true} + } + if sc.Foreground[sessionID].Web == nil { + sc.Foreground[sessionID].Web = make(map[ipn.HostPort]*ipn.WebServerConfig) + } + wsc, ok := sc.Foreground[sessionID].Web[req.HostPort] + if !ok { + wsc = &ipn.WebServerConfig{} + sc.Foreground[sessionID].Web[req.HostPort] = wsc + } + if wsc.Handlers == nil { + wsc.Handlers = make(map[string]*ipn.HTTPHandler) + } + wsc.Handlers[req.MountPoint] = &ipn.HTTPHandler{ + Proxy: req.Source, + } + if sc.AllowFunnel == nil { + sc.AllowFunnel = make(map[ipn.HostPort]bool) + } + sc.AllowFunnel[req.HostPort] = true } |
