handshake_manager_test.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package nebula
  2. import (
  3. "net/netip"
  4. "testing"
  5. "time"
  6. "github.com/gaissmai/bart"
  7. "github.com/slackhq/nebula/cert"
  8. "github.com/slackhq/nebula/header"
  9. "github.com/slackhq/nebula/test"
  10. "github.com/slackhq/nebula/udp"
  11. "github.com/stretchr/testify/assert"
  12. )
  13. func Test_NewHandshakeManagerVpnIp(t *testing.T) {
  14. l := test.NewLogger()
  15. localrange := netip.MustParsePrefix("10.1.1.1/24")
  16. ip := netip.MustParseAddr("172.1.1.2")
  17. preferredRanges := []netip.Prefix{localrange}
  18. mainHM := newHostMap(l)
  19. mainHM.preferredRanges.Store(&preferredRanges)
  20. lh := newTestLighthouse()
  21. cs := &CertState{
  22. initiatingVersion: cert.Version1,
  23. privateKey: []byte{},
  24. v1Cert: &dummyCert{version: cert.Version1},
  25. v1Credential: nil,
  26. }
  27. blah := NewHandshakeManager(l, mainHM, lh, &udp.NoopConn{}, defaultHandshakeConfig)
  28. blah.f = &Interface{handshakeManager: blah, pki: &PKI{}, l: l}
  29. blah.f.pki.cs.Store(cs)
  30. now := time.Now()
  31. blah.NextOutboundHandshakeTimerTick(now)
  32. i := blah.StartHandshake(ip, nil)
  33. i2 := blah.StartHandshake(ip, nil)
  34. assert.Same(t, i, i2)
  35. i.remotes = NewRemoteList([]netip.Addr{}, nil)
  36. // Adding something to pending should not affect the main hostmap
  37. assert.Empty(t, mainHM.Hosts)
  38. // Confirm they are in the pending index list
  39. assert.Contains(t, blah.vpnIps, ip)
  40. // Jump ahead `HandshakeRetries` ticks, offset by one to get the sleep logic right
  41. for i := 1; i <= DefaultHandshakeRetries+1; i++ {
  42. now = now.Add(time.Duration(i) * DefaultHandshakeTryInterval)
  43. blah.NextOutboundHandshakeTimerTick(now)
  44. }
  45. // Confirm they are still in the pending index list
  46. assert.Contains(t, blah.vpnIps, ip)
  47. // Tick 1 more time, a minute will certainly flush it out
  48. blah.NextOutboundHandshakeTimerTick(now.Add(time.Minute))
  49. // Confirm they have been removed
  50. assert.NotContains(t, blah.vpnIps, ip)
  51. }
  52. func testCountTimerWheelEntries(tw *LockingTimerWheel[netip.Addr]) (c int) {
  53. for _, i := range tw.t.wheel {
  54. n := i.Head
  55. for n != nil {
  56. c++
  57. n = n.Next
  58. }
  59. }
  60. return c
  61. }
  62. type mockEncWriter struct {
  63. }
  64. func (mw *mockEncWriter) SendMessageToVpnAddr(_ header.MessageType, _ header.MessageSubType, _ netip.Addr, _, _, _ []byte) {
  65. return
  66. }
  67. func (mw *mockEncWriter) SendVia(_ *HostInfo, _ *Relay, _, _, _ []byte, _ bool) {
  68. return
  69. }
  70. func (mw *mockEncWriter) SendMessageToHostInfo(_ header.MessageType, _ header.MessageSubType, _ *HostInfo, _, _, _ []byte) {
  71. return
  72. }
  73. func (mw *mockEncWriter) Handshake(_ netip.Addr) {}
  74. func (mw *mockEncWriter) GetHostInfo(_ netip.Addr) *HostInfo {
  75. return nil
  76. }
  77. func (mw *mockEncWriter) GetCertState() *CertState {
  78. return &CertState{initiatingVersion: cert.Version2}
  79. }
  80. func TestValidatePeerCert(t *testing.T) {
  81. l := test.NewLogger()
  82. myNetwork := netip.MustParsePrefix("10.0.0.1/24")
  83. myAddrTable := new(bart.Lite)
  84. myAddrTable.Insert(netip.PrefixFrom(myNetwork.Addr(), myNetwork.Addr().BitLen()))
  85. myNetTable := new(bart.Lite)
  86. myNetTable.Insert(myNetwork.Masked())
  87. newHM := func() *HandshakeManager {
  88. hm := NewHandshakeManager(l, newHostMap(l), newTestLighthouse(), &udp.NoopConn{}, defaultHandshakeConfig)
  89. hm.f = &Interface{
  90. handshakeManager: hm,
  91. pki: &PKI{},
  92. l: l,
  93. myVpnAddrsTable: myAddrTable,
  94. myVpnNetworksTable: myNetTable,
  95. lightHouse: hm.lightHouse,
  96. }
  97. return hm
  98. }
  99. cached := func(networks ...netip.Prefix) *cert.CachedCertificate {
  100. return &cert.CachedCertificate{
  101. Certificate: &dummyCert{name: "peer", networks: networks},
  102. }
  103. }
  104. via := ViaSender{
  105. UdpAddr: netip.MustParseAddrPort("198.51.100.7:4242"),
  106. IsRelayed: true, // skip the remote allow list (covered separately)
  107. }
  108. t.Run("addr inside our networks sets anyVpnAddrsInCommon", func(t *testing.T) {
  109. hm := newHM()
  110. // 10.0.0.2 falls inside our 10.0.0.0/24
  111. addrs, common, ok := hm.validatePeerCert(via, cached(netip.MustParsePrefix("10.0.0.2/24")))
  112. assert.True(t, ok)
  113. assert.True(t, common)
  114. assert.Equal(t, []netip.Addr{netip.MustParseAddr("10.0.0.2")}, addrs)
  115. })
  116. t.Run("addr outside our networks leaves anyVpnAddrsInCommon false", func(t *testing.T) {
  117. hm := newHM()
  118. addrs, common, ok := hm.validatePeerCert(via, cached(netip.MustParsePrefix("192.168.1.5/24")))
  119. assert.True(t, ok)
  120. assert.False(t, common)
  121. assert.Equal(t, []netip.Addr{netip.MustParseAddr("192.168.1.5")}, addrs)
  122. })
  123. t.Run("any matching network is enough", func(t *testing.T) {
  124. hm := newHM()
  125. addrs, common, ok := hm.validatePeerCert(via, cached(
  126. netip.MustParsePrefix("192.168.1.5/24"),
  127. netip.MustParsePrefix("10.0.0.42/24"),
  128. ))
  129. assert.True(t, ok)
  130. assert.True(t, common)
  131. assert.Len(t, addrs, 2)
  132. })
  133. t.Run("self-handshake is rejected", func(t *testing.T) {
  134. hm := newHM()
  135. // 10.0.0.1 is in myVpnAddrsTable
  136. addrs, common, ok := hm.validatePeerCert(via, cached(netip.MustParsePrefix("10.0.0.1/24")))
  137. assert.False(t, ok)
  138. assert.False(t, common)
  139. assert.Nil(t, addrs)
  140. })
  141. t.Run("cert with no networks is rejected", func(t *testing.T) {
  142. hm := newHM()
  143. addrs, common, ok := hm.validatePeerCert(via, cached())
  144. assert.False(t, ok)
  145. assert.False(t, common)
  146. assert.Nil(t, addrs)
  147. })
  148. }
  149. func TestHandleIncomingDispatch(t *testing.T) {
  150. l := test.NewLogger()
  151. newHM := func() *HandshakeManager {
  152. hm := NewHandshakeManager(l, newHostMap(l), newTestLighthouse(), &udp.NoopConn{}, defaultHandshakeConfig)
  153. hm.f = &Interface{
  154. handshakeManager: hm,
  155. pki: &PKI{},
  156. l: l,
  157. }
  158. return hm
  159. }
  160. via := ViaSender{
  161. UdpAddr: netip.MustParseAddrPort("198.51.100.7:4242"),
  162. IsRelayed: true, // bypass remote allow list
  163. }
  164. // A packet body of zero length is fine for these tests: dispatch is
  165. // gated on header fields, and we assert that we never reach noise/cert
  166. // processing for any of the malformed shapes here.
  167. pkt := make([]byte, header.Len)
  168. t.Run("unsupported subtype dropped", func(t *testing.T) {
  169. hm := newHM()
  170. h := &header.H{Type: header.Handshake, Subtype: header.MessageSubType(99), MessageCounter: 1}
  171. hm.HandleIncoming(via, pkt, h)
  172. assert.Empty(t, hm.indexes, "no pending handshake should be created")
  173. })
  174. t.Run("stage-1 with non-zero RemoteIndex dropped", func(t *testing.T) {
  175. hm := newHM()
  176. h := &header.H{
  177. Type: header.Handshake,
  178. Subtype: header.HandshakeIXPSK0,
  179. RemoteIndex: 0xdeadbeef,
  180. MessageCounter: 1,
  181. }
  182. hm.HandleIncoming(via, pkt, h)
  183. assert.Empty(t, hm.indexes, "spoofed stage-1 must not create a pending machine")
  184. })
  185. t.Run("continuation with no matching pending index dropped", func(t *testing.T) {
  186. hm := newHM()
  187. h := &header.H{
  188. Type: header.Handshake,
  189. Subtype: header.HandshakeIXPSK0,
  190. RemoteIndex: 0xcafef00d,
  191. MessageCounter: 2,
  192. }
  193. hm.HandleIncoming(via, pkt, h)
  194. assert.Empty(t, hm.indexes, "orphan stage-2 must not create state")
  195. })
  196. }