connection_manager_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. package nebula
  2. import (
  3. "context"
  4. "crypto/ed25519"
  5. "crypto/rand"
  6. "net"
  7. "testing"
  8. "time"
  9. "github.com/flynn/noise"
  10. "github.com/slackhq/nebula/cert"
  11. "github.com/slackhq/nebula/iputil"
  12. "github.com/slackhq/nebula/test"
  13. "github.com/slackhq/nebula/udp"
  14. "github.com/stretchr/testify/assert"
  15. )
  16. var vpnIp iputil.VpnIp
  17. func newTestLighthouse() *LightHouse {
  18. lh := &LightHouse{
  19. l: test.NewLogger(),
  20. addrMap: map[iputil.VpnIp]*RemoteList{},
  21. }
  22. lighthouses := map[iputil.VpnIp]struct{}{}
  23. staticList := map[iputil.VpnIp]struct{}{}
  24. lh.lighthouses.Store(&lighthouses)
  25. lh.staticList.Store(&staticList)
  26. return lh
  27. }
  28. func Test_NewConnectionManagerTest(t *testing.T) {
  29. l := test.NewLogger()
  30. //_, tuncidr, _ := net.ParseCIDR("1.1.1.1/24")
  31. _, vpncidr, _ := net.ParseCIDR("172.1.1.1/24")
  32. _, localrange, _ := net.ParseCIDR("10.1.1.1/24")
  33. vpnIp = iputil.Ip2VpnIp(net.ParseIP("172.1.1.2"))
  34. preferredRanges := []*net.IPNet{localrange}
  35. // Very incomplete mock objects
  36. hostMap := NewHostMap(l, "test", vpncidr, preferredRanges)
  37. cs := &CertState{
  38. rawCertificate: []byte{},
  39. privateKey: []byte{},
  40. certificate: &cert.NebulaCertificate{},
  41. rawCertificateNoKey: []byte{},
  42. }
  43. lh := newTestLighthouse()
  44. ifce := &Interface{
  45. hostMap: hostMap,
  46. inside: &test.NoopTun{},
  47. outside: &udp.Conn{},
  48. firewall: &Firewall{},
  49. lightHouse: lh,
  50. handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig),
  51. l: l,
  52. }
  53. ifce.certState.Store(cs)
  54. now := time.Now()
  55. // Create manager
  56. ctx, cancel := context.WithCancel(context.Background())
  57. defer cancel()
  58. nc := newConnectionManager(ctx, l, ifce, 5, 10)
  59. p := []byte("")
  60. nb := make([]byte, 12, 12)
  61. out := make([]byte, mtu)
  62. nc.HandleMonitorTick(now, p, nb, out)
  63. // Add an ip we have established a connection w/ to hostmap
  64. hostinfo := &HostInfo{
  65. vpnIp: vpnIp,
  66. localIndexId: 1099,
  67. remoteIndexId: 9901,
  68. }
  69. hostinfo.ConnectionState = &ConnectionState{
  70. certState: cs,
  71. H: &noise.HandshakeState{},
  72. }
  73. nc.hostMap.unlockedAddHostInfo(hostinfo, ifce)
  74. // We saw traffic out to vpnIp
  75. nc.Out(hostinfo.localIndexId)
  76. assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId)
  77. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp)
  78. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  79. // Move ahead 5s. Nothing should happen
  80. next_tick := now.Add(5 * time.Second)
  81. nc.HandleMonitorTick(next_tick, p, nb, out)
  82. nc.HandleDeletionTick(next_tick)
  83. // Move ahead 6s. We haven't heard back
  84. next_tick = now.Add(6 * time.Second)
  85. nc.HandleMonitorTick(next_tick, p, nb, out)
  86. nc.HandleDeletionTick(next_tick)
  87. // This host should now be up for deletion
  88. assert.Contains(t, nc.pendingDeletion, hostinfo.localIndexId)
  89. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp)
  90. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  91. // Move ahead some more
  92. next_tick = now.Add(45 * time.Second)
  93. nc.HandleMonitorTick(next_tick, p, nb, out)
  94. nc.HandleDeletionTick(next_tick)
  95. // The host should be evicted
  96. assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId)
  97. assert.NotContains(t, nc.hostMap.Hosts, hostinfo.vpnIp)
  98. assert.NotContains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  99. }
  100. func Test_NewConnectionManagerTest2(t *testing.T) {
  101. l := test.NewLogger()
  102. //_, tuncidr, _ := net.ParseCIDR("1.1.1.1/24")
  103. _, vpncidr, _ := net.ParseCIDR("172.1.1.1/24")
  104. _, localrange, _ := net.ParseCIDR("10.1.1.1/24")
  105. preferredRanges := []*net.IPNet{localrange}
  106. // Very incomplete mock objects
  107. hostMap := NewHostMap(l, "test", vpncidr, preferredRanges)
  108. cs := &CertState{
  109. rawCertificate: []byte{},
  110. privateKey: []byte{},
  111. certificate: &cert.NebulaCertificate{},
  112. rawCertificateNoKey: []byte{},
  113. }
  114. lh := newTestLighthouse()
  115. ifce := &Interface{
  116. hostMap: hostMap,
  117. inside: &test.NoopTun{},
  118. outside: &udp.Conn{},
  119. firewall: &Firewall{},
  120. lightHouse: lh,
  121. handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig),
  122. l: l,
  123. }
  124. ifce.certState.Store(cs)
  125. now := time.Now()
  126. // Create manager
  127. ctx, cancel := context.WithCancel(context.Background())
  128. defer cancel()
  129. nc := newConnectionManager(ctx, l, ifce, 5, 10)
  130. p := []byte("")
  131. nb := make([]byte, 12, 12)
  132. out := make([]byte, mtu)
  133. nc.HandleMonitorTick(now, p, nb, out)
  134. // Add an ip we have established a connection w/ to hostmap
  135. hostinfo := &HostInfo{
  136. vpnIp: vpnIp,
  137. localIndexId: 1099,
  138. remoteIndexId: 9901,
  139. }
  140. hostinfo.ConnectionState = &ConnectionState{
  141. certState: cs,
  142. H: &noise.HandshakeState{},
  143. }
  144. nc.hostMap.unlockedAddHostInfo(hostinfo, ifce)
  145. // We saw traffic out to vpnIp
  146. nc.Out(hostinfo.localIndexId)
  147. assert.NotContains(t, nc.pendingDeletion, vpnIp)
  148. assert.Contains(t, nc.hostMap.Hosts, vpnIp)
  149. // Move ahead 5s. Nothing should happen
  150. next_tick := now.Add(5 * time.Second)
  151. nc.HandleMonitorTick(next_tick, p, nb, out)
  152. nc.HandleDeletionTick(next_tick)
  153. // Move ahead 6s. We haven't heard back
  154. next_tick = now.Add(6 * time.Second)
  155. nc.HandleMonitorTick(next_tick, p, nb, out)
  156. nc.HandleDeletionTick(next_tick)
  157. // This host should now be up for deletion
  158. assert.Contains(t, nc.pendingDeletion, hostinfo.localIndexId)
  159. assert.Contains(t, nc.hostMap.Hosts, vpnIp)
  160. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  161. // We heard back this time
  162. nc.In(hostinfo.localIndexId)
  163. // Move ahead some more
  164. next_tick = now.Add(45 * time.Second)
  165. nc.HandleMonitorTick(next_tick, p, nb, out)
  166. nc.HandleDeletionTick(next_tick)
  167. // The host should not be evicted
  168. assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId)
  169. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp)
  170. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  171. }
  172. // Check if we can disconnect the peer.
  173. // Validate if the peer's certificate is invalid (expired, etc.)
  174. // Disconnect only if disconnectInvalid: true is set.
  175. func Test_NewConnectionManagerTest_DisconnectInvalid(t *testing.T) {
  176. now := time.Now()
  177. l := test.NewLogger()
  178. ipNet := net.IPNet{
  179. IP: net.IPv4(172, 1, 1, 2),
  180. Mask: net.IPMask{255, 255, 255, 0},
  181. }
  182. _, vpncidr, _ := net.ParseCIDR("172.1.1.1/24")
  183. _, localrange, _ := net.ParseCIDR("10.1.1.1/24")
  184. preferredRanges := []*net.IPNet{localrange}
  185. hostMap := NewHostMap(l, "test", vpncidr, preferredRanges)
  186. // Generate keys for CA and peer's cert.
  187. pubCA, privCA, _ := ed25519.GenerateKey(rand.Reader)
  188. caCert := cert.NebulaCertificate{
  189. Details: cert.NebulaCertificateDetails{
  190. Name: "ca",
  191. NotBefore: now,
  192. NotAfter: now.Add(1 * time.Hour),
  193. IsCA: true,
  194. PublicKey: pubCA,
  195. },
  196. }
  197. caCert.Sign(privCA)
  198. ncp := &cert.NebulaCAPool{
  199. CAs: cert.NewCAPool().CAs,
  200. }
  201. ncp.CAs["ca"] = &caCert
  202. pubCrt, _, _ := ed25519.GenerateKey(rand.Reader)
  203. peerCert := cert.NebulaCertificate{
  204. Details: cert.NebulaCertificateDetails{
  205. Name: "host",
  206. Ips: []*net.IPNet{&ipNet},
  207. Subnets: []*net.IPNet{},
  208. NotBefore: now,
  209. NotAfter: now.Add(60 * time.Second),
  210. PublicKey: pubCrt,
  211. IsCA: false,
  212. Issuer: "ca",
  213. },
  214. }
  215. peerCert.Sign(privCA)
  216. cs := &CertState{
  217. rawCertificate: []byte{},
  218. privateKey: []byte{},
  219. certificate: &cert.NebulaCertificate{},
  220. rawCertificateNoKey: []byte{},
  221. }
  222. lh := newTestLighthouse()
  223. ifce := &Interface{
  224. hostMap: hostMap,
  225. inside: &test.NoopTun{},
  226. outside: &udp.Conn{},
  227. firewall: &Firewall{},
  228. lightHouse: lh,
  229. handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig),
  230. l: l,
  231. disconnectInvalid: true,
  232. caPool: ncp,
  233. }
  234. ifce.certState.Store(cs)
  235. // Create manager
  236. ctx, cancel := context.WithCancel(context.Background())
  237. defer cancel()
  238. nc := newConnectionManager(ctx, l, ifce, 5, 10)
  239. ifce.connectionManager = nc
  240. hostinfo, _ := nc.hostMap.AddVpnIp(vpnIp, nil)
  241. hostinfo.ConnectionState = &ConnectionState{
  242. certState: cs,
  243. peerCert: &peerCert,
  244. H: &noise.HandshakeState{},
  245. }
  246. // Move ahead 45s.
  247. // Check if to disconnect with invalid certificate.
  248. // Should be alive.
  249. nextTick := now.Add(45 * time.Second)
  250. destroyed := nc.handleInvalidCertificate(nextTick, hostinfo)
  251. assert.False(t, destroyed)
  252. // Move ahead 61s.
  253. // Check if to disconnect with invalid certificate.
  254. // Should be disconnected.
  255. nextTick = now.Add(61 * time.Second)
  256. destroyed = nc.handleInvalidCertificate(nextTick, hostinfo)
  257. assert.True(t, destroyed)
  258. }