wgengine/magicsock: start tracking nearest DERP node

pull/142/head
Brad Fitzpatrick 5 years ago
parent dbc99dc0d2
commit 724c37fb41

@ -9,20 +9,28 @@ import (
"net" "net"
) )
// derpFakeIPStr is a fake WireGuard endpoint IP address that means // DerpMagicIP is a fake WireGuard endpoint IP address that means
// to use DERP. When used, the port number of the WireGuard endpoint // to use DERP. When used, the port number of the WireGuard endpoint
// is the DERP server number to use. // is the DERP server number to use.
const derpMagicIPStr = "127.3.3.40" // 3340 are above the keys DERP on the keyboard //
var derpMagicIP = net.IPv4(127, 3, 3, 40) // net.IP version of above // Mnemonic: 3.3.40 are numbers above the keys D, E, R, P.
const DerpMagicIP = "127.3.3.40"
var derpMagicIP = net.ParseIP(DerpMagicIP).To4()
var ( var (
derpHostOfIndex = map[int]string{} // index (fake port number) -> hostname derpHostOfIndex = map[int]string{} // index (fake port number) -> hostname
derpIndexOfHost = map[string]int{} // derpHostOfIndex reversed derpIndexOfHost = map[string]int{} // derpHostOfIndex reversed
) )
const (
derpNYC = 1
derpSF = 2
)
func init() { func init() {
// Just one zone for now: addDerper(derpNYC, "derp.tailscale.com")
addDerper(1, "derp.tailscale.com") addDerper(derpSF, "derp2.tailscale.com")
} }
func addDerper(i int, host string) { func addDerper(i int, host string) {

@ -71,6 +71,7 @@ type Conn struct {
derpMu sync.Mutex derpMu sync.Mutex
privateKey key.Private privateKey key.Private
myDerp int // nearest DERP server; 0 means none/unknown
derpConn map[int]*derphttp.Client // magic derp port (see derpmap.go) to its client derpConn map[int]*derphttp.Client // magic derp port (see derpmap.go) to its client
derpCancel map[int]context.CancelFunc // to close derp goroutines derpCancel map[int]context.CancelFunc // to close derp goroutines
derpWriteCh map[int]chan<- derpWriteRequest derpWriteCh map[int]chan<- derpWriteRequest
@ -203,25 +204,40 @@ func (c *Conn) epUpdate(ctx context.Context) {
go func() { go func() {
defer close(lastDone) defer close(lastDone)
endpoints, err := c.determineEndpoints(epCtx) nearestDerp, endpoints, err := c.determineEndpoints(epCtx)
if err != nil { if err != nil {
c.logf("magicsock.Conn: endpoint update failed: %v", err) c.logf("magicsock.Conn: endpoint update failed: %v", err)
// TODO(crawshaw): are there any conditions under which // TODO(crawshaw): are there any conditions under which
// we should trigger a retry based on the error here? // we should trigger a retry based on the error here?
return return
} }
if stringsEqual(endpoints, lastEndpoints) { derpChanged := c.setNearestDerp(nearestDerp)
if stringsEqual(endpoints, lastEndpoints) && !derpChanged {
return return
} }
lastEndpoints = endpoints lastEndpoints = endpoints
// TODO(bradfiz): get nearestDerp back to ipn for a HostInfo update
c.epFunc(endpoints) c.epFunc(endpoints)
}() }()
} }
} }
func (c *Conn) setNearestDerp(derpNum int) (changed bool) {
c.derpMu.Lock()
defer c.derpMu.Unlock()
changed = c.myDerp != derpNum
if changed && derpNum != 0 {
// On change, start connecting to it:
go c.derpWriteChanOfAddr(&net.UDPAddr{IP: derpMagicIP, Port: derpNum})
}
c.myDerp = derpNum
return changed
}
// determineEndpoints returns the machine's endpoint addresses. It // determineEndpoints returns the machine's endpoint addresses. It
// does a STUN lookup to determine its public address. // does a STUN lookup to determine its public address.
func (c *Conn) determineEndpoints(ctx context.Context) ([]string, error) { func (c *Conn) determineEndpoints(ctx context.Context) (nearestDerp int, ipPorts []string, err error) {
nearestDerp = derpNYC // for now
var ( var (
alreadyMu sync.Mutex alreadyMu sync.Mutex
already = make(map[string]bool) // endpoint -> true already = make(map[string]bool) // endpoint -> true
@ -249,7 +265,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]string, error) {
c.stunReceiveFunc.Store(s.Receive) c.stunReceiveFunc.Store(s.Receive)
if err := s.Run(ctx); err != nil { if err := s.Run(ctx); err != nil {
return nil, err return 0, nil, err
} }
c.ignoreSTUNPackets() c.ignoreSTUNPackets()
@ -257,7 +273,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]string, error) {
if localAddr := c.pconn.LocalAddr(); localAddr.IP.IsUnspecified() { if localAddr := c.pconn.LocalAddr(); localAddr.IP.IsUnspecified() {
ips, loopback, err := interfaces.LocalAddresses() ips, loopback, err := interfaces.LocalAddresses()
if err != nil { if err != nil {
return nil, err return 0, nil, err
} }
reason := "localAddresses" reason := "localAddresses"
if len(ips) == 0 { if len(ips) == 0 {
@ -287,7 +303,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]string, error) {
// The STUN address(es) are always first so that legacy wireguard // The STUN address(es) are always first so that legacy wireguard
// can use eps[0] as its only known endpoint address (although that's // can use eps[0] as its only known endpoint address (although that's
// obviously non-ideal). // obviously non-ideal).
return eps, nil return nearestDerp, eps, nil
} }
func stringsEqual(x, y []string) bool { func stringsEqual(x, y []string) bool {
@ -496,7 +512,7 @@ func (c *Conn) derpWriteChanOfAddr(addr *net.UDPAddr) chan<- derpWriteRequest {
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
// TODO: close derp channels (if addr.Port != myDerp) on inactivity timer
bidiCh := make(chan derpWriteRequest, bufferedDerpWritesBeforeDrop) bidiCh := make(chan derpWriteRequest, bufferedDerpWritesBeforeDrop)
ch = bidiCh ch = bidiCh
c.derpConn[addr.Port] = dc c.derpConn[addr.Port] = dc

@ -73,7 +73,10 @@ func pickPort(t *testing.T) uint16 {
} }
func TestDerpIPConstant(t *testing.T) { func TestDerpIPConstant(t *testing.T) {
if derpMagicIPStr != derpMagicIP.String() { if DerpMagicIP != derpMagicIP.String() {
t.Errorf("str %q != IP %v", derpMagicIPStr, derpMagicIP) t.Errorf("str %q != IP %v", DerpMagicIP, derpMagicIP)
}
if len(derpMagicIP) != 4 {
t.Errorf("derpMagicIP is len %d; want 4", len(derpMagicIP))
} }
} }

Loading…
Cancel
Save