userspace_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package wgengine
  4. import (
  5. "fmt"
  6. "net/netip"
  7. "os"
  8. "reflect"
  9. "runtime"
  10. "testing"
  11. "go4.org/mem"
  12. "tailscale.com/cmd/testwrapper/flakytest"
  13. "tailscale.com/control/controlknobs"
  14. "tailscale.com/envknob"
  15. "tailscale.com/health"
  16. "tailscale.com/net/dns"
  17. "tailscale.com/net/netaddr"
  18. "tailscale.com/net/tstun"
  19. "tailscale.com/tailcfg"
  20. "tailscale.com/tstest"
  21. "tailscale.com/tstime/mono"
  22. "tailscale.com/types/key"
  23. "tailscale.com/types/netmap"
  24. "tailscale.com/types/opt"
  25. "tailscale.com/util/eventbus/eventbustest"
  26. "tailscale.com/util/usermetric"
  27. "tailscale.com/wgengine/router"
  28. "tailscale.com/wgengine/wgcfg"
  29. )
  30. func TestNoteReceiveActivity(t *testing.T) {
  31. now := mono.Time(123456)
  32. var logBuf tstest.MemLogger
  33. confc := make(chan bool, 1)
  34. gotConf := func() bool {
  35. select {
  36. case <-confc:
  37. return true
  38. default:
  39. return false
  40. }
  41. }
  42. e := &userspaceEngine{
  43. timeNow: func() mono.Time { return now },
  44. recvActivityAt: map[key.NodePublic]mono.Time{},
  45. logf: logBuf.Logf,
  46. tundev: new(tstun.Wrapper),
  47. testMaybeReconfigHook: func() { confc <- true },
  48. trimmedNodes: map[key.NodePublic]bool{},
  49. }
  50. ra := e.recvActivityAt
  51. nk := key.NewNode().Public()
  52. // Activity on an untracked key should do nothing.
  53. e.noteRecvActivity(nk)
  54. if len(ra) != 0 {
  55. t.Fatalf("unexpected growth in map: now has %d keys; want 0", len(ra))
  56. }
  57. if logBuf.Len() != 0 {
  58. t.Fatalf("unexpected log write (and thus activity): %s", logBuf.Bytes())
  59. }
  60. // Now track it, but don't mark it trimmed, so shouldn't update.
  61. ra[nk] = 0
  62. e.noteRecvActivity(nk)
  63. if len(ra) != 1 {
  64. t.Fatalf("unexpected growth in map: now has %d keys; want 1", len(ra))
  65. }
  66. if got := ra[nk]; got != now {
  67. t.Fatalf("time in map = %v; want %v", got, now)
  68. }
  69. if gotConf() {
  70. t.Fatalf("unexpected reconfig")
  71. }
  72. // Now mark it trimmed and expect an update.
  73. e.trimmedNodes[nk] = true
  74. e.noteRecvActivity(nk)
  75. if len(ra) != 1 {
  76. t.Fatalf("unexpected growth in map: now has %d keys; want 1", len(ra))
  77. }
  78. if got := ra[nk]; got != now {
  79. t.Fatalf("time in map = %v; want %v", got, now)
  80. }
  81. if !gotConf() {
  82. t.Fatalf("didn't get expected reconfig")
  83. }
  84. }
  85. func nodeViews(v []*tailcfg.Node) []tailcfg.NodeView {
  86. nv := make([]tailcfg.NodeView, len(v))
  87. for i, n := range v {
  88. nv[i] = n.View()
  89. }
  90. return nv
  91. }
  92. func TestUserspaceEngineReconfig(t *testing.T) {
  93. bus := eventbustest.NewBus(t)
  94. ht := health.NewTracker(bus)
  95. reg := new(usermetric.Registry)
  96. e, err := NewFakeUserspaceEngine(t.Logf, 0, ht, reg, bus)
  97. if err != nil {
  98. t.Fatal(err)
  99. }
  100. t.Cleanup(e.Close)
  101. ue := e.(*userspaceEngine)
  102. routerCfg := &router.Config{}
  103. for _, nodeHex := range []string{
  104. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  105. "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
  106. } {
  107. nm := &netmap.NetworkMap{
  108. Peers: nodeViews([]*tailcfg.Node{
  109. {
  110. ID: 1,
  111. Key: nkFromHex(nodeHex),
  112. },
  113. }),
  114. }
  115. nk, err := key.ParseNodePublicUntyped(mem.S(nodeHex))
  116. if err != nil {
  117. t.Fatal(err)
  118. }
  119. cfg := &wgcfg.Config{
  120. Peers: []wgcfg.Peer{
  121. {
  122. PublicKey: nk,
  123. AllowedIPs: []netip.Prefix{
  124. netip.PrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
  125. },
  126. },
  127. },
  128. }
  129. e.SetNetworkMap(nm)
  130. err = e.Reconfig(cfg, routerCfg, &dns.Config{})
  131. if err != nil {
  132. t.Fatal(err)
  133. }
  134. wantRecvAt := map[key.NodePublic]mono.Time{
  135. nkFromHex(nodeHex): 0,
  136. }
  137. if got := ue.recvActivityAt; !reflect.DeepEqual(got, wantRecvAt) {
  138. t.Errorf("wrong recvActivityAt\n got: %v\nwant: %v\n", got, wantRecvAt)
  139. }
  140. wantTrimmedNodes := map[key.NodePublic]bool{
  141. nkFromHex(nodeHex): true,
  142. }
  143. if got := ue.trimmedNodes; !reflect.DeepEqual(got, wantTrimmedNodes) {
  144. t.Errorf("wrong wantTrimmedNodes\n got: %v\nwant: %v\n", got, wantTrimmedNodes)
  145. }
  146. }
  147. }
  148. func TestUserspaceEnginePortReconfig(t *testing.T) {
  149. flakytest.Mark(t, "https://github.com/tailscale/tailscale/issues/2855")
  150. const defaultPort = 49983
  151. var knobs controlknobs.Knobs
  152. bus := eventbustest.NewBus(t)
  153. // Keep making a wgengine until we find an unused port
  154. var ue *userspaceEngine
  155. ht := health.NewTracker(bus)
  156. reg := new(usermetric.Registry)
  157. for i := range 100 {
  158. attempt := uint16(defaultPort + i)
  159. e, err := NewFakeUserspaceEngine(t.Logf, attempt, &knobs, ht, reg, bus)
  160. if err != nil {
  161. t.Fatal(err)
  162. }
  163. ue = e.(*userspaceEngine)
  164. if ue.magicConn.LocalPort() == attempt {
  165. break
  166. }
  167. ue.Close()
  168. ue = nil
  169. }
  170. if ue == nil {
  171. t.Fatal("could not create a wgengine with a specific port")
  172. }
  173. t.Cleanup(ue.Close)
  174. startingPort := ue.magicConn.LocalPort()
  175. nodeKey, err := key.ParseNodePublicUntyped(mem.S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
  176. if err != nil {
  177. t.Fatal(err)
  178. }
  179. cfg := &wgcfg.Config{
  180. Peers: []wgcfg.Peer{
  181. {
  182. PublicKey: nodeKey,
  183. AllowedIPs: []netip.Prefix{
  184. netip.PrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
  185. },
  186. },
  187. },
  188. }
  189. routerCfg := &router.Config{}
  190. if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
  191. t.Fatal(err)
  192. }
  193. if got := ue.magicConn.LocalPort(); got != startingPort {
  194. t.Errorf("no debug setting changed local port to %d from %d", got, startingPort)
  195. }
  196. knobs.RandomizeClientPort.Store(true)
  197. if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
  198. t.Fatal(err)
  199. }
  200. if got := ue.magicConn.LocalPort(); got == startingPort {
  201. t.Errorf("debug setting did not change local port from %d", startingPort)
  202. }
  203. lastPort := ue.magicConn.LocalPort()
  204. knobs.RandomizeClientPort.Store(false)
  205. if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
  206. t.Fatal(err)
  207. }
  208. if startingPort == defaultPort {
  209. // Only try this if we managed to bind defaultPort the first time.
  210. // Otherwise, assume someone else on the computer is using defaultPort
  211. // and so Reconfig would have caused magicSockt to bind some other port.
  212. if got := ue.magicConn.LocalPort(); got != defaultPort {
  213. t.Errorf("debug setting did not change local port from %d to %d", startingPort, defaultPort)
  214. }
  215. }
  216. if got := ue.magicConn.LocalPort(); got == lastPort {
  217. t.Errorf("Reconfig did not change local port from %d", lastPort)
  218. }
  219. }
  220. // Test that enabling and disabling peer path MTU discovery works correctly.
  221. func TestUserspaceEnginePeerMTUReconfig(t *testing.T) {
  222. if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
  223. t.Skipf("skipping on %q; peer MTU not supported", runtime.GOOS)
  224. }
  225. defer os.Setenv("TS_DEBUG_ENABLE_PMTUD", os.Getenv("TS_DEBUG_ENABLE_PMTUD"))
  226. envknob.Setenv("TS_DEBUG_ENABLE_PMTUD", "")
  227. // Turn on debugging to help diagnose problems.
  228. defer os.Setenv("TS_DEBUG_PMTUD", os.Getenv("TS_DEBUG_PMTUD"))
  229. envknob.Setenv("TS_DEBUG_PMTUD", "true")
  230. var knobs controlknobs.Knobs
  231. bus := eventbustest.NewBus(t)
  232. ht := health.NewTracker(bus)
  233. reg := new(usermetric.Registry)
  234. e, err := NewFakeUserspaceEngine(t.Logf, 0, &knobs, ht, reg, bus)
  235. if err != nil {
  236. t.Fatal(err)
  237. }
  238. t.Cleanup(e.Close)
  239. ue := e.(*userspaceEngine)
  240. if ue.magicConn.PeerMTUEnabled() != false {
  241. t.Error("peer MTU enabled by default, should not be")
  242. }
  243. osDefaultDF, err := ue.magicConn.DontFragSetting()
  244. if err != nil {
  245. t.Errorf("get don't fragment bit failed: %v", err)
  246. }
  247. t.Logf("Info: OS default don't fragment bit(s) setting: %v", osDefaultDF)
  248. // Build a set of configs to use as we change the peer MTU settings.
  249. nodeKey, err := key.ParseNodePublicUntyped(mem.S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
  250. if err != nil {
  251. t.Fatal(err)
  252. }
  253. cfg := &wgcfg.Config{
  254. Peers: []wgcfg.Peer{
  255. {
  256. PublicKey: nodeKey,
  257. AllowedIPs: []netip.Prefix{
  258. netip.PrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
  259. },
  260. },
  261. },
  262. }
  263. routerCfg := &router.Config{}
  264. tests := []struct {
  265. desc string // test description
  266. wantP bool // desired value of PMTUD setting
  267. wantDF bool // desired value of don't fragment bits
  268. shouldP opt.Bool // if set, force peer MTU to this value
  269. }{
  270. {desc: "after_first_reconfig", wantP: false, wantDF: osDefaultDF, shouldP: ""},
  271. {desc: "enabling_PMTUD_first_time", wantP: true, wantDF: true, shouldP: "true"},
  272. {desc: "disabling_PMTUD", wantP: false, wantDF: false, shouldP: "false"},
  273. {desc: "enabling_PMTUD_second_time", wantP: true, wantDF: true, shouldP: "true"},
  274. {desc: "returning_to_default_PMTUD", wantP: false, wantDF: false, shouldP: ""},
  275. }
  276. for _, tt := range tests {
  277. t.Run(tt.desc, func(t *testing.T) {
  278. if v, ok := tt.shouldP.Get(); ok {
  279. knobs.PeerMTUEnable.Store(v)
  280. } else {
  281. knobs.PeerMTUEnable.Store(false)
  282. }
  283. if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
  284. t.Fatal(err)
  285. }
  286. if v := ue.magicConn.PeerMTUEnabled(); v != tt.wantP {
  287. t.Errorf("peer MTU set to %v, want %v", v, tt.wantP)
  288. }
  289. if v, err := ue.magicConn.DontFragSetting(); v != tt.wantDF || err != nil {
  290. t.Errorf("don't fragment bit set to %v, want %v, err %v", v, tt.wantP, err)
  291. }
  292. })
  293. }
  294. }
  295. func TestTSMPKeyAdvertisement(t *testing.T) {
  296. var knobs controlknobs.Knobs
  297. bus := eventbustest.NewBus(t)
  298. ht := health.NewTracker(bus)
  299. reg := new(usermetric.Registry)
  300. e, err := NewFakeUserspaceEngine(t.Logf, 0, &knobs, ht, reg, bus)
  301. if err != nil {
  302. t.Fatal(err)
  303. }
  304. t.Cleanup(e.Close)
  305. ue := e.(*userspaceEngine)
  306. routerCfg := &router.Config{}
  307. nodeKey := nkFromHex("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
  308. nm := &netmap.NetworkMap{
  309. Peers: nodeViews([]*tailcfg.Node{
  310. {
  311. ID: 1,
  312. Key: nodeKey,
  313. },
  314. }),
  315. SelfNode: (&tailcfg.Node{
  316. StableID: "TESTCTRL00000001",
  317. Name: "test-node.test.ts.net",
  318. Addresses: []netip.Prefix{netip.MustParsePrefix("100.64.0.1/32"), netip.MustParsePrefix("fd7a:115c:a1e0:ab12:4843:cd96:0:1/128")},
  319. }).View(),
  320. }
  321. cfg := &wgcfg.Config{
  322. Peers: []wgcfg.Peer{
  323. {
  324. PublicKey: nodeKey,
  325. AllowedIPs: []netip.Prefix{
  326. netip.PrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
  327. },
  328. },
  329. },
  330. }
  331. ue.SetNetworkMap(nm)
  332. err = ue.Reconfig(cfg, routerCfg, &dns.Config{})
  333. if err != nil {
  334. t.Fatal(err)
  335. }
  336. addr := netip.MustParseAddr("100.100.99.1")
  337. previousValue := metricTSMPDiscoKeyAdvertisementSent.Value()
  338. ue.sendTSMPDiscoAdvertisement(addr)
  339. if val := metricTSMPDiscoKeyAdvertisementSent.Value(); val <= previousValue {
  340. errs := metricTSMPDiscoKeyAdvertisementError.Value()
  341. t.Errorf("Expected 1 disco key advert, got %d, errors %d", val, errs)
  342. }
  343. // Remove config to have the engine shut down more consistently
  344. err = ue.Reconfig(&wgcfg.Config{}, &router.Config{}, &dns.Config{})
  345. if err != nil {
  346. t.Fatal(err)
  347. }
  348. }
  349. func nkFromHex(hex string) key.NodePublic {
  350. if len(hex) != 64 {
  351. panic(fmt.Sprintf("%q is len %d; want 64", hex, len(hex)))
  352. }
  353. k, err := key.ParseNodePublicUntyped(mem.S(hex[:64]))
  354. if err != nil {
  355. panic(fmt.Sprintf("%q is not hex: %v", hex, err))
  356. }
  357. return k
  358. }
  359. // an experiment to see if genLocalAddrFunc was worth it. As of Go
  360. // 1.16, it still very much is. (30-40x faster)
  361. func BenchmarkGenLocalAddrFunc(b *testing.B) {
  362. la1 := netip.MustParseAddr("1.2.3.4")
  363. la2 := netip.MustParseAddr("::4")
  364. lanot := netip.MustParseAddr("5.5.5.5")
  365. var x bool
  366. b.Run("map1", func(b *testing.B) {
  367. b.ReportAllocs()
  368. b.ResetTimer()
  369. m := map[netip.Addr]bool{
  370. la1: true,
  371. }
  372. for range b.N {
  373. x = m[la1]
  374. x = m[lanot]
  375. }
  376. })
  377. b.Run("map2", func(b *testing.B) {
  378. b.ReportAllocs()
  379. b.ResetTimer()
  380. m := map[netip.Addr]bool{
  381. la1: true,
  382. la2: true,
  383. }
  384. for range b.N {
  385. x = m[la1]
  386. x = m[lanot]
  387. }
  388. })
  389. b.Run("or1", func(b *testing.B) {
  390. b.ReportAllocs()
  391. b.ResetTimer()
  392. f := func(t netip.Addr) bool {
  393. return t == la1
  394. }
  395. for range b.N {
  396. x = f(la1)
  397. x = f(lanot)
  398. }
  399. })
  400. b.Run("or2", func(b *testing.B) {
  401. b.ReportAllocs()
  402. b.ResetTimer()
  403. f := func(t netip.Addr) bool {
  404. return t == la1 || t == la2
  405. }
  406. for range b.N {
  407. x = f(la1)
  408. x = f(lanot)
  409. }
  410. })
  411. b.Logf("x = %v", x)
  412. }