direct_test.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package controlclient
  4. import (
  5. "crypto/ed25519"
  6. "encoding/json"
  7. "net/http"
  8. "net/http/httptest"
  9. "net/netip"
  10. "testing"
  11. "time"
  12. "tailscale.com/hostinfo"
  13. "tailscale.com/ipn/ipnstate"
  14. "tailscale.com/net/tsdial"
  15. "tailscale.com/tailcfg"
  16. "tailscale.com/types/key"
  17. )
  18. func TestNewDirect(t *testing.T) {
  19. hi := hostinfo.New()
  20. ni := tailcfg.NetInfo{LinkType: "wired"}
  21. hi.NetInfo = &ni
  22. k := key.NewMachine()
  23. opts := Options{
  24. ServerURL: "https://example.com",
  25. Hostinfo: hi,
  26. GetMachinePrivateKey: func() (key.MachinePrivate, error) {
  27. return k, nil
  28. },
  29. Dialer: new(tsdial.Dialer),
  30. }
  31. c, err := NewDirect(opts)
  32. if err != nil {
  33. t.Fatal(err)
  34. }
  35. if c.serverURL != opts.ServerURL {
  36. t.Errorf("c.serverURL got %v want %v", c.serverURL, opts.ServerURL)
  37. }
  38. if !hi.Equal(c.hostinfo) {
  39. t.Errorf("c.hostinfo got %v want %v", c.hostinfo, hi)
  40. }
  41. changed := c.SetNetInfo(&ni)
  42. if changed {
  43. t.Errorf("c.SetNetInfo(ni) want false got %v", changed)
  44. }
  45. ni = tailcfg.NetInfo{LinkType: "wifi"}
  46. changed = c.SetNetInfo(&ni)
  47. if !changed {
  48. t.Errorf("c.SetNetInfo(ni) want true got %v", changed)
  49. }
  50. changed = c.SetHostinfo(hi)
  51. if changed {
  52. t.Errorf("c.SetHostinfo(hi) want false got %v", changed)
  53. }
  54. hi = hostinfo.New()
  55. hi.Hostname = "different host name"
  56. changed = c.SetHostinfo(hi)
  57. if !changed {
  58. t.Errorf("c.SetHostinfo(hi) want true got %v", changed)
  59. }
  60. endpoints := fakeEndpoints(1, 2, 3)
  61. changed = c.newEndpoints(endpoints)
  62. if !changed {
  63. t.Errorf("c.newEndpoints want true got %v", changed)
  64. }
  65. changed = c.newEndpoints(endpoints)
  66. if changed {
  67. t.Errorf("c.newEndpoints want false got %v", changed)
  68. }
  69. endpoints = fakeEndpoints(4, 5, 6)
  70. changed = c.newEndpoints(endpoints)
  71. if !changed {
  72. t.Errorf("c.newEndpoints want true got %v", changed)
  73. }
  74. }
  75. func fakeEndpoints(ports ...uint16) (ret []tailcfg.Endpoint) {
  76. for _, port := range ports {
  77. ret = append(ret, tailcfg.Endpoint{
  78. Addr: netip.AddrPortFrom(netip.Addr{}, port),
  79. })
  80. }
  81. return
  82. }
  83. func TestTsmpPing(t *testing.T) {
  84. hi := hostinfo.New()
  85. ni := tailcfg.NetInfo{LinkType: "wired"}
  86. hi.NetInfo = &ni
  87. k := key.NewMachine()
  88. opts := Options{
  89. ServerURL: "https://example.com",
  90. Hostinfo: hi,
  91. GetMachinePrivateKey: func() (key.MachinePrivate, error) {
  92. return k, nil
  93. },
  94. Dialer: new(tsdial.Dialer),
  95. }
  96. c, err := NewDirect(opts)
  97. if err != nil {
  98. t.Fatal(err)
  99. }
  100. pingRes := &tailcfg.PingResponse{
  101. Type: "TSMP",
  102. IP: "123.456.7890",
  103. Err: "",
  104. NodeName: "testnode",
  105. }
  106. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  107. defer r.Body.Close()
  108. body := new(ipnstate.PingResult)
  109. if err := json.NewDecoder(r.Body).Decode(body); err != nil {
  110. t.Fatal(err)
  111. }
  112. if pingRes.IP != body.IP {
  113. t.Fatalf("PingResult did not have the correct IP : got %v, expected : %v", body.IP, pingRes.IP)
  114. }
  115. w.WriteHeader(200)
  116. }))
  117. defer ts.Close()
  118. now := time.Now()
  119. pr := &tailcfg.PingRequest{
  120. URL: ts.URL,
  121. }
  122. err = postPingResult(now, t.Logf, c.httpc, pr, pingRes)
  123. if err != nil {
  124. t.Fatal(err)
  125. }
  126. }
  127. func TestDecodeWrappedAuthkey(t *testing.T) {
  128. k, isWrapped, sig, priv := decodeWrappedAuthkey("tskey-32mjsdkdsffds9o87dsfkjlh", nil)
  129. if want := "tskey-32mjsdkdsffds9o87dsfkjlh"; k != want {
  130. t.Errorf("decodeWrappedAuthkey(<unwrapped-key>).key = %q, want %q", k, want)
  131. }
  132. if isWrapped {
  133. t.Error("decodeWrappedAuthkey(<unwrapped-key>).isWrapped = true, want false")
  134. }
  135. if sig != nil {
  136. t.Errorf("decodeWrappedAuthkey(<unwrapped-key>).sig = %v, want nil", sig)
  137. }
  138. if priv != nil {
  139. t.Errorf("decodeWrappedAuthkey(<unwrapped-key>).priv = %v, want nil", priv)
  140. }
  141. k, isWrapped, sig, priv = decodeWrappedAuthkey("tskey-auth-k7UagY1CNTRL-ZZZZZ--TLpAEDA1ggnXuw4/fWnNWUwcoOjLemhOvml1juMl5lhLmY5sBUsj8EWEAfL2gdeD9g8VDw5tgcxCiHGlEb67BgU2DlFzZApi4LheLJraA+pYjTGChVhpZz1iyiBPD+U2qxDQAbM3+WFY0EBlggxmVqG53Hu0Rg+KmHJFMlUhfgzo+AQP6+Kk9GzvJJOs4-k36RdoSFqaoARfQo0UncHAV0t3YTqrkD5r/z2jTrE43GZWobnce7RGD4qYckUyVSF+DOj4BA/r4qT0bO8kk6zg", nil)
  142. if want := "tskey-auth-k7UagY1CNTRL-ZZZZZ"; k != want {
  143. t.Errorf("decodeWrappedAuthkey(<wrapped-key>).key = %q, want %q", k, want)
  144. }
  145. if !isWrapped {
  146. t.Error("decodeWrappedAuthkey(<wrapped-key>).isWrapped = false, want true")
  147. }
  148. if sig == nil {
  149. t.Fatal("decodeWrappedAuthkey(<wrapped-key>).sig = nil, want non-nil signature")
  150. }
  151. sigHash := sig.SigHash()
  152. if !ed25519.Verify(sig.KeyID, sigHash[:], sig.Signature) {
  153. t.Error("signature failed to verify")
  154. }
  155. // Make sure the private is correct by using it.
  156. someSig := ed25519.Sign(priv, []byte{1, 2, 3, 4})
  157. if !ed25519.Verify(sig.WrappingPubkey, []byte{1, 2, 3, 4}, someSig) {
  158. t.Error("failed to use priv")
  159. }
  160. }