Skip to content

Commit 63d9c7b

Browse files
committed
derp: add Client.LocalAddr method
So magicsock can later ask a DERP connection whether its source IP would've changed if it reconnected. Updates tailscale#3619 Change-Id: Ibc8810340c511d6786b60c78c1a61c09f5800e40 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
1 parent b09000a commit 63d9c7b

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

derp/derp_client.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ import (
1212
"fmt"
1313
"io"
1414
"sync"
15+
"sync/atomic"
1516
"time"
1617

1718
"go4.org/mem"
1819
"golang.org/x/time/rate"
20+
"inet.af/netaddr"
1921
"tailscale.com/types/key"
2022
"tailscale.com/types/logger"
2123
)
@@ -37,8 +39,8 @@ type Client struct {
3739
rate *rate.Limiter // if non-nil, rate limiter to use
3840

3941
// Owned by Recv:
40-
peeked int // bytes to discard on next Recv
41-
readErr error // sticky read error
42+
peeked int // bytes to discard on next Recv
43+
readErr atomic.Value // of error; sticky (set by Recv)
4244
}
4345

4446
// ClientOpt is an option passed to NewClient.
@@ -441,13 +443,14 @@ func (c *Client) Recv() (m ReceivedMessage, err error) {
441443
}
442444

443445
func (c *Client) recvTimeout(timeout time.Duration) (m ReceivedMessage, err error) {
444-
if c.readErr != nil {
445-
return nil, c.readErr
446+
readErr, _ := c.readErr.Load().(error)
447+
if readErr != nil {
448+
return nil, readErr
446449
}
447450
defer func() {
448451
if err != nil {
449452
err = fmt.Errorf("derp.Recv: %w", err)
450-
c.readErr = err
453+
c.readErr.Store(err)
451454
}
452455
}()
453456

@@ -587,3 +590,22 @@ func (c *Client) setSendRateLimiter(sm ServerInfoMessage) {
587590
sm.TokenBucketBytesBurst)
588591
}
589592
}
593+
594+
// LocalAddr returns the TCP connection's local address.
595+
//
596+
// If the client is broken in some previously detectable way, it
597+
// returns an error.
598+
func (c *Client) LocalAddr() (netaddr.IPPort, error) {
599+
readErr, _ := c.readErr.Load().(error)
600+
if readErr != nil {
601+
return netaddr.IPPort{}, readErr
602+
}
603+
if c.nc == nil {
604+
return netaddr.IPPort{}, errors.New("nil conn")
605+
}
606+
a := c.nc.LocalAddr()
607+
if a == nil {
608+
return netaddr.IPPort{}, errors.New("nil addr")
609+
}
610+
return netaddr.ParseIPPort(a.String())
611+
}

derp/derp_server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"math"
2424
"math/big"
2525
"math/rand"
26+
"net"
2627
"net/http"
2728
"os"
2829
"os/exec"
@@ -283,9 +284,8 @@ type PacketForwarder interface {
283284
// It is a defined type so that non-net connections can be used.
284285
type Conn interface {
285286
io.WriteCloser
286-
287+
LocalAddr() net.Addr
287288
// The *Deadline methods follow the semantics of net.Conn.
288-
289289
SetDeadline(time.Time) error
290290
SetReadDeadline(time.Time) error
291291
SetWriteDeadline(time.Time) error

0 commit comments

Comments
 (0)