feat: enhance listener lease management and improve MITM probe handling

Kim committed Apr 15, 2026 at 12:16 UTC 8423099eb96b001d2b87b1aeb474ba9d12b8111f
4 files changed +175 -154
sdk/expose.go
+7 -2
@@ -154,11 +154,16 @@ func (e *Exposure) ActiveRelayURLs() []string {
154
155 func (e *Exposure) Addr() net.Addr {
156 if e.identity.Address == "" {
157 - return listenerAddr("portal:exposure")
157 + return exposureAddr("portal:exposure")
158 }
159 - return listenerAddr("portal:" + e.identity.Address)
159 + return exposureAddr("portal:" + e.identity.Address)
160 }
161
162 +type exposureAddr string
163 +
164 +func (a exposureAddr) Network() string { return "portal" }
165 +func (a exposureAddr) String() string { return string(a) }
166 +
167 func (e *Exposure) Identity() types.Identity {
168 return e.identity
169 }
sdk/listener.go
+138 -109
@@ -54,6 +54,7 @@ type listener struct {
54 identity types.Identity
55 metadata types.LeaseMetadata
56 relaySet *discovery.RelaySet
57 + udpEnabled bool
58 tcpEnabled bool
59 dialTimeout time.Duration
60 requestTimeout time.Duration
@@ -70,13 +71,8 @@ type listener struct {
71 httpClient *http.Client
72 tlsConfig *tls.Config
73
73 - hostname string
74 - udpAddr string
75 - accessToken string
76 - expiresAt time.Time
77 - sniPort int
78 - tenantTLSConfig *tls.Config
79 - tenantTLSCloser io.Closer
74 + leaseMu sync.RWMutex
75 + lease *listenerLease
76 }
77
78 // newListener creates one relay listener and its dedicated relay transport for one relay URL.
@@ -109,6 +105,7 @@ func newListener(ctx context.Context, relayURL string, cfg listenerConfig) (*lis
105 identity: cfg.Identity,
106 metadata: cfg.Metadata,
107 relaySet: cfg.relaySet,
108 + udpEnabled: cfg.UDPEnabled,
109 tcpEnabled: cfg.TCPEnabled,
110 dialTimeout: dialTimeout,
111 requestTimeout: requestTimeout,
@@ -120,7 +117,7 @@ func newListener(ctx context.Context, relayURL string, cfg listenerConfig) (*lis
117 }
118 l.mitmManager = newMITMManager(listenerCtx, l, cfg.BanMITM)
119 l.stream = transport.NewClientStream(readyTarget, handshakeTimeout)
123 - if cfg.UDPEnabled {
120 + if l.udpEnabled {
121 l.datagram = transport.NewClientDatagram(func(err error) {
122 log.Info().
123 Err(err).
@@ -185,9 +182,9 @@ func (l *listener) run(ctx context.Context) {
182 }
183
184 if errors.Is(err, errLeaseRefreshRequired) {
188 - _, _, tenantTLSCloser := l.clearLease("lease refresh required")
189 - if tenantTLSCloser != nil {
190 - _ = tenantTLSCloser.Close()
185 + lease := l.clearLease("lease refresh required")
186 + if lease != nil && lease.tlsCloser != nil {
187 + _ = lease.tlsCloser.Close()
188 }
189 l.resetTransport()
190 continue
@@ -211,7 +208,7 @@ func (l *listener) Close() error {
208 l.cancel()
209 }
210
214 - registered, accessToken, tenantTLSCloser := l.clearLease("")
211 + lease := l.clearLease("")
212
213 if l.stream != nil {
214 l.stream.Drain()
@@ -220,37 +217,52 @@ func (l *listener) Close() error {
217 l.datagram.Close()
218 }
219
223 - if registered && l.identity.Key() != "" && accessToken != "" {
220 + if lease != nil && lease.hostname != "" && l.identity.Key() != "" && lease.accessToken != "" {
221 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
225 - closeErr = errors.Join(closeErr, l.unregisterLease(ctx, accessToken))
222 + closeErr = errors.Join(closeErr, l.unregisterLease(ctx, lease.accessToken))
223 cancel()
224 }
228 - if tenantTLSCloser != nil {
229 - closeErr = errors.Join(closeErr, tenantTLSCloser.Close())
225 + if lease != nil && lease.tlsCloser != nil {
226 + closeErr = errors.Join(closeErr, lease.tlsCloser.Close())
227 }
228 l.resetTransport()
229 })
230 return closeErr
231 }
232
236 -func (l *listener) clearLease(reason string) (bool, string, io.Closer) {
237 - registered := l.hostname != ""
238 - accessToken := l.accessToken
239 - tenantTLSCloser := l.tenantTLSCloser
240 - l.hostname = ""
241 - l.udpAddr = ""
242 - l.accessToken = ""
243 - l.expiresAt = time.Time{}
244 - l.sniPort = 0
245 - l.tenantTLSConfig = nil
246 - l.tenantTLSCloser = nil
233 +type listenerLease struct {
234 + hostname string
235 + udpAddr string
236 + accessToken string
237 + expiresAt time.Time
238 + sniPort int
239 + tlsConfig *tls.Config
240 + tlsCloser io.Closer
241 +}
242 +
243 +func (l *listener) clearLease(reason string) *listenerLease {
244 + l.leaseMu.Lock()
245 + lease := l.lease
246 + l.lease = nil
247 + l.leaseMu.Unlock()
248 +
249 if l.mitmManager != nil {
250 l.mitmManager.reset()
251 }
252 if l.datagram != nil && reason != "" {
253 l.datagram.Clear(reason)
254 }
253 - return registered, accessToken, tenantTLSCloser
255 + return lease
256 +}
257 +
258 +func (l *listener) leaseSnapshot() (listenerLease, bool) {
259 + l.leaseMu.RLock()
260 + defer l.leaseMu.RUnlock()
261 +
262 + if l.lease == nil {
263 + return listenerLease{}, false
264 + }
265 + return *l.lease, true
266 }
267
268 func (l *listener) Accept() (net.Conn, error) {
@@ -274,7 +286,7 @@ func (l *listener) Accept() (net.Conn, error) {
286 if handled {
287 continue
288 }
277 - return wrapMITMProbeConn(l.mitmManager, nextConn), nil
289 + return &mitmProbeConn{Conn: nextConn, manager: l.mitmManager}, nil
290 }
291 }
292
@@ -289,7 +301,9 @@ func (l *listener) acceptDatagram() (types.DatagramFrame, error) {
301 }
302
303 frame.Payload = append([]byte(nil), frame.Payload...)
292 - frame.UDPAddr = l.udpAddr
304 + if lease, ok := l.leaseSnapshot(); ok {
305 + frame.UDPAddr = lease.udpAddr
306 + }
307 frame.Address = l.identity.Address
308 if l.relayURL != nil {
309 frame.RelayURL = l.relayURL.String()
@@ -316,8 +330,12 @@ func (l *listener) datagramReady() (string, bool, bool) {
330 return "", false, false
331 }
332
319 - hostname := l.hostname
320 - udpAddr := l.udpAddr
333 + hostname := ""
334 + udpAddr := ""
335 + if lease, ok := l.leaseSnapshot(); ok {
336 + hostname = lease.hostname
337 + udpAddr = lease.udpAddr
338 + }
339 ready := l.datagram.Connected() && udpAddr != ""
340 closed := false
341 select {
@@ -330,11 +348,17 @@ func (l *listener) datagramReady() (string, bool, bool) {
348 }
349
350 func (l *listener) publicURL() string {
333 - if l.relayURL == nil {
351 + lease, ok := l.leaseSnapshot()
352 + if !ok {
353 return ""
354 }
355 + return l.publicURLForHostname(lease.hostname)
356 +}
357
337 - hostname := l.hostname
358 +func (l *listener) publicURLForHostname(hostname string) string {
359 + if l.relayURL == nil {
360 + return ""
361 + }
362 if hostname == "" {
363 return ""
364 }
@@ -355,24 +379,21 @@ func (l *listener) publicURL() string {
379 }
380
381 func (l *listener) runLease(ctx context.Context) error {
358 - registered := l.hostname != ""
359 - tlsConfig := l.tenantTLSConfig
360 - if !registered {
382 + lease, ok := l.leaseSnapshot()
383 + if !ok || lease.hostname == "" {
384 if ctx.Err() != nil {
385 return ctx.Err()
386 }
387 return errLeaseRefreshRequired
388 }
366 - readyTarget := l.readyTarget
367 -
389 leaseCtx, cancel := context.WithCancel(ctx)
390 defer cancel()
391
371 - errCh := make(chan error, max(readyTarget, 1)+1)
372 - if l.stream != nil && readyTarget > 0 {
373 - for range readyTarget {
392 + errCh := make(chan error, max(l.readyTarget, 1)+1)
393 + if l.stream != nil && l.readyTarget > 0 {
394 + for range l.readyTarget {
395 go func() {
375 - if err := l.runReverseSessionLoop(leaseCtx, tlsConfig); err != nil {
396 + if err := l.runReverseSessionLoop(leaseCtx, lease.tlsConfig); err != nil {
397 select {
398 case errCh <- err:
399 case <-leaseCtx.Done():
@@ -381,7 +402,7 @@ func (l *listener) runLease(ctx context.Context) error {
402 }()
403 }
404 }
384 - if l.datagram != nil {
405 + if l.udpEnabled {
406 go l.runDatagramLoop(leaseCtx)
407 }
408 go func() {
@@ -442,7 +463,6 @@ func (l *listener) runDatagramLoop(ctx context.Context) {
463 if l.datagram == nil {
464 return
465 }
445 - address := l.identity.Address
466
467 for {
468 select {
@@ -457,7 +477,7 @@ func (l *listener) runDatagramLoop(ctx context.Context) {
477 log.Info().
478 Err(err).
479 Str("component", "sdk-datagram-plane").
460 - Str("address", address).
480 + Str("address", l.identity.Address).
481 Msg("quic datagram plane unavailable; retrying")
482 if !utils.SleepOrDone(ctx, 2*time.Second) {
483 l.datagram.Clear("lease stopped")
@@ -468,7 +488,7 @@ func (l *listener) runDatagramLoop(ctx context.Context) {
488
489 log.Info().
490 Str("component", "sdk-datagram-plane").
471 - Str("address", address).
491 + Str("address", l.identity.Address).
492 Str("remote_addr", conn.RemoteAddr().String()).
493 Msg("quic tunnel connected")
494
@@ -480,7 +500,7 @@ func (l *listener) runDatagramLoop(ctx context.Context) {
500 log.Info().
501 Err(err).
502 Str("component", "sdk-datagram-plane").
483 - Str("address", address).
503 + Str("address", l.identity.Address).
504 Msg("quic datagram plane did not bind cleanly; retrying")
505 if !utils.SleepOrDone(ctx, time.Second) {
506 return
@@ -502,9 +522,13 @@ func (l *listener) runDatagramLoop(ctx context.Context) {
522 }
523
524 func (l *listener) openReverseSession(ctx context.Context) (net.Conn, error) {
505 - if l.accessToken == "" {
525 + lease, ok := l.leaseSnapshot()
526 + if !ok || lease.accessToken == "" {
527 return nil, errors.New("access token is not available")
528 }
529 + if l.tlsConfig == nil {
530 + return nil, errors.New("relay tls config is unavailable")
531 + }
532
533 dialer := &tls.Dialer{
534 NetDialer: &net.Dialer{Timeout: l.dialTimeout},
@@ -522,7 +546,7 @@ func (l *listener) openReverseSession(ctx context.Context) (net.Conn, error) {
546 Host: l.relayURL.Host,
547 Header: make(http.Header),
548 }
525 - req.Header.Set(types.HeaderAccessToken, l.accessToken)
549 + req.Header.Set(types.HeaderAccessToken, lease.accessToken)
550 req.Header.Set("Connection", "keep-alive")
551
552 if writeErr := req.Write(conn); writeErr != nil {
@@ -547,37 +571,17 @@ func (l *listener) openReverseSession(ctx context.Context) (net.Conn, error) {
571 return wrapBufferedConn(conn, reader), nil
572 }
573
550 -type bufferedConn struct {
551 - net.Conn
552 - reader *bytes.Reader
553 -}
554 -
555 -func wrapBufferedConn(conn net.Conn, reader *bufio.Reader) net.Conn {
556 - if reader == nil || reader.Buffered() == 0 {
557 - return conn
558 - }
559 - buf := make([]byte, reader.Buffered())
560 - if _, err := io.ReadFull(reader, buf); err != nil {
561 - return conn
562 - }
563 - return &bufferedConn{Conn: conn, reader: bytes.NewReader(buf)}
564 -}
565 -
566 -func (c *bufferedConn) Read(p []byte) (int, error) {
567 - if c.reader != nil && c.reader.Len() > 0 {
568 - return c.reader.Read(p)
569 - }
570 - return c.Conn.Read(p)
571 -}
572 -
574 func (l *listener) openQUICSession(ctx context.Context) (*quic.Conn, error) {
574 - if l.accessToken == "" {
575 + lease, ok := l.leaseSnapshot()
576 + if !ok || lease.accessToken == "" {
577 return nil, errors.New("access token is not available")
578 }
577 - if l.sniPort <= 0 {
579 + if lease.sniPort <= 0 {
580 return nil, errors.New("sni port is not available")
581 }
580 -
582 + if l.tlsConfig == nil {
583 + return nil, errors.New("relay tls config is unavailable")
584 + }
585 tlsConf := l.tlsConfig.Clone()
586 tlsConf.NextProtos = []string{"portal-tunnel"}
587
@@ -591,7 +595,7 @@ func (l *listener) openQUICSession(ctx context.Context) (*quic.Conn, error) {
595 if host == "" {
596 host = strings.TrimSpace(l.relayURL.Host)
597 }
594 - dialAddr := net.JoinHostPort(host, fmt.Sprintf("%d", l.sniPort))
598 + dialAddr := net.JoinHostPort(host, fmt.Sprintf("%d", lease.sniPort))
599 conn, err := quic.DialAddr(ctx, dialAddr, tlsConf, quicConf)
600 if err != nil {
601 return nil, fmt.Errorf("quic dial: %w", err)
@@ -604,7 +608,7 @@ func (l *listener) openQUICSession(ctx context.Context) (*quic.Conn, error) {
608 }
609
610 controlMsg := types.QUICControlMessage{
607 - AccessToken: l.accessToken,
611 + AccessToken: lease.accessToken,
612 }
613 if err := json.NewEncoder(stream).Encode(controlMsg); err != nil {
614 _ = conn.CloseWithError(1, "control write failed")
@@ -683,14 +687,13 @@ func (l *listener) runRenewLoop(ctx context.Context) error {
687 }
688
689 func (l *listener) renewLease(ctx context.Context) error {
686 - expiresAt := l.expiresAt
687 - accessToken := l.accessToken
688 - if accessToken == "" || !time.Now().Before(expiresAt) {
690 + lease, ok := l.leaseSnapshot()
691 + if !ok || lease.accessToken == "" || !time.Now().Before(lease.expiresAt) {
692 return errLeaseRefreshRequired
693 }
694
695 requestCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
693 - resp, err := l.renewRegisteredLease(requestCtx, l.leaseTTL, accessToken)
696 + resp, err := l.renewRegisteredLease(requestCtx, l.leaseTTL, lease.accessToken)
697 cancel()
698 if err != nil {
699 if errors.Is(err, &types.APIRequestError{Code: types.APIErrorCodeLeaseNotFound}) {
@@ -703,10 +706,16 @@ func (l *listener) renewLease(ctx context.Context) error {
706 if resp.AccessToken == "" {
707 return errors.New("relay did not return renewed access token")
708 }
706 - if l.accessToken == accessToken {
707 - l.accessToken = resp.AccessToken
708 - l.expiresAt = resp.ExpiresAt
709 + l.leaseMu.Lock()
710 + if l.lease == nil || l.lease.accessToken != lease.accessToken {
711 + l.leaseMu.Unlock()
712 + return errLeaseRefreshRequired
713 }
714 + next := *l.lease
715 + next.accessToken = resp.AccessToken
716 + next.expiresAt = resp.ExpiresAt
717 + l.lease = &next
718 + l.leaseMu.Unlock()
719 return nil
720 }
721
@@ -715,7 +724,7 @@ func (l *listener) registerAndConfigure(ctx context.Context) error {
724 return err
725 }
726
718 - resp, err := l.registerLease(ctx, l.leaseTTL, l.datagram != nil, l.tcpEnabled)
727 + resp, err := l.registerLease(ctx, l.leaseTTL, l.udpEnabled, l.tcpEnabled)
728 if err != nil {
729 return err
730 }
@@ -732,14 +741,14 @@ func (l *listener) registerAndConfigure(ctx context.Context) error {
741 _ = l.unregisterLease(context.Background(), resp.AccessToken)
742 return errors.New("relay returned mismatched lease identity")
743 }
735 - if l.datagram != nil && !resp.UDPEnabled {
744 + if l.udpEnabled && !resp.UDPEnabled {
745 _ = l.unregisterLease(context.Background(), resp.AccessToken)
746 return &types.APIRequestError{
747 Code: types.APIErrorCodeFeatureUnavailable,
748 Message: "relay did not enable required udp support",
749 }
750 }
742 - if l.datagram != nil && resp.SNIPort <= 0 {
751 + if l.udpEnabled && resp.SNIPort <= 0 {
752 _ = l.unregisterLease(context.Background(), resp.AccessToken)
753 return errors.New("relay did not return sni port for udp transport")
754 }
@@ -756,24 +765,26 @@ func (l *listener) registerAndConfigure(ctx context.Context) error {
765 }
766 return ctx.Err()
767 }
759 - datagram := l.datagram
760 - oldCloser := l.tenantTLSCloser
761 - l.hostname = resp.Hostname
762 - l.udpAddr = resp.UDPAddr
763 - l.accessToken = resp.AccessToken
764 - l.expiresAt = resp.ExpiresAt
765 - if datagram != nil {
766 - l.sniPort = resp.SNIPort
767 - } else {
768 - l.sniPort = 0
769 - }
770 - l.tenantTLSConfig = tlsConf
771 - l.tenantTLSCloser = tenantTLSCloser
772 - if oldCloser != nil {
773 - _ = oldCloser.Close()
774 - }
775 - if datagram != nil {
776 - datagram.Clear("lease updated")
768 + next := &listenerLease{
769 + hostname: resp.Hostname,
770 + udpAddr: resp.UDPAddr,
771 + accessToken: resp.AccessToken,
772 + expiresAt: resp.ExpiresAt,
773 + tlsConfig: tlsConf,
774 + tlsCloser: tenantTLSCloser,
775 + }
776 + if l.udpEnabled {
777 + next.sniPort = resp.SNIPort
778 + }
779 + l.leaseMu.Lock()
780 + oldLease := l.lease
781 + l.lease = next
782 + l.leaseMu.Unlock()
783 + if oldLease != nil && oldLease.tlsCloser != nil {
784 + _ = oldLease.tlsCloser.Close()
785 + }
786 + if l.udpEnabled && l.datagram != nil {
787 + l.datagram.Clear("lease updated")
788 }
789 relayURL := l.relayURL.String()
790 if l.relaySet != nil && relayURL != "" {
@@ -823,7 +834,25 @@ func (l *listener) waitRetry(ctx context.Context, operation string, err error, r
834 return utils.SleepOrDone(ctx, l.retryWait)
835 }
836
826 -type listenerAddr string
837 +type bufferedConn struct {
838 + net.Conn
839 + reader *bytes.Reader
840 +}
841
828 -func (a listenerAddr) Network() string { return "portal" }
829 -func (a listenerAddr) String() string { return string(a) }
842 +func wrapBufferedConn(conn net.Conn, reader *bufio.Reader) net.Conn {
843 + if reader == nil || reader.Buffered() == 0 {
844 + return conn
845 + }
846 + buf := make([]byte, reader.Buffered())
847 + if _, err := io.ReadFull(reader, buf); err != nil {
848 + return conn
849 + }
850 + return &bufferedConn{Conn: conn, reader: bytes.NewReader(buf)}
851 +}
852 +
853 +func (c *bufferedConn) Read(p []byte) (int, error) {
854 + if c.reader != nil && c.reader.Len() > 0 {
855 + return c.reader.Read(p)
856 + }
857 + return c.Conn.Read(p)
858 +}
sdk/mitm.go
+24 -34
@@ -41,12 +41,7 @@ type MITMProbeReport struct {
41
42 type mitmProbePending struct {
43 expected []byte
44 - resultCh chan mitmProbeResult
45 -}
46 -
47 -type mitmProbeResult struct {
48 - matched bool
49 - reason string
44 + resultCh chan string
45 }
46
47 type mitmManager struct {
@@ -83,15 +78,19 @@ func (m *mitmManager) probeTLSPassthrough(ctx context.Context) (MITMProbeReport,
78 return MITMProbeReport{}, errors.New("listener is not ready")
79 }
80
86 - publicURL := l.publicURL()
87 - if publicURL == "" {
81 + lease, ok := l.leaseSnapshot()
82 + if !ok {
83 return MITMProbeReport{}, errors.New("listener is not registered")
84 }
90 -
91 - if l.hostname == "" {
85 + if lease.hostname == "" {
86 return MITMProbeReport{}, errors.New("listener hostname is unavailable")
87 }
88
89 + publicURL := l.publicURLForHostname(lease.hostname)
90 + if publicURL == "" {
91 + return MITMProbeReport{}, errors.New("listener is not registered")
92 + }
93 +
94 report := MITMProbeReport{
95 RelayURL: l.relayURL.String(),
96 PublicURL: publicURL,
@@ -113,14 +112,14 @@ func (m *mitmManager) probeTLSPassthrough(ctx context.Context) (MITMProbeReport,
112 }
113
114 probeTLSConf := &tls.Config{
116 - ServerName: l.hostname,
115 + ServerName: lease.hostname,
116 InsecureSkipVerify: true,
117 }
119 - if l.tenantTLSConfig != nil {
120 - probeTLSConf.MinVersion = l.tenantTLSConfig.MinVersion
121 - probeTLSConf.MaxVersion = l.tenantTLSConfig.MaxVersion
122 - if len(l.tenantTLSConfig.NextProtos) > 0 {
123 - probeTLSConf.NextProtos = append([]string(nil), l.tenantTLSConfig.NextProtos...)
118 + if lease.tlsConfig != nil {
119 + probeTLSConf.MinVersion = lease.tlsConfig.MinVersion
120 + probeTLSConf.MaxVersion = lease.tlsConfig.MaxVersion
121 + if len(lease.tlsConfig.NextProtos) > 0 {
122 + probeTLSConf.NextProtos = append([]string(nil), lease.tlsConfig.NextProtos...)
123 }
124 }
125
@@ -166,9 +165,9 @@ func (m *mitmManager) probeTLSPassthrough(ctx context.Context) (MITMProbeReport,
165 }
166
167 select {
169 - case result := <-resultCh:
170 - report.Detected = !result.matched
171 - report.Reason = result.reason
168 + case reason := <-resultCh:
169 + report.Detected = reason != ""
170 + report.Reason = reason
171 case <-probeCtx.Done():
172 report.Reason = types.MITMProbeReasonProbeTimeout
173 if !errors.Is(probeCtx.Err(), context.DeadlineExceeded) {
@@ -334,11 +333,11 @@ func (m *mitmManager) maybeHandleConn(conn net.Conn) (net.Conn, bool, error) {
333 return nil, true, nil
334 }
335
337 -func (m *mitmManager) startProbe(nonce string, expected []byte) (<-chan mitmProbeResult, func()) {
336 +func (m *mitmManager) startProbe(nonce string, expected []byte) (<-chan string, func()) {
337 m.mu.Lock()
338 state := &mitmProbePending{
339 expected: append([]byte(nil), expected...),
341 - resultCh: make(chan mitmProbeResult, 1),
340 + resultCh: make(chan string, 1),
341 }
342 m.pending[nonce] = state
343 m.mu.Unlock()
@@ -358,26 +357,17 @@ func (m *mitmManager) completeProbe(nonce string, actual []byte) {
357 return
358 }
359
361 - result := mitmProbeResult{
362 - matched: bytes.Equal(state.expected, actual),
363 - }
364 - if !result.matched {
365 - result.reason = types.MITMProbeReasonExporterMismatch
360 + reason := ""
361 + if !bytes.Equal(state.expected, actual) {
362 + reason = types.MITMProbeReasonExporterMismatch
363 }
364
365 select {
369 - case state.resultCh <- result:
366 + case state.resultCh <- reason:
367 default:
368 }
369 }
370
374 -func wrapMITMProbeConn(manager *mitmManager, conn net.Conn) net.Conn {
375 - if conn == nil {
376 - return conn
377 - }
378 - return &mitmProbeConn{Conn: conn, manager: manager}
379 -}
380 -
371 type mitmProbeConn struct {
372 net.Conn
373 manager *mitmManager
sdk/mitm_test.go
+6 -9
@@ -66,9 +66,9 @@ func TestMITMProbeConnMatchesExporter(t *testing.T) {
66 _ = clientConn.Close()
67
68 select {
69 - case result := <-resultCh:
70 - if !result.matched {
71 - t.Fatalf("probe matched = false, reason = %q", result.reason)
69 + case reason := <-resultCh:
70 + if reason != "" {
71 + t.Fatalf("probe reason = %q, want empty", reason)
72 }
73 case <-time.After(2 * time.Second):
74 t.Fatal("timed out waiting for probe result")
@@ -121,12 +121,9 @@ func TestMITMProbeConnDetectsExporterMismatch(t *testing.T) {
121 _ = clientConn.Close()
122
123 select {
124 - case result := <-resultCh:
125 - if result.matched {
126 - t.Fatal("probe matched = true, want false")
127 - }
128 - if result.reason != types.MITMProbeReasonExporterMismatch {
129 - t.Fatalf("probe reason = %q, want %q", result.reason, types.MITMProbeReasonExporterMismatch)
124 + case reason := <-resultCh:
125 + if reason != types.MITMProbeReasonExporterMismatch {
126 + t.Fatalf("probe reason = %q, want %q", reason, types.MITMProbeReasonExporterMismatch)
127 }
128 case <-time.After(2 * time.Second):
129 t.Fatal("timed out waiting for probe result")