ipn, wgengine/magicsock: add ipn.Prefs.DisableDERP bool

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/141/head
Brad Fitzpatrick 5 years ago
parent bf704a5218
commit 43e505ac37

@ -167,8 +167,10 @@ func (b *LocalBackend) Start(opts Options) error {
b.notify = opts.Notify b.notify = opts.Notify
b.netMapCache = nil b.netMapCache = nil
persist := b.prefs.Persist persist := b.prefs.Persist
wantDERP := !b.prefs.DisableDERP
b.mu.Unlock() b.mu.Unlock()
b.e.SetDERPEnabled(wantDERP)
b.updateFilter(nil) b.updateFilter(nil)
var err error var err error

@ -53,6 +53,9 @@ type Prefs struct {
// TODO(danderson): remove? // TODO(danderson): remove?
NotepadURLs bool NotepadURLs bool
// DisableDERP prevents DERP from being used.
DisableDERP bool
// The Persist field is named 'Config' in the file for backward // The Persist field is named 'Config' in the file for backward
// compatibility with earlier versions. // compatibility with earlier versions.
// TODO(apenwarr): We should move this out of here, it's not a pref. // TODO(apenwarr): We should move this out of here, it's not a pref.
@ -99,6 +102,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
p.CorpDNS == p2.CorpDNS && p.CorpDNS == p2.CorpDNS &&
p.WantRunning == p2.WantRunning && p.WantRunning == p2.WantRunning &&
p.NotepadURLs == p2.NotepadURLs && p.NotepadURLs == p2.NotepadURLs &&
p.DisableDERP == p2.DisableDERP &&
p.UsePacketFilter == p2.UsePacketFilter && p.UsePacketFilter == p2.UsePacketFilter &&
compareIPNets(p.AdvertiseRoutes, p2.AdvertiseRoutes) && compareIPNets(p.AdvertiseRoutes, p2.AdvertiseRoutes) &&
p.Persist.Equals(p2.Persist) p.Persist.Equals(p2.Persist)

@ -20,7 +20,7 @@ func fieldsOf(t reflect.Type) (fields []string) {
} }
func TestPrefsEqual(t *testing.T) { func TestPrefsEqual(t *testing.T) {
prefsHandles := []string{"ControlURL", "RouteAll", "AllowSingleHosts", "CorpDNS", "WantRunning", "UsePacketFilter", "AdvertiseRoutes", "NotepadURLs", "Persist"} prefsHandles := []string{"ControlURL", "RouteAll", "AllowSingleHosts", "CorpDNS", "WantRunning", "UsePacketFilter", "AdvertiseRoutes", "NotepadURLs", "DisableDERP", "Persist"}
if have := fieldsOf(reflect.TypeOf(Prefs{})); !reflect.DeepEqual(have, prefsHandles) { if have := fieldsOf(reflect.TypeOf(Prefs{})); !reflect.DeepEqual(have, prefsHandles) {
t.Errorf("Prefs.Equal check might be out of sync\nfields: %q\nhandled: %q\n", t.Errorf("Prefs.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
have, prefsHandles) have, prefsHandles)

@ -80,6 +80,7 @@ type Conn struct {
derpRecvCh chan derpReadResult derpRecvCh chan derpReadResult
derpMu sync.Mutex derpMu sync.Mutex
wantDerp bool
privateKey key.Private privateKey key.Private
myDerp int // nearest DERP server; 0 means none/unknown 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
@ -160,6 +161,7 @@ func Listen(opts Options) (*Conn, error) {
epFunc: opts.endpointsFunc(), epFunc: opts.endpointsFunc(),
logf: log.Printf, logf: log.Printf,
addrsByUDP: make(map[udpAddr]*AddrSet), addrsByUDP: make(map[udpAddr]*AddrSet),
wantDerp: true,
derpRecvCh: make(chan derpReadResult), derpRecvCh: make(chan derpReadResult),
udpRecvCh: make(chan udpReadResult), udpRecvCh: make(chan udpReadResult),
} }
@ -263,7 +265,9 @@ func (c *Conn) updateNetInfo() {
// one. // one.
ni.PreferredDERP = c.pickDERPFallback() ni.PreferredDERP = c.pickDERPFallback()
} }
c.setNearestDerp(ni.PreferredDERP) if !c.setNearestDERP(ni.PreferredDERP) {
ni.PreferredDERP = 0
}
// TODO: set link type // TODO: set link type
@ -327,16 +331,19 @@ func (c *Conn) SetNetInfoCallback(fn func(*tailcfg.NetInfo)) {
} }
} }
func (c *Conn) setNearestDerp(derpNum int) (changed bool) { func (c *Conn) setNearestDERP(derpNum int) (wantDERP bool) {
c.derpMu.Lock() c.derpMu.Lock()
defer c.derpMu.Unlock() defer c.derpMu.Unlock()
changed = c.myDerp != derpNum if !c.wantDerp {
if changed && derpNum != 0 { c.myDerp = 0
return false
}
if derpNum != 0 && derpNum != c.myDerp {
// On change, start connecting to it: // On change, start connecting to it:
go c.derpWriteChanOfAddr(&net.UDPAddr{IP: derpMagicIP, Port: derpNum}) go c.derpWriteChanOfAddr(&net.UDPAddr{IP: derpMagicIP, Port: derpNum})
} }
c.myDerp = derpNum c.myDerp = derpNum
return changed return true
} }
// determineEndpoints returns the machine's endpoint addresses. It // determineEndpoints returns the machine's endpoint addresses. It
@ -560,25 +567,30 @@ var errDropDerpPacket = errors.New("too many DERP packets queued; dropping")
// or a fake UDP address representing a DERP server (see derpmap.go). // or a fake UDP address representing a DERP server (see derpmap.go).
// The provided public key identifies the recipient. // The provided public key identifies the recipient.
func (c *Conn) sendAddr(addr *net.UDPAddr, pubKey key.Public, b []byte) error { func (c *Conn) sendAddr(addr *net.UDPAddr, pubKey key.Public, b []byte) error {
if ch := c.derpWriteChanOfAddr(addr); ch != nil { if !addr.IP.Equal(derpMagicIP) {
errc := make(chan error, 1) _, err := c.pconn.WriteTo(b, addr)
return err
}
ch := c.derpWriteChanOfAddr(addr)
if ch == nil {
return nil
}
errc := make(chan error, 1)
select {
case <-c.donec():
return errConnClosed
case ch <- derpWriteRequest{addr, pubKey, b, errc}:
select { select {
case <-c.donec(): case <-c.donec():
return errConnClosed return errConnClosed
case ch <- derpWriteRequest{addr, pubKey, b, errc}: case err := <-errc:
select { return err // usually nil
case <-c.donec():
return errConnClosed
case err := <-errc:
return err // usually nil
}
default:
// Too many writes queued. Drop packet.
return errDropDerpPacket
} }
default:
// Too many writes queued. Drop packet.
return errDropDerpPacket
} }
_, err := c.pconn.WriteTo(b, addr)
return err
} }
// bufferedDerpWritesBeforeDrop is how many packets writes can be // bufferedDerpWritesBeforeDrop is how many packets writes can be
@ -597,6 +609,9 @@ func (c *Conn) derpWriteChanOfAddr(addr *net.UDPAddr) chan<- derpWriteRequest {
} }
c.derpMu.Lock() c.derpMu.Lock()
defer c.derpMu.Unlock() defer c.derpMu.Unlock()
if !c.wantDerp {
return nil
}
if c.privateKey.IsZero() { if c.privateKey.IsZero() {
c.logf("DERP lookup of %v with no private key; ignoring", addr.IP) c.logf("DERP lookup of %v with no private key; ignoring", addr.IP)
return nil return nil
@ -864,6 +879,18 @@ func (c *Conn) SetPrivateKey(privateKey wgcfg.PrivateKey) error {
return nil return nil
} }
// SetDERPEnabled controls whether DERP is used.
// New connections have it enabled by default.
func (c *Conn) SetDERPEnabled(wantDerp bool) {
c.derpMu.Lock()
defer c.derpMu.Unlock()
c.wantDerp = wantDerp
if !wantDerp {
c.closeAllDerpLocked()
}
}
// c.derpMu must be held. // c.derpMu must be held.
func (c *Conn) closeAllDerpLocked() { func (c *Conn) closeAllDerpLocked() {
for _, c := range c.derpConn { for _, c := range c.derpConn {

@ -604,3 +604,7 @@ func (e *userspaceEngine) LinkChange(isExpensive bool) {
func (e *userspaceEngine) SetNetInfoCallback(cb NetInfoCallback) { func (e *userspaceEngine) SetNetInfoCallback(cb NetInfoCallback) {
e.magicConn.SetNetInfoCallback(cb) e.magicConn.SetNetInfoCallback(cb)
} }
func (e *userspaceEngine) SetDERPEnabled(v bool) {
e.magicConn.SetDERPEnabled(v)
}

@ -78,6 +78,9 @@ func (e *watchdogEngine) RequestStatus() {
func (e *watchdogEngine) LinkChange(isExpensive bool) { func (e *watchdogEngine) LinkChange(isExpensive bool) {
e.watchdog("LinkChange", func() { e.wrap.LinkChange(isExpensive) }) e.watchdog("LinkChange", func() { e.wrap.LinkChange(isExpensive) })
} }
func (e *watchdogEngine) SetDERPEnabled(v bool) {
e.watchdog("SetDERPEnabled", func() { e.wrap.SetDERPEnabled(v) })
}
func (e *watchdogEngine) Close() { func (e *watchdogEngine) Close() {
e.watchdog("Close", e.wrap.Close) e.watchdog("Close", e.wrap.Close)
} }

@ -127,6 +127,10 @@ type Engine interface {
// such as mobile data on a phone. // such as mobile data on a phone.
LinkChange(isExpensive bool) LinkChange(isExpensive bool)
// SetDERPEnabled controls whether DERP is enabled.
// It starts enabled by default.
SetDERPEnabled(bool)
// SetNetInfoCallback sets the function to call when a // SetNetInfoCallback sets the function to call when a
// new NetInfo summary is available. // new NetInfo summary is available.
SetNetInfoCallback(NetInfoCallback) SetNetInfoCallback(NetInfoCallback)

Loading…
Cancel
Save