diff --git a/go.mod b/go.mod index a6f2e9517..38df23433 100644 --- a/go.mod +++ b/go.mod @@ -313,6 +313,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v1.0.0 // indirect + inet.af/tcpproxy v0.0.0-20221017015627-91f861402626 // indirect k8s.io/apiextensions-apiserver v0.25.0 // indirect k8s.io/client-go v0.25.0 // indirect k8s.io/component-base v0.25.0 // indirect diff --git a/go.sum b/go.sum index b386a7f34..d9c7a6f03 100644 --- a/go.sum +++ b/go.sum @@ -126,6 +126,7 @@ github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-proxyproto v0.0.0-20210323213023-7e956b284f0a/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -1934,6 +1935,8 @@ howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= inet.af/peercred v0.0.0-20210906144145-0893ea02156a h1:qdkS8Q5/i10xU2ArJMKYhVa1DORzBfYS/qA2UK2jheg= inet.af/peercred v0.0.0-20210906144145-0893ea02156a/go.mod h1:FjawnflS/udxX+SvpsMgZfdqx2aykOlkISeAsADi5IU= +inet.af/tcpproxy v0.0.0-20221017015627-91f861402626 h1:2dMP3Ox/Wh5BiItwOt4jxRsfzkgyBrHzx2nW28Yg6nc= +inet.af/tcpproxy v0.0.0-20221017015627-91f861402626/go.mod h1:Tojt5kmHpDIR2jMojxzZK2w2ZR7OILODmUo2gaSwjrk= inet.af/wf v0.0.0-20220728202103-50d96caab2f6 h1:BfgDtKnWJTeu+xI1aOEweXdPwqOhB3IbQUDj1XuftcY= inet.af/wf v0.0.0-20220728202103-50d96caab2f6/go.mod h1:bSAQ38BYbY68uwpasXOTZo22dKGy9SNvI6PZFeKomZE= k8s.io/api v0.25.0 h1:H+Q4ma2U/ww0iGB78ijZx6DRByPz6/733jIuFpX70e0= diff --git a/ipn/ipnlocal/serve.go b/ipn/ipnlocal/serve.go index faf63c22e..0fc5b65fa 100644 --- a/ipn/ipnlocal/serve.go +++ b/ipn/ipnlocal/serve.go @@ -24,6 +24,7 @@ "time" "golang.org/x/exp/slices" + "inet.af/tcpproxy" "tailscale.com/ipn" "tailscale.com/logtail/backoff" "tailscale.com/net/netutil" @@ -286,6 +287,26 @@ func (b *LocalBackend) HandleIngressTCPConn(ingressPeer *tailcfg.Node, target ip b.HandleInterceptedTCPConn(uint16(port16), srcAddr, getConn, sendRST) } +func (b *LocalBackend) HandleSassyTCPConn(dport uint16, srcAddr netip.AddrPort, getConn func() (net.Conn, bool), sendRST func()) { + conn, ok := getConn() + if !ok { + b.logf("localbackend: getConn didn't complete from %v to port %v", srcAddr, dport) + return + } + var p tcpproxy.Proxy + p.ListenFunc = func(net, laddr string) (net.Listener, error) { + return netutil.NewOneConnListener(conn, nil), nil + } + p.AddSNIRouteFunc("100.84.193.39:443", func(ctx context.Context, sniName string) (t tcpproxy.Target, ok bool) { + return &tcpproxy.DialProxy{ + Addr: net.JoinHostPort(sniName, "443"), + DialContext: b.dialer.SystemDial, + DialTimeout: 5 * time.Second, + }, true + }) + p.Start() +} + func (b *LocalBackend) HandleInterceptedTCPConn(dport uint16, srcAddr netip.AddrPort, getConn func() (net.Conn, bool), sendRST func()) { b.mu.Lock() sc := b.serveConfig diff --git a/wgengine/netstack/netstack.go b/wgengine/netstack/netstack.go index e2fc5e0c1..f8aff38d4 100644 --- a/wgengine/netstack/netstack.go +++ b/wgengine/netstack/netstack.go @@ -535,6 +535,8 @@ func (ns *Impl) shouldProcessInbound(p *packet.Parsed, t *tstun.Wrapper) bool { // Handle TCP connection to the Tailscale IP(s) in some cases: if ns.lb != nil && p.IPProto == ipproto.TCP && isLocal { + return true // XXX sassy test + var peerAPIPort uint16 if p.TCPFlags&packet.TCPSynAck == packet.TCPSyn { @@ -885,6 +887,18 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) { ns.lb.HandleQuad100Port80Conn(c) return } + if ns.isLocalIP(dialIP) { + getTCPConn := func() (_ net.Conn, ok bool) { + c := createConn() + return c, c != nil + } + sendRST := func() { + r.Complete(true) + } + ns.lb.HandleSassyTCPConn(reqDetails.LocalPort, clientRemoteAddrPort, getTCPConn, sendRST) + return + + } if ns.lb.ShouldInterceptTCPPort(reqDetails.LocalPort) && ns.isLocalIP(dialIP) { getTCPConn := func() (_ net.Conn, ok bool) { c := createConn() @@ -896,6 +910,7 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) { ns.lb.HandleInterceptedTCPConn(reqDetails.LocalPort, clientRemoteAddrPort, getTCPConn, sendRST) return } + return } if ns.ForwardTCPIn != nil {