Updates tailscale/corp#7515 Change-Id: I96f4016161ba3c370492da941274c6d9a234c2bb Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>main
parent
c35dcd427f
commit
25e26c16ee
@ -0,0 +1,107 @@ |
||||
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ipnlocal |
||||
|
||||
import ( |
||||
"context" |
||||
"crypto/tls" |
||||
"errors" |
||||
"io" |
||||
"net" |
||||
"net/http" |
||||
pathpkg "path" |
||||
"time" |
||||
|
||||
"tailscale.com/envknob" |
||||
"tailscale.com/ipn" |
||||
"tailscale.com/net/netutil" |
||||
) |
||||
|
||||
var runDevWebServer = envknob.RegisterBool("TS_DEV_WEBSERVER") |
||||
|
||||
func (b *LocalBackend) HandleInterceptedTCPConn(c net.Conn) { |
||||
if !runDevWebServer() { |
||||
b.logf("localbackend: closing TCP conn from %v to %v", c.RemoteAddr(), c.LocalAddr()) |
||||
c.Close() |
||||
return |
||||
} |
||||
|
||||
// TODO(bradfitz): look up how; sniff SNI if ambiguous
|
||||
hs := &http.Server{ |
||||
TLSConfig: &tls.Config{ |
||||
GetCertificate: b.getTLSServeCert, |
||||
}, |
||||
Handler: http.HandlerFunc(b.serveWebHandler), |
||||
} |
||||
hs.ServeTLS(netutil.NewOneConnListener(c, nil), "", "") |
||||
} |
||||
|
||||
func (b *LocalBackend) getServeHandler(r *http.Request) (_ *ipn.HTTPHandler, ok bool) { |
||||
if r.TLS == nil { |
||||
return nil, false |
||||
} |
||||
|
||||
sni := r.TLS.ServerName |
||||
port := "443" // TODO(bradfitz): fix
|
||||
key := ipn.HostPort(net.JoinHostPort(sni, port)) |
||||
|
||||
b.mu.Lock() |
||||
defer b.mu.Unlock() |
||||
|
||||
wsc, ok := b.serveConfig.Web[key] |
||||
if !ok { |
||||
return nil, false |
||||
} |
||||
path := r.URL.Path |
||||
for { |
||||
if h, ok := wsc.Handlers[path]; ok { |
||||
return h, true |
||||
} |
||||
if path == "/" { |
||||
return nil, false |
||||
} |
||||
path = pathpkg.Dir(path) |
||||
} |
||||
} |
||||
|
||||
func (b *LocalBackend) serveWebHandler(w http.ResponseWriter, r *http.Request) { |
||||
h, ok := b.getServeHandler(r) |
||||
if !ok { |
||||
http.NotFound(w, r) |
||||
return |
||||
} |
||||
if s := h.Text; s != "" { |
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8") |
||||
io.WriteString(w, s) |
||||
return |
||||
} |
||||
if v := h.Path; v != "" { |
||||
io.WriteString(w, "TODO(bradfitz): serve file") |
||||
return |
||||
} |
||||
if v := h.Proxy; v != "" { |
||||
io.WriteString(w, "TODO(bradfitz): proxy") |
||||
return |
||||
} |
||||
|
||||
http.Error(w, "empty handler", 500) |
||||
} |
||||
|
||||
func (b *LocalBackend) getTLSServeCert(hi *tls.ClientHelloInfo) (*tls.Certificate, error) { |
||||
if hi == nil || hi.ServerName == "" { |
||||
return nil, errors.New("no SNI ServerName") |
||||
} |
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) |
||||
defer cancel() |
||||
pair, err := b.GetCertPEM(ctx, hi.ServerName) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
cert, err := tls.X509KeyPair(pair.CertPEM, pair.KeyPEM) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &cert, nil |
||||
} |
||||
Loading…
Reference in new issue