From 34e459ac1e876e6508f7527f3a6902b2f587435f Mon Sep 17 00:00:00 2001 From: Mike O'Driscoll Date: Tue, 1 Apr 2025 14:36:47 -0400 Subject: [PATCH 1/3] cmd/derper,derp: add DERP mesh port isolation Add support to only allow derp mesh frames a specific port. Fixes #26312 Signed-off-by: Mike O'Driscoll --- cmd/derper/derper.go | 49 ++++++++++++++++++++++++++++++++++++++++++-- derp/derp_server.go | 28 ++++++++++++++++++++----- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/cmd/derper/derper.go b/cmd/derper/derper.go index 3c6fda68c..445b9c0a2 100644 --- a/cmd/derper/derper.go +++ b/cmd/derper/derper.go @@ -58,6 +58,7 @@ var ( dev = flag.Bool("dev", false, "run in localhost development mode (overrides -a)") versionFlag = flag.Bool("version", false, "print version and exit") addr = flag.String("a", ":443", "server HTTP/HTTPS listen address, in form \":port\", \"ip:port\", or for IPv6 \"[ip]:port\". If the IP is omitted, it defaults to all interfaces. Serves HTTPS if the port is 443 and/or -certmode is manual, otherwise HTTP.") + meshAddr = flag.String("mesh-addr", "", "optional, Specify a separate http/https listen address for mesh connections, if unset, mesh will use address specified in 'a'") httpPort = flag.Int("http-port", 80, "The port on which to serve HTTP. Set to -1 to disable. The listener is bound to the same IP (if any) as specified in the -a flag.") stunPort = flag.Int("stun-port", 3478, "The UDP port on which to serve STUN. The listener is bound to the same IP (if any) as specified in the -a flag.") configPath = flag.String("c", "", "config file path") @@ -203,6 +204,13 @@ func main() { s.SetVerifyClientURL(*verifyClientURL) s.SetVerifyClientURLFailOpen(*verifyFailOpen) s.SetTCPWriteTimeout(*tcpWriteTimeout) + if *meshAddr != "" { + _, port, err := net.SplitHostPort(*meshAddr) + if err != nil { + log.Fatalf("failed to parse mesh port addr %s: %v", *meshAddr, err) + } + s.SetMeshPort(port) + } var meshKey string if *dev { @@ -345,9 +353,23 @@ func main() { ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, } + var meshSrv *http.Server + if *meshAddr != "" { + // Same as httpsrv above, different port. + meshSrv = &http.Server{ + Addr: *meshAddr, + Handler: mux, + ErrorLog: quietLogger, + ReadTimeout: 30 * time.Second, + WriteTimeout: 30 * time.Second, + } + } go func() { <-ctx.Done() httpsrv.Shutdown(ctx) + if meshSrv != nil { + meshSrv.Shutdown(ctx) + } }() if serveTLS { @@ -359,7 +381,7 @@ func main() { } httpsrv.TLSConfig = certManager.TLSConfig() getCert := httpsrv.TLSConfig.GetCertificate - httpsrv.TLSConfig.GetCertificate = func(hi *tls.ClientHelloInfo) (*tls.Certificate, error) { + certFunc := func(hi *tls.ClientHelloInfo) (*tls.Certificate, error) { cert, err := getCert(hi) if err != nil { return nil, err @@ -367,9 +389,10 @@ func main() { cert.Certificate = append(cert.Certificate, s.MetaCert()) return cert, nil } + httpsrv.TLSConfig.GetCertificate = certFunc // Disable TLS 1.0 and 1.1, which are obsolete and have security issues. httpsrv.TLSConfig.MinVersion = tls.VersionTLS12 - httpsrv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.TLS != nil { label := "unknown" switch r.TLS.Version { @@ -389,6 +412,17 @@ func main() { mux.ServeHTTP(w, r) }) + httpsrv.Handler = handlerFunc + + if meshSrv != nil { + go func() { + meshSrv.TLSConfig = certManager.TLSConfig() + meshSrv.TLSConfig.GetCertificate = certFunc + meshSrv.TLSConfig.MinVersion = tls.VersionTLS12 + meshSrv.Handler = handlerFunc + err = rateLimitedListenAndServeTLS(meshSrv, &lc) + }() + } if *httpPort > -1 { go func() { port80mux := http.NewServeMux() @@ -420,6 +454,17 @@ func main() { } err = rateLimitedListenAndServeTLS(httpsrv, &lc) } else { + if meshSrv != nil { + go func() { + log.Printf("derper: starting mesh on %s", *meshAddr) + var lnm net.Listener + lnm, err = lc.Listen(context.Background(), "tcp", *meshAddr) + if err != nil { + log.Fatal(err) + } + err = meshSrv.Serve(lnm) + }() + } log.Printf("derper: serving on %s", *addr) var ln net.Listener ln, err = lc.Listen(context.Background(), "tcp", httpsrv.Addr) diff --git a/derp/derp_server.go b/derp/derp_server.go index c330572d2..7811cbd93 100644 --- a/derp/derp_server.go +++ b/derp/derp_server.go @@ -23,6 +23,7 @@ import ( "math" "math/big" "math/rand/v2" + "net" "net/http" "net/netip" "os" @@ -133,6 +134,7 @@ type Server struct { logf logger.Logf memSys0 uint64 // runtime.MemStats.Sys at start (or early-ish) meshKey string + meshPort string limitedLogf logger.Logf metaCert []byte // the encoded x509 cert to send after LetsEncrypt cert+intermediate dupPolicy dupPolicy @@ -503,6 +505,10 @@ func (s *Server) SetTCPWriteTimeout(d time.Duration) { s.tcpWriteTimeout = d } +func (s *Server) SetMeshPort(port string) { + s.meshPort = port +} + // HasMeshKey reports whether the server is configured with a mesh key. func (s *Server) HasMeshKey() bool { return s.meshKey != "" } @@ -900,6 +906,8 @@ func (s *Server) accept(ctx context.Context, nc Conn, brw *bufio.ReadWriter, rem return fmt.Errorf("receive client key: %v", err) } + _, localPort, _ := net.SplitHostPort(nc.LocalAddr().String()) + remoteIPPort, _ := netip.ParseAddrPort(remoteAddr) if err := s.verifyClient(ctx, clientKey, clientInfo, remoteIPPort.Addr()); err != nil { return fmt.Errorf("client %v rejected: %v", clientKey, err) @@ -926,7 +934,7 @@ func (s *Server) accept(ctx context.Context, nc Conn, brw *bufio.ReadWriter, rem discoSendQueue: make(chan pkt, s.perClientSendQueueDepth), sendPongCh: make(chan [8]byte, 1), peerGone: make(chan peerGoneMsg), - canMesh: s.isMeshPeer(clientInfo), + canMesh: s.hasMeshPSK(clientInfo) && s.usingMeshPort(localPort), isNotIdealConn: IdealNodeContextKey.Value(ctx) != "", peerGoneLim: rate.NewLimiter(rate.Every(time.Second), 3), } @@ -1331,16 +1339,26 @@ func (c *sclient) requestMeshUpdate() { } } -// isMeshPeer reports whether the client is a trusted mesh peer -// node in the DERP region. -func (s *Server) isMeshPeer(info *clientInfo) bool { +// hasMeshPSK reports whether the client provides +// a matching pre-shared key and can be trusted. +func (s *Server) hasMeshPSK(info *clientInfo) bool { return info != nil && info.MeshKey != "" && info.MeshKey == s.meshKey } +// usingMeshPort reports if the given port is +// authorized for mesh connections. +func (s *Server) usingMeshPort(port string) bool { + if s.meshPort == "" { + return true + } + + return s.meshPort == port +} + // verifyClient checks whether the client is allowed to connect to the derper, // depending on how & whether the server's been configured to verify. func (s *Server) verifyClient(ctx context.Context, clientKey key.NodePublic, info *clientInfo, clientIP netip.Addr) error { - if s.isMeshPeer(info) { + if s.hasMeshPSK(info) { // Trusted mesh peer. No need to verify further. In fact, verifying // further wouldn't work: it's not part of the tailnet so tailscaled and // likely the admission control URL wouldn't know about it. From 16d67ca9f9d43dc6ebda14ac70078cbdd21010b3 Mon Sep 17 00:00:00 2001 From: Mike O'Driscoll Date: Mon, 24 Mar 2025 14:55:14 -0400 Subject: [PATCH 2/3] cmd/derpprobe,prober: add mesh key flag to derpprobe Add and pass the mesh key to derpprobe for probing derpers with verify set to true. Fixes tailscale/corp#27294 Signed-off-by: Mike O'Driscoll --- cmd/derpprobe/derpprobe.go | 61 ++++++++++++++++++++++++++++++++++++++ prober/derp.go | 40 +++++++++++++++---------- 2 files changed, 85 insertions(+), 16 deletions(-) diff --git a/cmd/derpprobe/derpprobe.go b/cmd/derpprobe/derpprobe.go index 899838462..5661c3d5a 100644 --- a/cmd/derpprobe/derpprobe.go +++ b/cmd/derpprobe/derpprobe.go @@ -5,13 +5,18 @@ package main import ( + "context" "flag" "fmt" "log" "net/http" + "os" + "path" + "path/filepath" "sort" "time" + "github.com/tailscale/setec/client/setec" "tailscale.com/prober" "tailscale.com/tsweb" "tailscale.com/version" @@ -20,7 +25,15 @@ import ( _ "tailscale.com/tsweb/promvarz" ) +const meshKeyEnvVar = "TAILSCALE_DERPER_MESH_KEY" +const setecMeshKeyName = "meshkey" + +func defaultSetecCacheDir() string { + return filepath.Join(os.Getenv("HOME"), ".cache", "derper-secrets") +} + var ( + dev = flag.Bool("dev", false, "run in localhost development mode") derpMapURL = flag.String("derp-map", "https://login.tailscale.com/derpmap/default", "URL to DERP map (https:// or file://) or 'local' to use the local tailscaled's DERP map") versionFlag = flag.Bool("version", false, "print version and exit") listen = flag.String("listen", ":8030", "HTTP listen address") @@ -36,6 +49,10 @@ var ( qdPacketsPerSecond = flag.Int("qd-packets-per-second", 0, "if greater than 0, queuing delay will be measured continuously using 260 byte packets (approximate size of a CallMeMaybe packet) sent at this rate per second") qdPacketTimeout = flag.Duration("qd-packet-timeout", 5*time.Second, "queuing delay packets arriving after this period of time from being sent are treated like dropped packets and don't count toward queuing delay timings") regionCodeOrID = flag.String("region-code", "", "probe only this region (e.g. 'lax' or '17'); if left blank, all regions will be probed") + meshPSKFile = flag.String("mesh-psk-file", "", "if non-empty, path to file containing the mesh pre-shared key file. It should contain some hex string; whitespace is trimmed.") + secretsURL = flag.String("secrets-url", "", "SETEC server URL for secrets retrieval of mesh key") + secretPrefix = flag.String("secrets-path-prefix", "prod/derp", "setec path prefix for \""+setecMeshKeyName+"\" secret for DERP mesh key") + secretsCacheDir = flag.String("secrets-cache-dir", defaultSetecCacheDir(), "directory to cache setec secrets in (required if --secrets-url is set)") ) func main() { @@ -51,6 +68,7 @@ func main() { prober.WithSTUNProbing(*stunInterval), prober.WithTLSProbing(*tlsInterval), prober.WithQueuingDelayProbing(*qdPacketsPerSecond, *qdPacketTimeout), + prober.WithMeshKey(getMeshKey()), } if *bwInterval > 0 { opts = append(opts, prober.WithBandwidthProbing(*bwInterval, *bwSize, *bwTUNIPv4Address)) @@ -95,6 +113,49 @@ func main() { log.Fatal(http.ListenAndServe(*listen, mux)) } +func getMeshKey() string { + var meshKey string + + if *dev { + meshKey = os.Getenv(meshKeyEnvVar) + if meshKey == "" { + log.Printf("No mesh key specified for dev via %s\n", meshKeyEnvVar) + } else { + log.Printf("Set mesh key from %s\n", meshKeyEnvVar) + } + } else if *secretsURL != "" { + meshKeySecret := path.Join(*secretPrefix, setecMeshKeyName) + fc, err := setec.NewFileCache(*secretsCacheDir) + if err != nil { + log.Fatalf("NewFileCache: %v", err) + } + log.Printf("Setting up setec store from %q", *secretsURL) + st, err := setec.NewStore(context.Background(), + setec.StoreConfig{ + Client: setec.Client{Server: *secretsURL}, + Secrets: []string{ + meshKeySecret, + }, + Cache: fc, + }) + if err != nil { + log.Fatalf("NewStore: %v", err) + } + meshKey = st.Secret(meshKeySecret).GetString() + log.Println("Got mesh key from setec store") + st.Close() + } else if *meshPSKFile != "" { + b, err := setec.StaticFile(*meshPSKFile) + if err != nil { + log.Fatalf("StaticFile failed to get key: %v", err) + } + log.Println("Got mesh key from static file") + meshKey = b.GetString() + } + + return meshKey +} + type overallStatus struct { good, bad []string } diff --git a/prober/derp.go b/prober/derp.go index 98e61ff54..9c91fdb9b 100644 --- a/prober/derp.go +++ b/prober/derp.go @@ -47,6 +47,7 @@ import ( type derpProber struct { p *Prober derpMapURL string // or "local" + meshKey string udpInterval time.Duration meshInterval time.Duration tlsInterval time.Duration @@ -71,7 +72,7 @@ type derpProber struct { udpProbeFn func(string, int) ProbeClass meshProbeFn func(string, string) ProbeClass bwProbeFn func(string, string, int64) ProbeClass - qdProbeFn func(string, string, int, time.Duration) ProbeClass + qdProbeFn func(string, string, int, time.Duration, string) ProbeClass sync.Mutex lastDERPMap *tailcfg.DERPMap @@ -143,6 +144,12 @@ func WithRegionCodeOrID(regionCode string) DERPOpt { } } +func WithMeshKey(meshKey string) DERPOpt { + return func(d *derpProber) { + d.meshKey = meshKey + } +} + // DERP creates a new derpProber. // // If derpMapURL is "local", the DERPMap is fetched via @@ -250,7 +257,7 @@ func (d *derpProber) probeMapFn(ctx context.Context) error { wantProbes[n] = true if d.probes[n] == nil { log.Printf("adding DERP queuing delay probe for %s->%s (%s)", server.Name, to.Name, region.RegionName) - d.probes[n] = d.p.Run(n, -10*time.Second, labels, d.qdProbeFn(server.Name, to.Name, d.qdPacketsPerSecond, d.qdPacketTimeout)) + d.probes[n] = d.p.Run(n, -10*time.Second, labels, d.qdProbeFn(server.Name, to.Name, d.qdPacketsPerSecond, d.qdPacketTimeout, d.meshKey)) } } } @@ -284,7 +291,7 @@ func (d *derpProber) probeMesh(from, to string) ProbeClass { } dm := d.lastDERPMap - return derpProbeNodePair(ctx, dm, fromN, toN) + return derpProbeNodePair(ctx, dm, fromN, toN, d.meshKey) }, Class: "derp_mesh", Labels: Labels{"derp_path": derpPath}, @@ -308,7 +315,7 @@ func (d *derpProber) probeBandwidth(from, to string, size int64) ProbeClass { if err != nil { return err } - return derpProbeBandwidth(ctx, d.lastDERPMap, fromN, toN, size, &transferTimeSeconds, &totalBytesTransferred, d.bwTUNIPv4Prefix) + return derpProbeBandwidth(ctx, d.lastDERPMap, fromN, toN, size, &transferTimeSeconds, &totalBytesTransferred, d.bwTUNIPv4Prefix, d.meshKey) }, Class: "derp_bw", Labels: Labels{ @@ -336,7 +343,7 @@ func (d *derpProber) probeBandwidth(from, to string, size int64) ProbeClass { // to the queuing delay measurement and are recorded as dropped. 'from' and 'to' are // expected to be names (DERPNode.Name) of two DERP servers in the same region, // and may refer to the same server. -func (d *derpProber) probeQueuingDelay(from, to string, packetsPerSecond int, packetTimeout time.Duration) ProbeClass { +func (d *derpProber) probeQueuingDelay(from, to string, packetsPerSecond int, packetTimeout time.Duration, meshKey string) ProbeClass { derpPath := "mesh" if from == to { derpPath = "single" @@ -349,7 +356,7 @@ func (d *derpProber) probeQueuingDelay(from, to string, packetsPerSecond int, pa if err != nil { return err } - return derpProbeQueuingDelay(ctx, d.lastDERPMap, fromN, toN, packetsPerSecond, packetTimeout, &packetsDropped, qdh) + return derpProbeQueuingDelay(ctx, d.lastDERPMap, fromN, toN, packetsPerSecond, packetTimeout, &packetsDropped, qdh, meshKey) }, Class: "derp_qd", Labels: Labels{"derp_path": derpPath}, @@ -368,15 +375,15 @@ func (d *derpProber) probeQueuingDelay(from, to string, packetsPerSecond int, pa // derpProbeQueuingDelay continuously sends data between two local DERP clients // connected to two DERP servers in order to measure queuing delays. From and to // can be the same server. -func derpProbeQueuingDelay(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode, packetsPerSecond int, packetTimeout time.Duration, packetsDropped *expvar.Float, qdh *histogram) (err error) { +func derpProbeQueuingDelay(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode, packetsPerSecond int, packetTimeout time.Duration, packetsDropped *expvar.Float, qdh *histogram, meshKey string) (err error) { // This probe uses clients with isProber=false to avoid spamming the derper // logs with every packet sent by the queuing delay probe. - fromc, err := newConn(ctx, dm, from, false) + fromc, err := newConn(ctx, dm, from, false, meshKey) if err != nil { return err } defer fromc.Close() - toc, err := newConn(ctx, dm, to, false) + toc, err := newConn(ctx, dm, to, false, meshKey) if err != nil { return err } @@ -674,15 +681,15 @@ func derpProbeUDP(ctx context.Context, ipStr string, port int) error { // DERP clients connected to two DERP servers.If tunIPv4Address is specified, // probes will use a TCP connection over a TUN device at this address in order // to exercise TCP-in-TCP in similar fashion to TCP over Tailscale via DERP. -func derpProbeBandwidth(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode, size int64, transferTimeSeconds, totalBytesTransferred *expvar.Float, tunIPv4Prefix *netip.Prefix) (err error) { +func derpProbeBandwidth(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode, size int64, transferTimeSeconds, totalBytesTransferred *expvar.Float, tunIPv4Prefix *netip.Prefix, meshKey string) (err error) { // This probe uses clients with isProber=false to avoid spamming the derper logs with every packet // sent by the bandwidth probe. - fromc, err := newConn(ctx, dm, from, false) + fromc, err := newConn(ctx, dm, from, false, meshKey) if err != nil { return err } defer fromc.Close() - toc, err := newConn(ctx, dm, to, false) + toc, err := newConn(ctx, dm, to, false, meshKey) if err != nil { return err } @@ -712,13 +719,13 @@ func derpProbeBandwidth(ctx context.Context, dm *tailcfg.DERPMap, from, to *tail // derpProbeNodePair sends a small packet between two local DERP clients // connected to two DERP servers. -func derpProbeNodePair(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode) (err error) { - fromc, err := newConn(ctx, dm, from, true) +func derpProbeNodePair(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode, meshKey string) (err error) { + fromc, err := newConn(ctx, dm, from, true, meshKey) if err != nil { return err } defer fromc.Close() - toc, err := newConn(ctx, dm, to, true) + toc, err := newConn(ctx, dm, to, true, meshKey) if err != nil { return err } @@ -1116,7 +1123,7 @@ func derpProbeBandwidthTUN(ctx context.Context, transferTimeSeconds, totalBytesT return nil } -func newConn(ctx context.Context, dm *tailcfg.DERPMap, n *tailcfg.DERPNode, isProber bool) (*derphttp.Client, error) { +func newConn(ctx context.Context, dm *tailcfg.DERPMap, n *tailcfg.DERPNode, isProber bool, meshKey string) (*derphttp.Client, error) { // To avoid spamming the log with regular connection messages. l := logger.Filtered(log.Printf, func(s string) bool { return !strings.Contains(s, "derphttp.Client.Connect: connecting to") @@ -1132,6 +1139,7 @@ func newConn(ctx context.Context, dm *tailcfg.DERPMap, n *tailcfg.DERPNode, isPr } }) dc.IsProber = isProber + dc.MeshKey = meshKey err := dc.Connect(ctx) if err != nil { return nil, err From 48a12a52e5e1ae1ae6b23cf4bf7959e35a84188c Mon Sep 17 00:00:00 2001 From: Mike O'Driscoll Date: Wed, 2 Apr 2025 13:29:41 -0400 Subject: [PATCH 3/3] foo --- cmd/derper/derper.go | 4 +++- derp/derp_server.go | 8 ++++++++ prober/derp.go | 5 +++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cmd/derper/derper.go b/cmd/derper/derper.go index 445b9c0a2..8eb0a749e 100644 --- a/cmd/derper/derper.go +++ b/cmd/derper/derper.go @@ -510,7 +510,9 @@ func rateLimitedListenAndServeTLS(srv *http.Server, lc *net.ListenConfig) error return err } rln := newRateLimitedListener(ln, rate.Limit(*acceptConnLimit), *acceptConnBurst) - expvar.Publish("tls_listener", rln.ExpVar()) + if expvar.Get("tls_listener") == nil { + expvar.Publish("tls_listener", rln.ExpVar()) + } defer rln.Close() return srv.ServeTLS(rln, "", "") } diff --git a/derp/derp_server.go b/derp/derp_server.go index 7811cbd93..c521fe9b8 100644 --- a/derp/derp_server.go +++ b/derp/derp_server.go @@ -992,6 +992,7 @@ func (c *sclient) run(ctx context.Context) error { c.startStatsLoop(sendCtx) + fmt.Printf("Mike %s : %v\n", c.nc.LocalAddr().String(), c.canMesh) for { ft, fl, err := readFrameHeader(c.br) c.debugLogf("read frame type %d len %d err %v", ft, fl, err) @@ -1007,6 +1008,8 @@ func (c *sclient) run(ctx context.Context) error { return fmt.Errorf("client %s: readFrameHeader: %w", c.key.ShortString(), err) } c.s.noteClientActivity(c) + + fmt.Printf("0x%X\n", ft) switch ft { case frameNotePreferred: err = c.handleFrameNotePreferred(ft, fl) @@ -1162,6 +1165,9 @@ func (c *sclient) handleFrameForwardPacket(ft frameType, fl uint32) error { // handleFrameSendPacket reads a "send packet" frame from the client. func (c *sclient) handleFrameSendPacket(ft frameType, fl uint32) error { + if !c.canMesh { + return fmt.Errorf("insufficient permissions") + } s := c.s dstKey, contents, err := s.recvPacket(c.br, fl) @@ -1352,6 +1358,8 @@ func (s *Server) usingMeshPort(port string) bool { return true } + fmt.Printf("Mike %s/%s\n", s.meshPort, port) + return s.meshPort == port } diff --git a/prober/derp.go b/prober/derp.go index 9c91fdb9b..c2c5a6040 100644 --- a/prober/derp.go +++ b/prober/derp.go @@ -291,6 +291,7 @@ func (d *derpProber) probeMesh(from, to string) ProbeClass { } dm := d.lastDERPMap + fromN.DERPPort = 8888 return derpProbeNodePair(ctx, dm, fromN, toN, d.meshKey) }, Class: "derp_mesh", @@ -720,12 +721,12 @@ func derpProbeBandwidth(ctx context.Context, dm *tailcfg.DERPMap, from, to *tail // derpProbeNodePair sends a small packet between two local DERP clients // connected to two DERP servers. func derpProbeNodePair(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode, meshKey string) (err error) { - fromc, err := newConn(ctx, dm, from, true, meshKey) + fromc, err := newConn(ctx, dm, from, !to.InsecureForTests, meshKey) if err != nil { return err } defer fromc.Close() - toc, err := newConn(ctx, dm, to, true, meshKey) + toc, err := newConn(ctx, dm, to, !from.InsecureForTests, meshKey) if err != nil { return err }