topology_test.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. // Copyright 2019 the Kilo authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package mesh
  15. import (
  16. "net"
  17. "testing"
  18. "time"
  19. "github.com/go-kit/kit/log"
  20. "github.com/kylelemons/godebug/pretty"
  21. "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
  22. "github.com/squat/kilo/pkg/wireguard"
  23. )
  24. func mustParseCIDR(s string) (r net.IPNet) {
  25. if _, ip, err := net.ParseCIDR(s); err != nil {
  26. panic("failed to parse CIDR")
  27. } else {
  28. r = *ip
  29. }
  30. return
  31. }
  32. var (
  33. key1 = wgtypes.Key{'k', 'e', 'y', '1'}
  34. key2 = wgtypes.Key{'k', 'e', 'y', '2'}
  35. key3 = wgtypes.Key{'k', 'e', 'y', '3'}
  36. key4 = wgtypes.Key{'k', 'e', 'y', '4'}
  37. key5 = wgtypes.Key{'k', 'e', 'y', '5'}
  38. )
  39. func setup(t *testing.T) (map[string]*Node, map[string]*Peer, wgtypes.Key, int) {
  40. key := wgtypes.Key{'p', 'r', 'i', 'v'}
  41. e1 := &net.IPNet{IP: net.ParseIP("10.1.0.1").To4(), Mask: net.CIDRMask(16, 32)}
  42. e2 := &net.IPNet{IP: net.ParseIP("10.1.0.2").To4(), Mask: net.CIDRMask(16, 32)}
  43. e3 := &net.IPNet{IP: net.ParseIP("10.1.0.3").To4(), Mask: net.CIDRMask(16, 32)}
  44. e4 := &net.IPNet{IP: net.ParseIP("10.1.0.4").To4(), Mask: net.CIDRMask(16, 32)}
  45. i1 := &net.IPNet{IP: net.ParseIP("192.168.0.1").To4(), Mask: net.CIDRMask(32, 32)}
  46. i2 := &net.IPNet{IP: net.ParseIP("192.168.0.2").To4(), Mask: net.CIDRMask(32, 32)}
  47. i3 := &net.IPNet{IP: net.ParseIP("192.168.178.3").To4(), Mask: net.CIDRMask(32, 32)}
  48. nodes := map[string]*Node{
  49. "a": {
  50. Name: "a",
  51. Endpoint: wireguard.NewEndpoint(e1.IP, DefaultKiloPort),
  52. InternalIP: i1,
  53. Location: "1",
  54. Subnet: &net.IPNet{IP: net.ParseIP("10.2.1.0"), Mask: net.CIDRMask(24, 32)},
  55. Key: key1,
  56. PersistentKeepalive: 25,
  57. },
  58. "b": {
  59. Name: "b",
  60. Endpoint: wireguard.NewEndpoint(e2.IP, DefaultKiloPort),
  61. InternalIP: i1,
  62. Location: "2",
  63. Subnet: &net.IPNet{IP: net.ParseIP("10.2.2.0"), Mask: net.CIDRMask(24, 32)},
  64. Key: key2,
  65. AllowedLocationIPs: []net.IPNet{*i3},
  66. },
  67. "c": {
  68. Name: "c",
  69. Endpoint: wireguard.NewEndpoint(e3.IP, DefaultKiloPort),
  70. InternalIP: i2,
  71. // Same location as node b.
  72. Location: "2",
  73. Subnet: &net.IPNet{IP: net.ParseIP("10.2.3.0"), Mask: net.CIDRMask(24, 32)},
  74. Key: key3,
  75. },
  76. "d": {
  77. Name: "d",
  78. Endpoint: wireguard.NewEndpoint(e4.IP, DefaultKiloPort),
  79. // Same location as node a, but without private IP
  80. Location: "1",
  81. Subnet: &net.IPNet{IP: net.ParseIP("10.2.4.0"), Mask: net.CIDRMask(24, 32)},
  82. Key: key4,
  83. },
  84. }
  85. peers := map[string]*Peer{
  86. "a": {
  87. Name: "a",
  88. Peer: wireguard.Peer{
  89. PeerConfig: wgtypes.PeerConfig{
  90. AllowedIPs: []net.IPNet{
  91. {IP: net.ParseIP("10.5.0.1"), Mask: net.CIDRMask(24, 32)},
  92. {IP: net.ParseIP("10.5.0.2"), Mask: net.CIDRMask(24, 32)},
  93. },
  94. PublicKey: key4,
  95. },
  96. },
  97. },
  98. "b": {
  99. Name: "b",
  100. Peer: wireguard.Peer{
  101. PeerConfig: wgtypes.PeerConfig{
  102. AllowedIPs: []net.IPNet{
  103. {IP: net.ParseIP("10.5.0.3"), Mask: net.CIDRMask(24, 32)},
  104. },
  105. PublicKey: key5,
  106. },
  107. Endpoint: wireguard.NewEndpoint(net.ParseIP("192.168.0.1"), DefaultKiloPort),
  108. },
  109. },
  110. }
  111. return nodes, peers, key, DefaultKiloPort
  112. }
  113. func TestNewTopology(t *testing.T) {
  114. nodes, peers, key, port := setup(t)
  115. w1 := net.ParseIP("10.4.0.1").To4()
  116. w2 := net.ParseIP("10.4.0.2").To4()
  117. w3 := net.ParseIP("10.4.0.3").To4()
  118. w4 := net.ParseIP("10.4.0.4").To4()
  119. for _, tc := range []struct {
  120. name string
  121. granularity Granularity
  122. hostname string
  123. result *Topology
  124. }{
  125. {
  126. name: "logical from a",
  127. granularity: LogicalGranularity,
  128. hostname: nodes["a"].Name,
  129. result: &Topology{
  130. hostname: nodes["a"].Name,
  131. leader: true,
  132. location: logicalLocationPrefix + nodes["a"].Location,
  133. subnet: nodes["a"].Subnet,
  134. privateIP: nodes["a"].InternalIP,
  135. wireGuardCIDR: &net.IPNet{IP: w1, Mask: net.CIDRMask(16, 32)},
  136. segments: []*segment{
  137. {
  138. allowedIPs: []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  139. endpoint: nodes["a"].Endpoint,
  140. key: nodes["a"].Key,
  141. persistentKeepalive: nodes["a"].PersistentKeepalive,
  142. location: logicalLocationPrefix + nodes["a"].Location,
  143. cidrs: []*net.IPNet{nodes["a"].Subnet},
  144. hostnames: []string{"a"},
  145. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  146. cniCompatibilityIPs: []*net.IPNet{nil},
  147. wireGuardIP: w1,
  148. },
  149. {
  150. allowedIPs: []net.IPNet{*nodes["b"].Subnet, *nodes["b"].InternalIP, *nodes["c"].Subnet, *nodes["c"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  151. endpoint: nodes["b"].Endpoint,
  152. key: nodes["b"].Key,
  153. persistentKeepalive: nodes["b"].PersistentKeepalive,
  154. location: logicalLocationPrefix + nodes["b"].Location,
  155. cidrs: []*net.IPNet{nodes["b"].Subnet, nodes["c"].Subnet},
  156. hostnames: []string{"b", "c"},
  157. privateIPs: []net.IP{nodes["b"].InternalIP.IP, nodes["c"].InternalIP.IP},
  158. cniCompatibilityIPs: []*net.IPNet{nil, nil},
  159. wireGuardIP: w2,
  160. allowedLocationIPs: nodes["b"].AllowedLocationIPs,
  161. },
  162. {
  163. allowedIPs: []net.IPNet{*nodes["d"].Subnet, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  164. endpoint: nodes["d"].Endpoint,
  165. key: nodes["d"].Key,
  166. persistentKeepalive: nodes["d"].PersistentKeepalive,
  167. location: nodeLocationPrefix + nodes["d"].Name,
  168. cidrs: []*net.IPNet{nodes["d"].Subnet},
  169. hostnames: []string{"d"},
  170. privateIPs: nil,
  171. cniCompatibilityIPs: []*net.IPNet{nil},
  172. wireGuardIP: w3,
  173. },
  174. },
  175. peers: []*Peer{peers["a"], peers["b"]},
  176. logger: log.NewNopLogger(),
  177. },
  178. },
  179. {
  180. name: "logical from b",
  181. granularity: LogicalGranularity,
  182. hostname: nodes["b"].Name,
  183. result: &Topology{
  184. hostname: nodes["b"].Name,
  185. leader: true,
  186. location: logicalLocationPrefix + nodes["b"].Location,
  187. subnet: nodes["b"].Subnet,
  188. privateIP: nodes["b"].InternalIP,
  189. wireGuardCIDR: &net.IPNet{IP: w2, Mask: net.CIDRMask(16, 32)},
  190. segments: []*segment{
  191. {
  192. allowedIPs: []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  193. endpoint: nodes["a"].Endpoint,
  194. key: nodes["a"].Key,
  195. persistentKeepalive: nodes["a"].PersistentKeepalive,
  196. location: logicalLocationPrefix + nodes["a"].Location,
  197. cidrs: []*net.IPNet{nodes["a"].Subnet},
  198. hostnames: []string{"a"},
  199. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  200. cniCompatibilityIPs: []*net.IPNet{nil},
  201. wireGuardIP: w1,
  202. },
  203. {
  204. allowedIPs: []net.IPNet{*nodes["b"].Subnet, *nodes["b"].InternalIP, *nodes["c"].Subnet, *nodes["c"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  205. endpoint: nodes["b"].Endpoint,
  206. key: nodes["b"].Key,
  207. persistentKeepalive: nodes["b"].PersistentKeepalive,
  208. location: logicalLocationPrefix + nodes["b"].Location,
  209. cidrs: []*net.IPNet{nodes["b"].Subnet, nodes["c"].Subnet},
  210. hostnames: []string{"b", "c"},
  211. privateIPs: []net.IP{nodes["b"].InternalIP.IP, nodes["c"].InternalIP.IP},
  212. cniCompatibilityIPs: []*net.IPNet{nil, nil},
  213. wireGuardIP: w2,
  214. allowedLocationIPs: nodes["b"].AllowedLocationIPs,
  215. },
  216. {
  217. allowedIPs: []net.IPNet{*nodes["d"].Subnet, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  218. endpoint: nodes["d"].Endpoint,
  219. key: nodes["d"].Key,
  220. persistentKeepalive: nodes["d"].PersistentKeepalive,
  221. location: nodeLocationPrefix + nodes["d"].Name,
  222. cidrs: []*net.IPNet{nodes["d"].Subnet},
  223. hostnames: []string{"d"},
  224. privateIPs: nil,
  225. cniCompatibilityIPs: []*net.IPNet{nil},
  226. wireGuardIP: w3,
  227. },
  228. },
  229. peers: []*Peer{peers["a"], peers["b"]},
  230. logger: log.NewNopLogger(),
  231. },
  232. },
  233. {
  234. name: "logical from c",
  235. granularity: LogicalGranularity,
  236. hostname: nodes["c"].Name,
  237. result: &Topology{
  238. hostname: nodes["c"].Name,
  239. leader: false,
  240. location: logicalLocationPrefix + nodes["b"].Location,
  241. subnet: nodes["c"].Subnet,
  242. privateIP: nodes["c"].InternalIP,
  243. wireGuardCIDR: DefaultKiloSubnet,
  244. segments: []*segment{
  245. {
  246. allowedIPs: []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  247. endpoint: nodes["a"].Endpoint,
  248. key: nodes["a"].Key,
  249. persistentKeepalive: nodes["a"].PersistentKeepalive,
  250. location: logicalLocationPrefix + nodes["a"].Location,
  251. cidrs: []*net.IPNet{nodes["a"].Subnet},
  252. hostnames: []string{"a"},
  253. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  254. cniCompatibilityIPs: []*net.IPNet{nil},
  255. wireGuardIP: w1,
  256. },
  257. {
  258. allowedIPs: []net.IPNet{*nodes["b"].Subnet, *nodes["b"].InternalIP, *nodes["c"].Subnet, *nodes["c"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  259. endpoint: nodes["b"].Endpoint,
  260. key: nodes["b"].Key,
  261. persistentKeepalive: nodes["b"].PersistentKeepalive,
  262. location: logicalLocationPrefix + nodes["b"].Location,
  263. cidrs: []*net.IPNet{nodes["b"].Subnet, nodes["c"].Subnet},
  264. hostnames: []string{"b", "c"},
  265. privateIPs: []net.IP{nodes["b"].InternalIP.IP, nodes["c"].InternalIP.IP},
  266. cniCompatibilityIPs: []*net.IPNet{nil, nil},
  267. wireGuardIP: w2,
  268. allowedLocationIPs: nodes["b"].AllowedLocationIPs,
  269. },
  270. {
  271. allowedIPs: []net.IPNet{*nodes["d"].Subnet, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  272. endpoint: nodes["d"].Endpoint,
  273. key: nodes["d"].Key,
  274. persistentKeepalive: nodes["d"].PersistentKeepalive,
  275. location: nodeLocationPrefix + nodes["d"].Name,
  276. cidrs: []*net.IPNet{nodes["d"].Subnet},
  277. hostnames: []string{"d"},
  278. privateIPs: nil,
  279. cniCompatibilityIPs: []*net.IPNet{nil},
  280. wireGuardIP: w3,
  281. },
  282. },
  283. peers: []*Peer{peers["a"], peers["b"]},
  284. logger: log.NewNopLogger(),
  285. },
  286. },
  287. {
  288. name: "full from a",
  289. granularity: FullGranularity,
  290. hostname: nodes["a"].Name,
  291. result: &Topology{
  292. hostname: nodes["a"].Name,
  293. leader: true,
  294. location: nodeLocationPrefix + nodes["a"].Name,
  295. subnet: nodes["a"].Subnet,
  296. privateIP: nodes["a"].InternalIP,
  297. wireGuardCIDR: &net.IPNet{IP: w1, Mask: net.CIDRMask(16, 32)},
  298. segments: []*segment{
  299. {
  300. allowedIPs: []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  301. endpoint: nodes["a"].Endpoint,
  302. key: nodes["a"].Key,
  303. persistentKeepalive: nodes["a"].PersistentKeepalive,
  304. location: nodeLocationPrefix + nodes["a"].Name,
  305. cidrs: []*net.IPNet{nodes["a"].Subnet},
  306. hostnames: []string{"a"},
  307. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  308. cniCompatibilityIPs: []*net.IPNet{nil},
  309. wireGuardIP: w1,
  310. },
  311. {
  312. allowedIPs: []net.IPNet{*nodes["b"].Subnet, *nodes["b"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  313. endpoint: nodes["b"].Endpoint,
  314. key: nodes["b"].Key,
  315. persistentKeepalive: nodes["b"].PersistentKeepalive,
  316. location: nodeLocationPrefix + nodes["b"].Name,
  317. cidrs: []*net.IPNet{nodes["b"].Subnet},
  318. hostnames: []string{"b"},
  319. privateIPs: []net.IP{nodes["b"].InternalIP.IP},
  320. cniCompatibilityIPs: []*net.IPNet{nil},
  321. wireGuardIP: w2,
  322. allowedLocationIPs: nodes["b"].AllowedLocationIPs,
  323. },
  324. {
  325. allowedIPs: []net.IPNet{*nodes["c"].Subnet, *nodes["c"].InternalIP, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  326. endpoint: nodes["c"].Endpoint,
  327. key: nodes["c"].Key,
  328. persistentKeepalive: nodes["c"].PersistentKeepalive,
  329. location: nodeLocationPrefix + nodes["c"].Name,
  330. cidrs: []*net.IPNet{nodes["c"].Subnet},
  331. hostnames: []string{"c"},
  332. privateIPs: []net.IP{nodes["c"].InternalIP.IP},
  333. cniCompatibilityIPs: []*net.IPNet{nil},
  334. wireGuardIP: w3,
  335. },
  336. {
  337. allowedIPs: []net.IPNet{*nodes["d"].Subnet, {IP: w4, Mask: net.CIDRMask(32, 32)}},
  338. endpoint: nodes["d"].Endpoint,
  339. key: nodes["d"].Key,
  340. persistentKeepalive: nodes["d"].PersistentKeepalive,
  341. location: nodeLocationPrefix + nodes["d"].Name,
  342. cidrs: []*net.IPNet{nodes["d"].Subnet},
  343. hostnames: []string{"d"},
  344. privateIPs: nil,
  345. cniCompatibilityIPs: []*net.IPNet{nil},
  346. wireGuardIP: w4,
  347. },
  348. },
  349. peers: []*Peer{peers["a"], peers["b"]},
  350. logger: log.NewNopLogger(),
  351. },
  352. },
  353. {
  354. name: "full from b",
  355. granularity: FullGranularity,
  356. hostname: nodes["b"].Name,
  357. result: &Topology{
  358. hostname: nodes["b"].Name,
  359. leader: true,
  360. location: nodeLocationPrefix + nodes["b"].Name,
  361. subnet: nodes["b"].Subnet,
  362. privateIP: nodes["b"].InternalIP,
  363. wireGuardCIDR: &net.IPNet{IP: w2, Mask: net.CIDRMask(16, 32)},
  364. segments: []*segment{
  365. {
  366. allowedIPs: []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  367. endpoint: nodes["a"].Endpoint,
  368. key: nodes["a"].Key,
  369. persistentKeepalive: nodes["a"].PersistentKeepalive,
  370. location: nodeLocationPrefix + nodes["a"].Name,
  371. cidrs: []*net.IPNet{nodes["a"].Subnet},
  372. hostnames: []string{"a"},
  373. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  374. cniCompatibilityIPs: []*net.IPNet{nil},
  375. wireGuardIP: w1,
  376. },
  377. {
  378. allowedIPs: []net.IPNet{*nodes["b"].Subnet, *nodes["b"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  379. endpoint: nodes["b"].Endpoint,
  380. key: nodes["b"].Key,
  381. persistentKeepalive: nodes["b"].PersistentKeepalive,
  382. location: nodeLocationPrefix + nodes["b"].Name,
  383. cidrs: []*net.IPNet{nodes["b"].Subnet},
  384. hostnames: []string{"b"},
  385. privateIPs: []net.IP{nodes["b"].InternalIP.IP},
  386. cniCompatibilityIPs: []*net.IPNet{nil},
  387. wireGuardIP: w2,
  388. allowedLocationIPs: nodes["b"].AllowedLocationIPs,
  389. },
  390. {
  391. allowedIPs: []net.IPNet{*nodes["c"].Subnet, *nodes["c"].InternalIP, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  392. endpoint: nodes["c"].Endpoint,
  393. key: nodes["c"].Key,
  394. persistentKeepalive: nodes["c"].PersistentKeepalive,
  395. location: nodeLocationPrefix + nodes["c"].Name,
  396. cidrs: []*net.IPNet{nodes["c"].Subnet},
  397. hostnames: []string{"c"},
  398. privateIPs: []net.IP{nodes["c"].InternalIP.IP},
  399. cniCompatibilityIPs: []*net.IPNet{nil},
  400. wireGuardIP: w3,
  401. },
  402. {
  403. allowedIPs: []net.IPNet{*nodes["d"].Subnet, {IP: w4, Mask: net.CIDRMask(32, 32)}},
  404. endpoint: nodes["d"].Endpoint,
  405. key: nodes["d"].Key,
  406. persistentKeepalive: nodes["d"].PersistentKeepalive,
  407. location: nodeLocationPrefix + nodes["d"].Name,
  408. cidrs: []*net.IPNet{nodes["d"].Subnet},
  409. hostnames: []string{"d"},
  410. privateIPs: nil,
  411. cniCompatibilityIPs: []*net.IPNet{nil},
  412. wireGuardIP: w4,
  413. },
  414. },
  415. peers: []*Peer{peers["a"], peers["b"]},
  416. logger: log.NewNopLogger(),
  417. },
  418. },
  419. {
  420. name: "full from c",
  421. granularity: FullGranularity,
  422. hostname: nodes["c"].Name,
  423. result: &Topology{
  424. hostname: nodes["c"].Name,
  425. leader: true,
  426. location: nodeLocationPrefix + nodes["c"].Name,
  427. subnet: nodes["c"].Subnet,
  428. privateIP: nodes["c"].InternalIP,
  429. wireGuardCIDR: &net.IPNet{IP: w3, Mask: net.CIDRMask(16, 32)},
  430. segments: []*segment{
  431. {
  432. allowedIPs: []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  433. endpoint: nodes["a"].Endpoint,
  434. key: nodes["a"].Key,
  435. persistentKeepalive: nodes["a"].PersistentKeepalive,
  436. location: nodeLocationPrefix + nodes["a"].Name,
  437. cidrs: []*net.IPNet{nodes["a"].Subnet},
  438. hostnames: []string{"a"},
  439. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  440. cniCompatibilityIPs: []*net.IPNet{nil},
  441. wireGuardIP: w1,
  442. },
  443. {
  444. allowedIPs: []net.IPNet{*nodes["b"].Subnet, *nodes["b"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  445. endpoint: nodes["b"].Endpoint,
  446. key: nodes["b"].Key,
  447. persistentKeepalive: nodes["b"].PersistentKeepalive,
  448. location: nodeLocationPrefix + nodes["b"].Name,
  449. cidrs: []*net.IPNet{nodes["b"].Subnet},
  450. hostnames: []string{"b"},
  451. privateIPs: []net.IP{nodes["b"].InternalIP.IP},
  452. cniCompatibilityIPs: []*net.IPNet{nil},
  453. wireGuardIP: w2,
  454. allowedLocationIPs: nodes["b"].AllowedLocationIPs,
  455. },
  456. {
  457. allowedIPs: []net.IPNet{*nodes["c"].Subnet, *nodes["c"].InternalIP, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  458. endpoint: nodes["c"].Endpoint,
  459. key: nodes["c"].Key,
  460. persistentKeepalive: nodes["c"].PersistentKeepalive,
  461. location: nodeLocationPrefix + nodes["c"].Name,
  462. cidrs: []*net.IPNet{nodes["c"].Subnet},
  463. hostnames: []string{"c"},
  464. privateIPs: []net.IP{nodes["c"].InternalIP.IP},
  465. cniCompatibilityIPs: []*net.IPNet{nil},
  466. wireGuardIP: w3,
  467. },
  468. {
  469. allowedIPs: []net.IPNet{*nodes["d"].Subnet, {IP: w4, Mask: net.CIDRMask(32, 32)}},
  470. endpoint: nodes["d"].Endpoint,
  471. key: nodes["d"].Key,
  472. persistentKeepalive: nodes["d"].PersistentKeepalive,
  473. location: nodeLocationPrefix + nodes["d"].Name,
  474. cidrs: []*net.IPNet{nodes["d"].Subnet},
  475. hostnames: []string{"d"},
  476. privateIPs: nil,
  477. cniCompatibilityIPs: []*net.IPNet{nil},
  478. wireGuardIP: w4,
  479. },
  480. },
  481. peers: []*Peer{peers["a"], peers["b"]},
  482. logger: log.NewNopLogger(),
  483. },
  484. },
  485. {
  486. name: "full from d",
  487. granularity: FullGranularity,
  488. hostname: nodes["d"].Name,
  489. result: &Topology{
  490. hostname: nodes["d"].Name,
  491. leader: true,
  492. location: nodeLocationPrefix + nodes["d"].Name,
  493. subnet: nodes["d"].Subnet,
  494. privateIP: nil,
  495. wireGuardCIDR: &net.IPNet{IP: w4, Mask: net.CIDRMask(16, 32)},
  496. segments: []*segment{
  497. {
  498. allowedIPs: []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  499. endpoint: nodes["a"].Endpoint,
  500. key: nodes["a"].Key,
  501. persistentKeepalive: nodes["a"].PersistentKeepalive,
  502. location: nodeLocationPrefix + nodes["a"].Name,
  503. cidrs: []*net.IPNet{nodes["a"].Subnet},
  504. hostnames: []string{"a"},
  505. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  506. cniCompatibilityIPs: []*net.IPNet{nil},
  507. wireGuardIP: w1,
  508. },
  509. {
  510. allowedIPs: []net.IPNet{*nodes["b"].Subnet, *nodes["b"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  511. endpoint: nodes["b"].Endpoint,
  512. key: nodes["b"].Key,
  513. persistentKeepalive: nodes["b"].PersistentKeepalive,
  514. location: nodeLocationPrefix + nodes["b"].Name,
  515. cidrs: []*net.IPNet{nodes["b"].Subnet},
  516. hostnames: []string{"b"},
  517. privateIPs: []net.IP{nodes["b"].InternalIP.IP},
  518. cniCompatibilityIPs: []*net.IPNet{nil},
  519. wireGuardIP: w2,
  520. allowedLocationIPs: nodes["b"].AllowedLocationIPs,
  521. },
  522. {
  523. allowedIPs: []net.IPNet{*nodes["c"].Subnet, *nodes["c"].InternalIP, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  524. endpoint: nodes["c"].Endpoint,
  525. key: nodes["c"].Key,
  526. persistentKeepalive: nodes["c"].PersistentKeepalive,
  527. location: nodeLocationPrefix + nodes["c"].Name,
  528. cidrs: []*net.IPNet{nodes["c"].Subnet},
  529. hostnames: []string{"c"},
  530. privateIPs: []net.IP{nodes["c"].InternalIP.IP},
  531. cniCompatibilityIPs: []*net.IPNet{nil},
  532. wireGuardIP: w3,
  533. },
  534. {
  535. allowedIPs: []net.IPNet{*nodes["d"].Subnet, {IP: w4, Mask: net.CIDRMask(32, 32)}},
  536. endpoint: nodes["d"].Endpoint,
  537. key: nodes["d"].Key,
  538. persistentKeepalive: nodes["d"].PersistentKeepalive,
  539. location: nodeLocationPrefix + nodes["d"].Name,
  540. cidrs: []*net.IPNet{nodes["d"].Subnet},
  541. hostnames: []string{"d"},
  542. privateIPs: nil,
  543. cniCompatibilityIPs: []*net.IPNet{nil},
  544. wireGuardIP: w4,
  545. },
  546. },
  547. peers: []*Peer{peers["a"], peers["b"]},
  548. logger: log.NewNopLogger(),
  549. },
  550. },
  551. } {
  552. tc.result.key = key
  553. tc.result.port = port
  554. topo, err := NewTopology(nodes, peers, tc.granularity, tc.hostname, port, key, DefaultKiloSubnet, nil, 0, nil)
  555. if err != nil {
  556. t.Errorf("test case %q: failed to generate Topology: %v", tc.name, err)
  557. }
  558. if diff := pretty.Compare(topo, tc.result); diff != "" {
  559. t.Errorf("test case %q: got diff: %v", tc.name, diff)
  560. }
  561. }
  562. }
  563. func mustTopo(t *testing.T, nodes map[string]*Node, peers map[string]*Peer, granularity Granularity, hostname string, port int, key wgtypes.Key, subnet *net.IPNet, persistentKeepalive time.Duration) *Topology {
  564. topo, err := NewTopology(nodes, peers, granularity, hostname, port, key, subnet, nil, persistentKeepalive, nil)
  565. if err != nil {
  566. t.Errorf("failed to generate Topology: %v", err)
  567. }
  568. return topo
  569. }
  570. func TestFindLeader(t *testing.T) {
  571. ip, e1, err := net.ParseCIDR("10.0.0.1/32")
  572. if err != nil {
  573. t.Fatalf("failed to parse external IP CIDR: %v", err)
  574. }
  575. e1.IP = ip
  576. ip, e2, err := net.ParseCIDR("8.8.8.8/32")
  577. if err != nil {
  578. t.Fatalf("failed to parse external IP CIDR: %v", err)
  579. }
  580. e2.IP = ip
  581. nodes := []*Node{
  582. {
  583. Name: "a",
  584. Endpoint: wireguard.NewEndpoint(e1.IP, DefaultKiloPort),
  585. },
  586. {
  587. Name: "b",
  588. Endpoint: wireguard.NewEndpoint(e2.IP, DefaultKiloPort),
  589. },
  590. {
  591. Name: "c",
  592. Endpoint: wireguard.NewEndpoint(e2.IP, DefaultKiloPort),
  593. },
  594. {
  595. Name: "d",
  596. Endpoint: wireguard.NewEndpoint(e1.IP, DefaultKiloPort),
  597. Leader: true,
  598. },
  599. {
  600. Name: "2",
  601. Endpoint: wireguard.NewEndpoint(e2.IP, DefaultKiloPort),
  602. Leader: true,
  603. },
  604. }
  605. for _, tc := range []struct {
  606. name string
  607. nodes []*Node
  608. out int
  609. }{
  610. {
  611. name: "nil",
  612. nodes: nil,
  613. out: 0,
  614. },
  615. {
  616. name: "one",
  617. nodes: []*Node{nodes[0]},
  618. out: 0,
  619. },
  620. {
  621. name: "non-leaders",
  622. nodes: []*Node{nodes[0], nodes[1], nodes[2]},
  623. out: 1,
  624. },
  625. {
  626. name: "leaders",
  627. nodes: []*Node{nodes[3], nodes[4]},
  628. out: 1,
  629. },
  630. {
  631. name: "public",
  632. nodes: []*Node{nodes[1], nodes[2], nodes[4]},
  633. out: 2,
  634. },
  635. {
  636. name: "private",
  637. nodes: []*Node{nodes[0], nodes[3]},
  638. out: 1,
  639. },
  640. {
  641. name: "all",
  642. nodes: nodes,
  643. out: 4,
  644. },
  645. } {
  646. l := findLeader(tc.nodes)
  647. if l != tc.out {
  648. t.Errorf("test case %q: expected %d got %d", tc.name, tc.out, l)
  649. }
  650. }
  651. }
  652. func TestDeduplicatePeerIPs(t *testing.T) {
  653. p1 := &Peer{
  654. Name: "1",
  655. Peer: wireguard.Peer{
  656. PeerConfig: wgtypes.PeerConfig{
  657. PublicKey: key1,
  658. AllowedIPs: []net.IPNet{
  659. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  660. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(24, 32)},
  661. },
  662. },
  663. },
  664. }
  665. p2 := &Peer{
  666. Name: "2",
  667. Peer: wireguard.Peer{
  668. PeerConfig: wgtypes.PeerConfig{
  669. PublicKey: key2,
  670. AllowedIPs: []net.IPNet{
  671. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  672. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  673. },
  674. },
  675. },
  676. }
  677. p3 := &Peer{
  678. Name: "3",
  679. Peer: wireguard.Peer{
  680. PeerConfig: wgtypes.PeerConfig{
  681. PublicKey: key3,
  682. AllowedIPs: []net.IPNet{
  683. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(24, 32)},
  684. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  685. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  686. },
  687. },
  688. },
  689. }
  690. p4 := &Peer{
  691. Name: "4",
  692. Peer: wireguard.Peer{
  693. PeerConfig: wgtypes.PeerConfig{
  694. PublicKey: key4,
  695. AllowedIPs: []net.IPNet{
  696. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  697. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  698. },
  699. },
  700. },
  701. }
  702. for _, tc := range []struct {
  703. name string
  704. peers []*Peer
  705. out []*Peer
  706. }{
  707. {
  708. name: "nil",
  709. peers: nil,
  710. out: nil,
  711. },
  712. {
  713. name: "simple dupe",
  714. peers: []*Peer{p1, p2},
  715. out: []*Peer{
  716. p1,
  717. {
  718. Name: "2",
  719. Peer: wireguard.Peer{
  720. PeerConfig: wgtypes.PeerConfig{
  721. PublicKey: key2,
  722. AllowedIPs: []net.IPNet{
  723. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  724. },
  725. },
  726. },
  727. },
  728. },
  729. },
  730. {
  731. name: "simple dupe reversed",
  732. peers: []*Peer{p2, p1},
  733. out: []*Peer{
  734. p2,
  735. {
  736. Name: "1",
  737. Peer: wireguard.Peer{
  738. PeerConfig: wgtypes.PeerConfig{
  739. PublicKey: key1,
  740. AllowedIPs: []net.IPNet{
  741. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(24, 32)},
  742. },
  743. },
  744. },
  745. },
  746. },
  747. },
  748. {
  749. name: "one duplicates all",
  750. peers: []*Peer{p3, p2, p1, p4},
  751. out: []*Peer{
  752. p3,
  753. {
  754. Name: "2",
  755. Peer: wireguard.Peer{
  756. PeerConfig: wgtypes.PeerConfig{
  757. PublicKey: key2,
  758. },
  759. },
  760. },
  761. {
  762. Name: "1",
  763. Peer: wireguard.Peer{
  764. PeerConfig: wgtypes.PeerConfig{
  765. PublicKey: key1,
  766. },
  767. },
  768. },
  769. {
  770. Name: "4",
  771. Peer: wireguard.Peer{
  772. PeerConfig: wgtypes.PeerConfig{
  773. PublicKey: key4,
  774. },
  775. },
  776. },
  777. },
  778. },
  779. {
  780. name: "one duplicates itself",
  781. peers: []*Peer{p4, p1},
  782. out: []*Peer{
  783. {
  784. Name: "4",
  785. Peer: wireguard.Peer{
  786. PeerConfig: wgtypes.PeerConfig{
  787. PublicKey: key4,
  788. AllowedIPs: []net.IPNet{
  789. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  790. },
  791. },
  792. },
  793. },
  794. {
  795. Name: "1",
  796. Peer: wireguard.Peer{
  797. PeerConfig: wgtypes.PeerConfig{
  798. PublicKey: key1,
  799. AllowedIPs: []net.IPNet{
  800. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  801. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(24, 32)},
  802. },
  803. },
  804. },
  805. },
  806. },
  807. },
  808. } {
  809. out := deduplicatePeerIPs(tc.peers)
  810. if diff := pretty.Compare(out, tc.out); diff != "" {
  811. t.Errorf("test case %q: got diff: %v", tc.name, diff)
  812. }
  813. }
  814. }
  815. func TestFilterAllowedIPs(t *testing.T) {
  816. nodes, peers, key, port := setup(t)
  817. topo := mustTopo(t, nodes, peers, LogicalGranularity, nodes["a"].Name, port, key, DefaultKiloSubnet, nodes["a"].PersistentKeepalive)
  818. for _, tc := range []struct {
  819. name string
  820. allowedLocationIPs map[int][]net.IPNet
  821. result map[int][]net.IPNet
  822. }{
  823. {
  824. name: "nothing to filter",
  825. allowedLocationIPs: map[int][]net.IPNet{
  826. 0: {
  827. mustParseCIDR("192.168.178.4/32"),
  828. },
  829. 1: {
  830. mustParseCIDR("192.168.178.5/32"),
  831. },
  832. 2: {
  833. mustParseCIDR("192.168.178.6/32"),
  834. mustParseCIDR("192.168.178.7/32"),
  835. },
  836. },
  837. result: map[int][]net.IPNet{
  838. 0: {
  839. mustParseCIDR("192.168.178.4/32"),
  840. },
  841. 1: {
  842. mustParseCIDR("192.168.178.5/32"),
  843. },
  844. 2: {
  845. mustParseCIDR("192.168.178.6/32"),
  846. mustParseCIDR("192.168.178.7/32"),
  847. },
  848. },
  849. },
  850. {
  851. name: "intersections between segments",
  852. allowedLocationIPs: map[int][]net.IPNet{
  853. 0: {
  854. mustParseCIDR("192.168.178.4/32"),
  855. mustParseCIDR("192.168.178.8/32"),
  856. },
  857. 1: {
  858. mustParseCIDR("192.168.178.5/32"),
  859. },
  860. 2: {
  861. mustParseCIDR("192.168.178.6/32"),
  862. mustParseCIDR("192.168.178.7/32"),
  863. mustParseCIDR("192.168.178.4/32"),
  864. },
  865. },
  866. result: map[int][]net.IPNet{
  867. 0: {
  868. mustParseCIDR("192.168.178.8/32"),
  869. },
  870. 1: {
  871. mustParseCIDR("192.168.178.5/32"),
  872. },
  873. 2: {
  874. mustParseCIDR("192.168.178.6/32"),
  875. mustParseCIDR("192.168.178.7/32"),
  876. mustParseCIDR("192.168.178.4/32"),
  877. },
  878. },
  879. },
  880. {
  881. name: "intersections with wireGuardCIDR",
  882. allowedLocationIPs: map[int][]net.IPNet{
  883. 0: {
  884. mustParseCIDR("10.4.0.1/32"),
  885. mustParseCIDR("192.168.178.8/32"),
  886. },
  887. 1: {
  888. mustParseCIDR("192.168.178.5/32"),
  889. },
  890. 2: {
  891. mustParseCIDR("192.168.178.6/32"),
  892. mustParseCIDR("192.168.178.7/32"),
  893. },
  894. },
  895. result: map[int][]net.IPNet{
  896. 0: {
  897. mustParseCIDR("192.168.178.8/32"),
  898. },
  899. 1: {
  900. mustParseCIDR("192.168.178.5/32"),
  901. },
  902. 2: {
  903. mustParseCIDR("192.168.178.6/32"),
  904. mustParseCIDR("192.168.178.7/32"),
  905. },
  906. },
  907. },
  908. {
  909. name: "intersections with more than one allowedLocationIPs",
  910. allowedLocationIPs: map[int][]net.IPNet{
  911. 0: {
  912. mustParseCIDR("192.168.178.8/32"),
  913. },
  914. 1: {
  915. mustParseCIDR("192.168.178.5/32"),
  916. },
  917. 2: {
  918. mustParseCIDR("192.168.178.7/24"),
  919. },
  920. },
  921. result: map[int][]net.IPNet{
  922. 0: {},
  923. 1: {},
  924. 2: {
  925. mustParseCIDR("192.168.178.7/24"),
  926. },
  927. },
  928. },
  929. } {
  930. for k, v := range tc.allowedLocationIPs {
  931. topo.segments[k].allowedLocationIPs = v
  932. }
  933. for k, v := range topo.segments {
  934. f := topo.filterAllowedLocationIPs(v.allowedLocationIPs, v.location)
  935. // Overwrite the allowedLocationIPs to mimic the actual usage of the filterAllowedLocationIPs function.
  936. topo.segments[k].allowedLocationIPs = f
  937. if !ipNetSlicesEqual(f, tc.result[k]) {
  938. t.Errorf("test case %q:\n\texpected:\n\t%q\n\tgot:\n\t%q\n", tc.name, tc.result[k], f)
  939. }
  940. }
  941. }
  942. }