2020-08-06 22:57:03 +01:00
|
|
|
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package wgengine
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2020-10-13 20:04:52 +01:00
|
|
|
"reflect"
|
2020-08-06 22:57:03 +01:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2020-10-13 20:04:52 +01:00
|
|
|
"go4.org/mem"
|
2020-12-24 20:33:55 +00:00
|
|
|
"inet.af/netaddr"
|
2021-04-02 08:34:32 +01:00
|
|
|
"tailscale.com/net/dns"
|
2021-03-27 05:14:08 +00:00
|
|
|
"tailscale.com/net/tstun"
|
2020-08-06 22:57:03 +01:00
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/types/key"
|
2020-10-13 20:04:52 +01:00
|
|
|
"tailscale.com/wgengine/router"
|
2021-01-29 20:16:36 +00:00
|
|
|
"tailscale.com/wgengine/wgcfg"
|
2020-08-06 22:57:03 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestNoteReceiveActivity(t *testing.T) {
|
|
|
|
now := time.Unix(1, 0)
|
|
|
|
var logBuf bytes.Buffer
|
|
|
|
|
|
|
|
confc := make(chan bool, 1)
|
|
|
|
gotConf := func() bool {
|
|
|
|
select {
|
|
|
|
case <-confc:
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
e := &userspaceEngine{
|
|
|
|
timeNow: func() time.Time { return now },
|
|
|
|
recvActivityAt: map[tailcfg.DiscoKey]time.Time{},
|
|
|
|
logf: func(format string, a ...interface{}) {
|
|
|
|
fmt.Fprintf(&logBuf, format, a...)
|
|
|
|
},
|
2021-03-27 06:13:20 +00:00
|
|
|
tundev: new(tstun.Wrapper),
|
2020-08-06 22:57:03 +01:00
|
|
|
testMaybeReconfigHook: func() { confc <- true },
|
2020-08-26 20:20:09 +01:00
|
|
|
trimmedDisco: map[tailcfg.DiscoKey]bool{},
|
2020-08-06 22:57:03 +01:00
|
|
|
}
|
|
|
|
ra := e.recvActivityAt
|
|
|
|
|
|
|
|
dk := tailcfg.DiscoKey(key.NewPrivate().Public())
|
|
|
|
|
|
|
|
// Activity on an untracked key should do nothing.
|
|
|
|
e.noteReceiveActivity(dk)
|
|
|
|
if len(ra) != 0 {
|
|
|
|
t.Fatalf("unexpected growth in map: now has %d keys; want 0", len(ra))
|
|
|
|
}
|
|
|
|
if logBuf.Len() != 0 {
|
|
|
|
t.Fatalf("unexpected log write (and thus activity): %s", logBuf.Bytes())
|
|
|
|
}
|
|
|
|
|
2020-08-26 20:20:09 +01:00
|
|
|
// Now track it, but don't mark it trimmed, so shouldn't update.
|
2020-08-06 22:57:03 +01:00
|
|
|
ra[dk] = time.Time{}
|
|
|
|
e.noteReceiveActivity(dk)
|
|
|
|
if len(ra) != 1 {
|
|
|
|
t.Fatalf("unexpected growth in map: now has %d keys; want 1", len(ra))
|
|
|
|
}
|
|
|
|
if got := ra[dk]; got != now {
|
|
|
|
t.Fatalf("time in map = %v; want %v", got, now)
|
|
|
|
}
|
2020-08-26 20:20:09 +01:00
|
|
|
if gotConf() {
|
|
|
|
t.Fatalf("unexpected reconfig")
|
2020-08-06 22:57:03 +01:00
|
|
|
}
|
|
|
|
|
2020-08-26 20:20:09 +01:00
|
|
|
// Now mark it trimmed and expect an update.
|
|
|
|
e.trimmedDisco[dk] = true
|
2020-08-06 22:57:03 +01:00
|
|
|
e.noteReceiveActivity(dk)
|
2020-08-26 20:20:09 +01:00
|
|
|
if len(ra) != 1 {
|
|
|
|
t.Fatalf("unexpected growth in map: now has %d keys; want 1", len(ra))
|
|
|
|
}
|
|
|
|
if got := ra[dk]; got != now {
|
|
|
|
t.Fatalf("time in map = %v; want %v", got, now)
|
|
|
|
}
|
2020-08-06 22:57:03 +01:00
|
|
|
if !gotConf() {
|
2020-08-26 20:20:09 +01:00
|
|
|
t.Fatalf("didn't get expected reconfig")
|
2020-08-06 22:57:03 +01:00
|
|
|
}
|
|
|
|
}
|
2020-10-13 20:04:52 +01:00
|
|
|
|
|
|
|
func TestUserspaceEngineReconfig(t *testing.T) {
|
2021-03-01 18:08:53 +00:00
|
|
|
e, err := NewFakeUserspaceEngine(t.Logf, 0)
|
2020-10-13 20:04:52 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer e.Close()
|
|
|
|
ue := e.(*userspaceEngine)
|
|
|
|
|
|
|
|
routerCfg := &router.Config{}
|
|
|
|
|
|
|
|
for _, discoHex := range []string{
|
|
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
|
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
|
|
} {
|
|
|
|
cfg := &wgcfg.Config{
|
|
|
|
Peers: []wgcfg.Peer{
|
|
|
|
{
|
2020-12-24 20:33:55 +00:00
|
|
|
AllowedIPs: []netaddr.IPPrefix{
|
|
|
|
{IP: netaddr.IPv4(100, 100, 99, 1), Bits: 32},
|
2020-10-13 20:04:52 +01:00
|
|
|
},
|
2021-05-01 00:45:36 +01:00
|
|
|
Endpoints: wgcfg.Endpoints{DiscoKey: dkFromHex(discoHex)},
|
2020-10-13 20:04:52 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-04-02 08:34:32 +01:00
|
|
|
err = e.Reconfig(cfg, routerCfg, &dns.Config{})
|
2020-10-13 20:04:52 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
wantRecvAt := map[tailcfg.DiscoKey]time.Time{
|
|
|
|
dkFromHex(discoHex): time.Time{},
|
|
|
|
}
|
|
|
|
if got := ue.recvActivityAt; !reflect.DeepEqual(got, wantRecvAt) {
|
|
|
|
t.Errorf("wrong recvActivityAt\n got: %v\nwant: %v\n", got, wantRecvAt)
|
|
|
|
}
|
|
|
|
|
|
|
|
wantTrimmedDisco := map[tailcfg.DiscoKey]bool{
|
|
|
|
dkFromHex(discoHex): true,
|
|
|
|
}
|
|
|
|
if got := ue.trimmedDisco; !reflect.DeepEqual(got, wantTrimmedDisco) {
|
|
|
|
t.Errorf("wrong wantTrimmedDisco\n got: %v\nwant: %v\n", got, wantTrimmedDisco)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func dkFromHex(hex string) tailcfg.DiscoKey {
|
|
|
|
if len(hex) != 64 {
|
|
|
|
panic(fmt.Sprintf("%q is len %d; want 64", hex, len(hex)))
|
|
|
|
}
|
|
|
|
k, err := key.NewPublicFromHexMem(mem.S(hex[:64]))
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("%q is not hex: %v", hex, err))
|
|
|
|
}
|
|
|
|
return tailcfg.DiscoKey(k)
|
|
|
|
}
|
2021-03-28 06:40:38 +01:00
|
|
|
|
|
|
|
// an experiment to see if genLocalAddrFunc was worth it. As of Go
|
|
|
|
// 1.16, it still very much is. (30-40x faster)
|
|
|
|
func BenchmarkGenLocalAddrFunc(b *testing.B) {
|
|
|
|
la1 := netaddr.MustParseIP("1.2.3.4")
|
|
|
|
la2 := netaddr.MustParseIP("::4")
|
|
|
|
lanot := netaddr.MustParseIP("5.5.5.5")
|
|
|
|
var x bool
|
|
|
|
b.Run("map1", func(b *testing.B) {
|
|
|
|
m := map[netaddr.IP]bool{
|
|
|
|
la1: true,
|
|
|
|
}
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
x = m[la1]
|
|
|
|
x = m[lanot]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
b.Run("map2", func(b *testing.B) {
|
|
|
|
m := map[netaddr.IP]bool{
|
|
|
|
la1: true,
|
|
|
|
la2: true,
|
|
|
|
}
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
x = m[la1]
|
|
|
|
x = m[lanot]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
b.Run("or1", func(b *testing.B) {
|
|
|
|
f := func(t netaddr.IP) bool {
|
|
|
|
return t == la1
|
|
|
|
}
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
x = f(la1)
|
|
|
|
x = f(lanot)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
b.Run("or2", func(b *testing.B) {
|
|
|
|
f := func(t netaddr.IP) bool {
|
|
|
|
return t == la1 || t == la2
|
|
|
|
}
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
x = f(la1)
|
|
|
|
x = f(lanot)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
b.Logf("x = %v", x)
|
|
|
|
}
|