Skip to content

Commit 9ce1607

Browse files
committed
Export OnlyTCP443
1 parent 953541d commit 9ce1607

File tree

4 files changed

+129
-4
lines changed

4 files changed

+129
-4
lines changed

derp/derphttp/derphttp_client.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ func (c *Client) tlsClient(nc net.Conn, node *tailcfg.DERPNode) *tls.Conn {
668668
// DERP nodes for a region are tried in sequence according to their order
669669
// in the DERP map. TLS is initiated on the first node where a socket is
670670
// established.
671-
func (c *Client) DialRegionTLS(ctx context.Context, reg *tailcfg.DERPRegion) (tlsConn *tls.Conn, connClose io.Closer, node *tailcfg.DERPNode, err error) {
671+
func (c *Client) _DialRegionTLS(ctx context.Context, reg *tailcfg.DERPRegion) (tlsConn *tls.Conn, connClose io.Closer, node *tailcfg.DERPNode, err error) {
672672
tcpConn, node, err := c.dialRegion(ctx, reg)
673673
if err != nil {
674674
return nil, nil, nil, err

derp/derphttp/derphttp_client_mod.go

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package derphttp
2+
3+
import (
4+
"cmp"
5+
"context"
6+
"crypto/tls"
7+
"errors"
8+
"fmt"
9+
"github.com/sagernet/tailscale/net/sockstats"
10+
tailcfg "github.com/sagernet/tailscale/tailcfg"
11+
"io"
12+
"net"
13+
"net/netip"
14+
"time"
15+
)
16+
17+
func (c *Client) DialRegionTLS(ctx context.Context, reg *tailcfg.DERPRegion) (tlsConn *tls.Conn, connClose io.Closer, node *tailcfg.DERPNode, err error) {
18+
if len(reg.Nodes) == 0 {
19+
return nil, nil, nil, fmt.Errorf("no nodes for %s", c.targetString(reg))
20+
}
21+
var firstErr error
22+
for _, n := range reg.Nodes {
23+
if n.STUNOnly {
24+
if firstErr == nil {
25+
firstErr = fmt.Errorf("no non-STUNOnly nodes for %s", c.targetString(reg))
26+
}
27+
continue
28+
}
29+
c, err := c.dialNodeTLS(ctx, n)
30+
if err == nil {
31+
return c, c.NetConn(), n, nil
32+
}
33+
if firstErr == nil {
34+
firstErr = err
35+
}
36+
}
37+
return nil, nil, nil, firstErr
38+
}
39+
40+
func (c *Client) dialNodeTLS(ctx context.Context, n *tailcfg.DERPNode) (*tls.Conn, error) {
41+
type res struct {
42+
c *tls.Conn
43+
err error
44+
}
45+
resc := make(chan res) // must be unbuffered
46+
ctx, cancel := context.WithTimeout(ctx, dialNodeTimeout)
47+
defer cancel()
48+
49+
ctx = sockstats.WithSockStats(ctx, sockstats.LabelDERPHTTPClient, c.logf)
50+
51+
nwait := 0
52+
startDial := func(dstPrimary, proto string) {
53+
nwait++
54+
go func() {
55+
if proto == "tcp4" && c.preferIPv6() {
56+
t, tChannel := c.clock.NewTimer(200 * time.Millisecond)
57+
select {
58+
case <-ctx.Done():
59+
// Either user canceled original context,
60+
// it timed out, or the v6 dial succeeded.
61+
t.Stop()
62+
return
63+
case <-tChannel:
64+
// Start v4 dial
65+
}
66+
}
67+
dst := cmp.Or(dstPrimary, n.HostName)
68+
port := "443"
69+
if !c.useHTTPS() {
70+
port = "3340"
71+
}
72+
if n.DERPPort != 0 {
73+
port = fmt.Sprint(n.DERPPort)
74+
}
75+
conn, err := c.dialContext(ctx, proto, net.JoinHostPort(dst, port))
76+
if err != nil {
77+
select {
78+
case resc <- res{nil, err}:
79+
case <-ctx.Done():
80+
}
81+
return
82+
}
83+
tlsConn := c.tlsClient(conn, n)
84+
err = tlsConn.Handshake()
85+
select {
86+
case resc <- res{tlsConn, err}:
87+
case <-ctx.Done():
88+
if c != nil {
89+
c.Close()
90+
}
91+
}
92+
}()
93+
}
94+
if shouldDialProto(n.IPv4, netip.Addr.Is4) {
95+
startDial(n.IPv4, "tcp4")
96+
}
97+
if shouldDialProto(n.IPv6, netip.Addr.Is6) {
98+
startDial(n.IPv6, "tcp6")
99+
}
100+
if nwait == 0 {
101+
return nil, errors.New("both IPv4 and IPv6 are explicitly disabled for node")
102+
}
103+
104+
var firstErr error
105+
for {
106+
select {
107+
case res := <-resc:
108+
nwait--
109+
if res.err == nil {
110+
return res.c, nil
111+
}
112+
if firstErr == nil {
113+
firstErr = res.err
114+
}
115+
if nwait == 0 {
116+
return nil, firstErr
117+
}
118+
case <-ctx.Done():
119+
return nil, ctx.Err()
120+
}
121+
}
122+
}

ipn/ipnlocal/local.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ type LocalBackend struct {
387387
needsCaptiveDetection chan bool
388388

389389
lookupHook dnscache.LookupHookFunc
390+
onlyTCP443 bool
390391
}
391392

392393
// HealthTracker returns the health tracker for the backend.
@@ -426,7 +427,7 @@ type clientGen func(controlclient.Options) (controlclient.Client, error)
426427
// but is not actually running.
427428
//
428429
// If dialer is nil, a new one is made.
429-
func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, loginFlags controlclient.LoginFlags, lookupHook dnscache.LookupHookFunc) (_ *LocalBackend, err error) {
430+
func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, loginFlags controlclient.LoginFlags, lookupHook dnscache.LookupHookFunc, onlyTCP443 bool) (_ *LocalBackend, err error) {
430431
e := sys.Engine.Get()
431432
store := sys.StateStore.Get()
432433
dialer := sys.Dialer.Get()
@@ -493,6 +494,7 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
493494
captiveCancel: nil, // so that we start checkCaptivePortalLoop when Running
494495
needsCaptiveDetection: make(chan bool),
495496
lookupHook: lookupHook,
497+
onlyTCP443: onlyTCP443,
496498
}
497499
mConn.SetNetInfoCallback(b.setNetInfo)
498500

@@ -1662,7 +1664,7 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
16621664

16631665
b.e.SetNetworkMap(st.NetMap)
16641666
b.MagicConn().SetDERPMap(st.NetMap.DERPMap)
1665-
b.MagicConn().SetOnlyTCP443(st.NetMap.HasCap(tailcfg.NodeAttrOnlyTCP443))
1667+
b.MagicConn().SetOnlyTCP443(b.onlyTCP443 || st.NetMap.HasCap(tailcfg.NodeAttrOnlyTCP443))
16661668

16671669
// Update our cached DERP map
16681670
dnsfallback.UpdateCache(st.NetMap.DERPMap, b.logf)

tsnet/tsnet.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ type Server struct {
126126

127127
Dialer N.Dialer
128128
LookupHook dnscache.LookupHookFunc
129+
OnlyTCP443 bool
129130
DNS dns.OSConfigurator
130131
HTTPClient *http.Client
131132

@@ -625,7 +626,7 @@ func (s *Server) start() (reterr error) {
625626
if s.Ephemeral {
626627
loginFlags = controlclient.LoginEphemeral
627628
}
628-
lb, err := ipnlocal.NewLocalBackend(tsLogf, s.logid, sys, loginFlags|controlclient.LocalBackendStartKeyOSNeutral, s.LookupHook)
629+
lb, err := ipnlocal.NewLocalBackend(tsLogf, s.logid, sys, loginFlags|controlclient.LocalBackendStartKeyOSNeutral, s.LookupHook, s.OnlyTCP443)
629630
if err != nil {
630631
return fmt.Errorf("NewLocalBackend: %v", err)
631632
}

0 commit comments

Comments
 (0)