net/tstun: block looped disco traffic

Updates #1526 (maybe fixes? time will tell)

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-09-13 14:21:40 -07:00
committed by Brad Fitzpatrick
parent 3759fb8987
commit dabeda21e0
4 changed files with 82 additions and 0 deletions

View File

@@ -7,6 +7,7 @@
package tstun
import (
"bytes"
"errors"
"fmt"
"io"
@@ -19,7 +20,9 @@ import (
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
"inet.af/netaddr"
"tailscale.com/disco"
"tailscale.com/net/packet"
"tailscale.com/tailcfg"
"tailscale.com/tstime/mono"
"tailscale.com/types/ipproto"
"tailscale.com/types/logger"
@@ -76,6 +79,7 @@ type Wrapper struct {
destIPActivity atomic.Value // of map[netaddr.IP]func()
destMACAtomic atomic.Value // of [6]byte
discoKey atomic.Value // of tailcfg.DiscoKey
// buffer stores the oldest unconsumed packet from tdev.
// It is made a static buffer in order to avoid allocations.
@@ -196,6 +200,30 @@ func (t *Wrapper) SetDestIPActivityFuncs(m map[netaddr.IP]func()) {
t.destIPActivity.Store(m)
}
// SetDiscoKey sets the current discovery key.
//
// It is only used for filtering out bogus traffic when network
// stack(s) get confused; see Issue 1526.
func (t *Wrapper) SetDiscoKey(k tailcfg.DiscoKey) {
t.discoKey.Store(k)
}
// isSelfDisco reports whether packet p
// looks like a Disco packet from ourselves.
// See Issue 1526.
func (t *Wrapper) isSelfDisco(p *packet.Parsed) bool {
if p.IPProto != ipproto.UDP {
return false
}
pkt := p.Payload()
discoSrc, ok := disco.Source(pkt)
if !ok {
return false
}
selfDiscoPub, ok := t.discoKey.Load().(tailcfg.DiscoKey)
return ok && bytes.Equal(selfDiscoPub[:], discoSrc)
}
func (t *Wrapper) Close() error {
var err error
t.closeOnce.Do(func() {
@@ -483,6 +511,16 @@ func (t *Wrapper) filterIn(buf []byte) filter.Response {
}
}
// Issue 1526 workaround: if we see disco packets over
// Tailscale from ourselves, then drop them, as that shouldn't
// happen unless a networking stack is confused, as it seems
// macOS in Network Extension mode might be.
if p.IPProto == ipproto.UDP && // disco is over UDP; avoid isSelfDisco call for TCP/etc
t.isSelfDisco(p) {
t.logf("[unexpected] received self disco package over tstun; dropping")
return filter.DropSilently
}
if t.PreFilterIn != nil {
if res := t.PreFilterIn(p, t); res.IsDrop() {
return res