wgengine/tstun/faketun: it's a null tunnel, not a loopback.

At some point faketun got implemented as a loopback (put a packet in
from wireguard, the same packet goes back to wireguard) which is not
useful. It's supposed to be an interface that just sinks all packets,
and then wgengine adds *only* and ICMP Echo responder as a layer on
top.

This caused extremely odd bugs on darwin, where the special case that
reinjects packets from local->local was filling the loopback channel
and creating an infinite loop (which became jammed since the reader and
writer were in the same goroutine).

Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
apenwarr/faketun
Avery Pennarun 4 years ago
parent 3e4c46259d
commit 5041800ac6

@ -12,7 +12,6 @@ import (
) )
type fakeTUN struct { type fakeTUN struct {
datachan chan []byte
evchan chan tun.Event evchan chan tun.Event
closechan chan struct{} closechan chan struct{}
} }
@ -22,7 +21,6 @@ type fakeTUN struct {
// It primarily exists for testing. // It primarily exists for testing.
func NewFakeTUN() tun.Device { func NewFakeTUN() tun.Device {
return &fakeTUN{ return &fakeTUN{
datachan: make(chan []byte),
evchan: make(chan tun.Event), evchan: make(chan tun.Event),
closechan: make(chan struct{}), closechan: make(chan struct{}),
} }
@ -39,22 +37,17 @@ func (t *fakeTUN) Close() error {
} }
func (t *fakeTUN) Read(out []byte, offset int) (int, error) { func (t *fakeTUN) Read(out []byte, offset int) (int, error) {
select { <-t.closechan
case <-t.closechan: return 0, io.EOF
return 0, io.EOF
case b := <-t.datachan:
copy(out[offset:offset+len(b)], b)
return len(b), nil
}
} }
func (t *fakeTUN) Write(b []byte, n int) (int, error) { func (t *fakeTUN) Write(b []byte, n int) (int, error) {
select { select {
case <-t.closechan: case <-t.closechan:
return 0, ErrClosed return 0, ErrClosed
case t.datachan <- b[n:]: default:
return len(b), nil
} }
return len(b), nil
} }
func (t *fakeTUN) Flush() error { return nil } func (t *fakeTUN) Flush() error { return nil }

@ -274,39 +274,13 @@ func TestAllocs(t *testing.T) {
ftun, tun := newFakeTUN(t.Logf, false) ftun, tun := newFakeTUN(t.Logf, false)
defer tun.Close() defer tun.Close()
go func() {
var buf []byte
for {
select {
case <-tun.closed:
return
case buf = <-ftun.datachan:
// continue
}
select {
case <-tun.closed:
return
case ftun.datachan <- buf:
// continue
}
}
}()
buf := []byte{0x00} buf := []byte{0x00}
allocs := testing.AllocsPerRun(100, func() { allocs := testing.AllocsPerRun(100, func() {
_, err := tun.Write(buf, 0) _, err := ftun.Write(buf, 0)
if err != nil { if err != nil {
t.Errorf("write: error: %v", err) t.Errorf("write: error: %v", err)
return return
} }
_, err = tun.Read(buf, 0)
if err != nil {
t.Errorf("read: error: %v", err)
return
}
}) })
if allocs > 0 { if allocs > 0 {
@ -318,45 +292,9 @@ func BenchmarkWrite(b *testing.B) {
ftun, tun := newFakeTUN(b.Logf, true) ftun, tun := newFakeTUN(b.Logf, true)
defer tun.Close() defer tun.Close()
go func() {
for {
select {
case <-tun.closed:
return
case <-ftun.datachan:
// continue
}
}
}()
packet := udp(0x05060708, 0x01020304, 89, 89)
for i := 0; i < b.N; i++ {
_, err := tun.Write(packet, 0)
if err != nil {
b.Errorf("err = %v; want nil", err)
}
}
}
func BenchmarkRead(b *testing.B) {
ftun, tun := newFakeTUN(b.Logf, true)
defer tun.Close()
packet := udp(0x05060708, 0x01020304, 89, 89) packet := udp(0x05060708, 0x01020304, 89, 89)
go func() {
for {
select {
case <-tun.closed:
return
case ftun.datachan <- packet:
// continue
}
}
}()
var buf [128]byte
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := tun.Read(buf[:], 0) _, err := ftun.Write(packet, 0)
if err != nil { if err != nil {
b.Errorf("err = %v; want nil", err) b.Errorf("err = %v; want nil", err)
} }

Loading…
Cancel
Save