|
|
@ -11,20 +11,73 @@ import (
|
|
|
|
"io"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"net/netip"
|
|
|
|
pathpkg "path"
|
|
|
|
pathpkg "path"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"tailscale.com/envknob"
|
|
|
|
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/net/netutil"
|
|
|
|
"tailscale.com/net/netutil"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
var runDevWebServer = envknob.RegisterBool("TS_DEV_WEBSERVER")
|
|
|
|
func (b *LocalBackend) HandleInterceptedTCPConn(dport uint16, srcAddr netip.AddrPort, getConn func() (net.Conn, bool), sendRST func()) {
|
|
|
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
|
|
|
sc := b.serveConfig
|
|
|
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
func (b *LocalBackend) HandleInterceptedTCPConn(c net.Conn) {
|
|
|
|
if !sc.Valid() {
|
|
|
|
if !runDevWebServer() {
|
|
|
|
b.logf("[unexpected] localbackend: got TCP conn w/o serveConfig; from %v to port %v", srcAddr, dport)
|
|
|
|
b.logf("localbackend: closing TCP conn from %v to %v", c.RemoteAddr(), c.LocalAddr())
|
|
|
|
sendRST()
|
|
|
|
c.Close()
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tcph, ok := sc.TCP().GetOk(int(dport))
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
|
|
b.logf("[unexpected] localbackend: got TCP conn without TCP config for port %v; from %v", dport, srcAddr)
|
|
|
|
|
|
|
|
sendRST()
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if backDst := tcph.TCPForward(); backDst != "" {
|
|
|
|
|
|
|
|
if tcph.TerminateTLS() {
|
|
|
|
|
|
|
|
b.logf("TODO(bradfitz): finish")
|
|
|
|
|
|
|
|
sendRST()
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
|
|
|
|
|
|
backConn, err := b.dialer.SystemDial(ctx, "tcp", backDst)
|
|
|
|
|
|
|
|
cancel()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
b.logf("localbackend: failed to TCP proxy port %v (from %v) to %s: %v", dport, srcAddr, backDst, err)
|
|
|
|
|
|
|
|
sendRST()
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
conn, ok := getConn()
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
|
|
b.logf("localbackend: getConn didn't complete from %v to port %v", srcAddr, dport)
|
|
|
|
|
|
|
|
backConn.Close()
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
|
|
|
defer backConn.Close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO(bradfitz): do the RegisterIPPortIdentity and
|
|
|
|
|
|
|
|
// UnregisterIPPortIdentity stuff that netstack does
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
errc := make(chan error, 1)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
|
|
_, err := io.Copy(backConn, conn)
|
|
|
|
|
|
|
|
errc <- err
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
|
|
_, err := io.Copy(conn, backConn)
|
|
|
|
|
|
|
|
errc <- err
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
<-errc
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
conn, ok := getConn()
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -35,7 +88,7 @@ func (b *LocalBackend) HandleInterceptedTCPConn(c net.Conn) {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Handler: http.HandlerFunc(b.serveWebHandler),
|
|
|
|
Handler: http.HandlerFunc(b.serveWebHandler),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hs.ServeTLS(netutil.NewOneConnListener(c, nil), "", "")
|
|
|
|
hs.ServeTLS(netutil.NewOneConnListener(conn, nil), "", "")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (b *LocalBackend) getServeHandler(r *http.Request) (_ ipn.HTTPHandlerView, ok bool) {
|
|
|
|
func (b *LocalBackend) getServeHandler(r *http.Request) (_ ipn.HTTPHandlerView, ok bool) {
|
|
|
|