From ea599b018c021a27e2e3315344dfa6b3dab6abd7 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Thu, 26 Oct 2023 11:39:20 -0700 Subject: [PATCH] ipn: serve web client requests from LocalBackend instead of starting a separate server listening on a particular port, use the TCPHandlerForDst method to intercept requests for the special web client port (currently 5252, probably configurable later). Updates tailscale/corp#14335 Signed-off-by: Will Norris --- ipn/ipnlocal/local.go | 4 ++++ ipn/ipnlocal/web.go | 44 +++++++++++----------------------------- ipn/ipnlocal/web_stub.go | 5 +++++ 3 files changed, 21 insertions(+), 32 deletions(-) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index daae32c5d..19c7da294 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -3129,6 +3129,10 @@ func (b *LocalBackend) TCPHandlerForDst(src, dst netip.AddrPort) (handler func(c opts = append(opts, ptr.To(tcpip.KeepaliveIdleOption(72*time.Hour))) return b.handleSSHConn, opts } + // TODO(will,sonia): allow customizing web client port ? + if dst.Port() == 5252 && b.ShouldRunWebClient() { + return b.handleWebClientConn, opts + } if port, ok := b.GetPeerAPIPort(dst.Addr()); ok && dst.Port() == port { return func(c net.Conn) error { b.handlePeerAPIConn(src, dst, c) diff --git a/ipn/ipnlocal/web.go b/ipn/ipnlocal/web.go index 676120e28..16850d9bf 100644 --- a/ipn/ipnlocal/web.go +++ b/ipn/ipnlocal/web.go @@ -6,30 +6,27 @@ package ipnlocal import ( - "context" "errors" "fmt" + "net" "net/http" - "sync" "tailscale.com/client/tailscale" "tailscale.com/client/web" "tailscale.com/envknob" + "tailscale.com/net/netutil" ) // webServer holds state for the web interface for managing // this tailscale instance. The web interface is not used by // default, but initialized by calling LocalBackend.WebOrInit. type webServer struct { - ws *web.Server // or nil, initialized lazily - httpServer *http.Server // or nil, initialized lazily + ws *web.Server // or nil, initialized lazily // lc optionally specifies a LocalClient to use to connect // to the localapi for this tailscaled instance. // If nil, a default is used. lc *tailscale.LocalClient - - wg sync.WaitGroup } // SetWebLocalClient sets the b.web.lc function. @@ -63,24 +60,6 @@ func (b *LocalBackend) WebInit() (err error) { return fmt.Errorf("web.NewServer: %w", err) } - // Start up the server. - b.web.wg.Add(1) - go func() { - defer b.web.wg.Done() - // TODO(sonia/will): only listen on Tailscale IP addresses - addr := ":5252" - b.web.httpServer = &http.Server{ - Addr: addr, - Handler: http.HandlerFunc(b.web.ws.ServeHTTP), - } - b.logf("WebInit: serving web ui on %s", addr) - if err := b.web.httpServer.ListenAndServe(); err != nil { - if err != http.ErrServerClosed { - b.logf("[unexpected] WebInit: %v", err) - } - } - }() - b.logf("WebInit: started web ui") return nil } @@ -93,18 +72,19 @@ func (b *LocalBackend) WebInit() (err error) { func (b *LocalBackend) WebShutdown() { b.mu.Lock() webS := b.web.ws - httpS := b.web.httpServer b.web.ws = nil - b.web.httpServer = nil b.mu.Unlock() // release lock before shutdown if webS != nil { b.web.ws.Shutdown() } - if httpS != nil { - if err := b.web.httpServer.Shutdown(context.Background()); err != nil { - b.logf("[unexpected] WebShutdown: %v", err) - } - } - b.web.wg.Wait() b.logf("WebShutdown: shut down web ui") } + +// handleWebClientConn serves web client requests. +func (b *LocalBackend) handleWebClientConn(c net.Conn) error { + if err := b.WebInit(); err != nil { + return err + } + s := http.Server{Handler: b.web.ws} + return s.Serve(netutil.NewOneConnListener(c, nil)) +} diff --git a/ipn/ipnlocal/web_stub.go b/ipn/ipnlocal/web_stub.go index e3b77826b..a00db3b0b 100644 --- a/ipn/ipnlocal/web_stub.go +++ b/ipn/ipnlocal/web_stub.go @@ -7,6 +7,7 @@ package ipnlocal import ( "errors" + "net" "tailscale.com/client/tailscale" ) @@ -20,3 +21,7 @@ func (b *LocalBackend) WebInit() error { } func (b *LocalBackend) WebShutdown() {} + +func (b *LocalBackend) handleWebClientConn(c net.Conn) error { + return errors.New("not implemented") +}