derp_test.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package prober
  4. import (
  5. "context"
  6. "crypto/sha256"
  7. "crypto/tls"
  8. "encoding/json"
  9. "net"
  10. "net/http"
  11. "net/http/httptest"
  12. "testing"
  13. "time"
  14. "tailscale.com/derp"
  15. "tailscale.com/derp/derphttp"
  16. "tailscale.com/derp/derpserver"
  17. "tailscale.com/net/netmon"
  18. "tailscale.com/tailcfg"
  19. "tailscale.com/types/key"
  20. )
  21. func TestDerpProber(t *testing.T) {
  22. dm := &tailcfg.DERPMap{
  23. Regions: map[int]*tailcfg.DERPRegion{
  24. 0: {
  25. RegionID: 0,
  26. RegionCode: "zero",
  27. Nodes: []*tailcfg.DERPNode{
  28. {
  29. Name: "n1",
  30. RegionID: 0,
  31. HostName: "derpn1.tailscale.test",
  32. IPv4: "1.1.1.1",
  33. IPv6: "::1",
  34. },
  35. {
  36. Name: "n2",
  37. RegionID: 0,
  38. HostName: "derpn2.tailscale.test",
  39. IPv4: "1.1.1.1",
  40. IPv6: "::1",
  41. },
  42. },
  43. },
  44. 1: {
  45. RegionID: 1,
  46. RegionCode: "one",
  47. Nodes: []*tailcfg.DERPNode{
  48. {
  49. Name: "n3",
  50. RegionID: 0,
  51. HostName: "derpn3.tailscale.test",
  52. IPv4: "1.1.1.1",
  53. IPv6: "::1",
  54. },
  55. },
  56. },
  57. },
  58. }
  59. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  60. resp, err := json.Marshal(dm)
  61. if err != nil {
  62. t.Fatal(err)
  63. }
  64. w.Write(resp)
  65. }))
  66. defer srv.Close()
  67. clk := newFakeTime()
  68. p := newForTest(clk.Now, clk.NewTicker)
  69. dp := &derpProber{
  70. p: p,
  71. derpMapURL: srv.URL,
  72. tlsInterval: time.Second,
  73. tlsProbeFn: func(_ string, _ *tls.Config) ProbeClass { return FuncProbe(func(context.Context) error { return nil }) },
  74. udpInterval: time.Second,
  75. udpProbeFn: func(_ string, _ int) ProbeClass { return FuncProbe(func(context.Context) error { return nil }) },
  76. meshInterval: time.Second,
  77. meshProbeFn: func(_, _ string) ProbeClass { return FuncProbe(func(context.Context) error { return nil }) },
  78. nodes: make(map[string]*tailcfg.DERPNode),
  79. probes: make(map[string]*Probe),
  80. regionCodeOrID: "zero",
  81. }
  82. if err := dp.probeMapFn(context.Background()); err != nil {
  83. t.Errorf("unexpected probeMapFn() error: %s", err)
  84. }
  85. if len(dp.nodes) != 2 || dp.nodes["n1"] == nil || dp.nodes["n2"] == nil {
  86. t.Errorf("unexpected nodes: %+v", dp.nodes)
  87. }
  88. // Probes expected for two nodes:
  89. // - 3 regular probes per node (TLS, UDPv4, UDPv6)
  90. // - 4 mesh probes (N1->N2, N1->N1, N2->N1, N2->N2)
  91. if len(dp.probes) != 10 {
  92. t.Errorf("unexpected probes: %+v", dp.probes)
  93. }
  94. // Add one more node and check that probes got created.
  95. dm.Regions[0].Nodes = append(dm.Regions[0].Nodes, &tailcfg.DERPNode{
  96. Name: "n4",
  97. RegionID: 0,
  98. HostName: "derpn4.tailscale.test",
  99. IPv4: "1.1.1.1",
  100. IPv6: "::1",
  101. })
  102. if err := dp.probeMapFn(context.Background()); err != nil {
  103. t.Errorf("unexpected probeMapFn() error: %s", err)
  104. }
  105. if len(dp.nodes) != 3 {
  106. t.Errorf("unexpected nodes: %+v", dp.nodes)
  107. }
  108. // 9 regular probes + 9 mesh probes
  109. if len(dp.probes) != 18 {
  110. t.Errorf("unexpected probes: %+v", dp.probes)
  111. }
  112. // Remove 2 nodes and check that probes have been destroyed.
  113. dm.Regions[0].Nodes = dm.Regions[0].Nodes[:1]
  114. if err := dp.probeMapFn(context.Background()); err != nil {
  115. t.Errorf("unexpected probeMapFn() error: %s", err)
  116. }
  117. if len(dp.nodes) != 1 {
  118. t.Errorf("unexpected nodes: %+v", dp.nodes)
  119. }
  120. // 3 regular probes + 1 mesh probe
  121. if len(dp.probes) != 4 {
  122. t.Errorf("unexpected probes: %+v", dp.probes)
  123. }
  124. // Stop filtering regions.
  125. dp.regionCodeOrID = ""
  126. if err := dp.probeMapFn(context.Background()); err != nil {
  127. t.Errorf("unexpected probeMapFn() error: %s", err)
  128. }
  129. if len(dp.nodes) != 2 {
  130. t.Errorf("unexpected nodes: %+v", dp.nodes)
  131. }
  132. // 6 regular probes + 2 mesh probe
  133. if len(dp.probes) != 8 {
  134. t.Errorf("unexpected probes: %+v", dp.probes)
  135. }
  136. }
  137. func TestRunDerpProbeNodePair(t *testing.T) {
  138. // os.Setenv("DERP_DEBUG_LOGS", "true")
  139. serverPrivateKey := key.NewNode()
  140. s := derpserver.New(serverPrivateKey, t.Logf)
  141. defer s.Close()
  142. httpsrv := &http.Server{
  143. TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
  144. Handler: derpserver.Handler(s),
  145. }
  146. ln, err := net.Listen("tcp4", "localhost:0")
  147. if err != nil {
  148. t.Fatal(err)
  149. }
  150. serverURL := "http://" + ln.Addr().String()
  151. t.Logf("server URL: %s", serverURL)
  152. go func() {
  153. if err := httpsrv.Serve(ln); err != nil {
  154. if err == http.ErrServerClosed {
  155. return
  156. }
  157. panic(err)
  158. }
  159. }()
  160. newClient := func() *derphttp.Client {
  161. c, err := derphttp.NewClient(key.NewNode(), serverURL, t.Logf, netmon.NewStatic())
  162. if err != nil {
  163. t.Fatalf("NewClient: %v", err)
  164. }
  165. m, err := c.Recv()
  166. if err != nil {
  167. t.Fatalf("Recv: %v", err)
  168. }
  169. switch m.(type) {
  170. case derp.ServerInfoMessage:
  171. default:
  172. t.Fatalf("unexpected first message type %T", m)
  173. }
  174. return c
  175. }
  176. c1 := newClient()
  177. defer c1.Close()
  178. c2 := newClient()
  179. defer c2.Close()
  180. ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
  181. defer cancel()
  182. err = runDerpProbeNodePair(ctx, &tailcfg.DERPNode{Name: "c1"}, &tailcfg.DERPNode{Name: "c2"}, c1, c2, 100_000_000)
  183. if err != nil {
  184. t.Error(err)
  185. }
  186. }
  187. func Test_packetsForSize(t *testing.T) {
  188. tests := []struct {
  189. name string
  190. size int
  191. wantPackets int
  192. wantUnique bool
  193. }{
  194. {"small_unqiue", 8, 1, true},
  195. {"8k_unique", 8192, 1, true},
  196. {"full_size_packet", derp.MaxPacketSize, 1, true},
  197. {"larger_than_one", derp.MaxPacketSize + 1, 2, false},
  198. {"large", 500000, 8, false},
  199. }
  200. for _, tt := range tests {
  201. t.Run(tt.name, func(t *testing.T) {
  202. hashes := make(map[string]int)
  203. for range 5 {
  204. pkts := packetsForSize(int64(tt.size))
  205. if len(pkts) != tt.wantPackets {
  206. t.Errorf("packetsForSize(%d) got %d packets, want %d", tt.size, len(pkts), tt.wantPackets)
  207. }
  208. var total int
  209. hash := sha256.New()
  210. for _, p := range pkts {
  211. hash.Write(p)
  212. total += len(p)
  213. }
  214. hashes[string(hash.Sum(nil))]++
  215. if total != tt.size {
  216. t.Errorf("packetsForSize(%d) returned %d bytes total", tt.size, total)
  217. }
  218. }
  219. unique := len(hashes) > 1
  220. if unique != tt.wantUnique {
  221. t.Errorf("packetsForSize(%d) is unique=%v (returned %d different answers); want unique=%v", tt.size, unique, len(hashes), unique)
  222. }
  223. })
  224. }
  225. }