ipn/ipnlocal: add start of handling TCP proxying

Updates tailscale/corp#7515

Change-Id: I82d19b5864674b2169f25ec8e429f60a543e0c57
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
bradfitz/set_prefs_locked
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent 4bccc02413
commit b683921b87

@ -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) {

@ -784,6 +784,8 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
r.Complete(true) // sends a RST r.Complete(true) // sends a RST
return return
} }
clientRemotePort := reqDetails.RemotePort
clientRemoteAddrPort := netip.AddrPortFrom(clientRemoteIP, clientRemotePort)
dialIP := netaddrIPFromNetstackIP(reqDetails.LocalAddress) dialIP := netaddrIPFromNetstackIP(reqDetails.LocalAddress)
isTailscaleIP := tsaddr.IsTailscaleIP(dialIP) isTailscaleIP := tsaddr.IsTailscaleIP(dialIP)
@ -894,11 +896,14 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
return return
} }
if ns.lb.ShouldInterceptTCPPort(reqDetails.LocalPort) && ns.isLocalIP(dialIP) { if ns.lb.ShouldInterceptTCPPort(reqDetails.LocalPort) && ns.isLocalIP(dialIP) {
c := createConn() getTCPConn := func() (_ net.Conn, ok bool) {
if c == nil { c := createConn()
return return c, c != nil
}
sendRST := func() {
r.Complete(true)
} }
ns.lb.HandleInterceptedTCPConn(c) ns.lb.HandleInterceptedTCPConn(reqDetails.LocalPort, clientRemoteAddrPort, getTCPConn, sendRST)
return return
} }
} }

Loading…
Cancel
Save