topology_test.go 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615
  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. "strings"
  18. "testing"
  19. "github.com/kylelemons/godebug/pretty"
  20. "github.com/squat/kilo/pkg/encapsulation"
  21. "github.com/squat/kilo/pkg/wireguard"
  22. "github.com/vishvananda/netlink"
  23. "golang.org/x/sys/unix"
  24. )
  25. func allowedIPs(ips ...string) string {
  26. return strings.Join(ips, ", ")
  27. }
  28. func setup(t *testing.T) (map[string]*Node, map[string]*Peer, []byte, uint32) {
  29. key := []byte("private")
  30. e1 := &net.IPNet{IP: net.ParseIP("10.1.0.1").To4(), Mask: net.CIDRMask(16, 32)}
  31. e2 := &net.IPNet{IP: net.ParseIP("10.1.0.2").To4(), Mask: net.CIDRMask(16, 32)}
  32. e3 := &net.IPNet{IP: net.ParseIP("10.1.0.3").To4(), Mask: net.CIDRMask(16, 32)}
  33. i1 := &net.IPNet{IP: net.ParseIP("192.168.0.1").To4(), Mask: net.CIDRMask(32, 32)}
  34. i2 := &net.IPNet{IP: net.ParseIP("192.168.0.2").To4(), Mask: net.CIDRMask(32, 32)}
  35. nodes := map[string]*Node{
  36. "a": {
  37. Name: "a",
  38. Endpoint: &wireguard.Endpoint{DNSOrIP: wireguard.DNSOrIP{IP: e1.IP}, Port: DefaultKiloPort},
  39. InternalIP: i1,
  40. Location: "1",
  41. Subnet: &net.IPNet{IP: net.ParseIP("10.2.1.0"), Mask: net.CIDRMask(24, 32)},
  42. Key: []byte("key1"),
  43. PersistentKeepalive: 25,
  44. },
  45. "b": {
  46. Name: "b",
  47. Endpoint: &wireguard.Endpoint{DNSOrIP: wireguard.DNSOrIP{IP: e2.IP}, Port: DefaultKiloPort},
  48. InternalIP: i1,
  49. Location: "2",
  50. Subnet: &net.IPNet{IP: net.ParseIP("10.2.2.0"), Mask: net.CIDRMask(24, 32)},
  51. Key: []byte("key2"),
  52. },
  53. "c": {
  54. Name: "c",
  55. Endpoint: &wireguard.Endpoint{DNSOrIP: wireguard.DNSOrIP{IP: e3.IP}, Port: DefaultKiloPort},
  56. InternalIP: i2,
  57. // Same location a node b.
  58. Location: "2",
  59. Subnet: &net.IPNet{IP: net.ParseIP("10.2.3.0"), Mask: net.CIDRMask(24, 32)},
  60. Key: []byte("key3"),
  61. },
  62. }
  63. peers := map[string]*Peer{
  64. "a": {
  65. Name: "a",
  66. Peer: wireguard.Peer{
  67. AllowedIPs: []*net.IPNet{
  68. {IP: net.ParseIP("10.5.0.1"), Mask: net.CIDRMask(24, 32)},
  69. {IP: net.ParseIP("10.5.0.2"), Mask: net.CIDRMask(24, 32)},
  70. },
  71. PublicKey: []byte("key4"),
  72. },
  73. },
  74. "b": {
  75. Name: "b",
  76. Peer: wireguard.Peer{
  77. AllowedIPs: []*net.IPNet{
  78. {IP: net.ParseIP("10.5.0.3"), Mask: net.CIDRMask(24, 32)},
  79. },
  80. Endpoint: &wireguard.Endpoint{
  81. DNSOrIP: wireguard.DNSOrIP{IP: net.ParseIP("192.168.0.1")},
  82. Port: DefaultKiloPort,
  83. },
  84. PublicKey: []byte("key5"),
  85. },
  86. },
  87. }
  88. return nodes, peers, key, DefaultKiloPort
  89. }
  90. func TestNewTopology(t *testing.T) {
  91. nodes, peers, key, port := setup(t)
  92. w1 := net.ParseIP("10.4.0.1").To4()
  93. w2 := net.ParseIP("10.4.0.2").To4()
  94. w3 := net.ParseIP("10.4.0.3").To4()
  95. for _, tc := range []struct {
  96. name string
  97. granularity Granularity
  98. hostname string
  99. result *Topology
  100. }{
  101. {
  102. name: "logical from a",
  103. granularity: LogicalGranularity,
  104. hostname: nodes["a"].Name,
  105. result: &Topology{
  106. hostname: nodes["a"].Name,
  107. leader: true,
  108. location: nodes["a"].Location,
  109. subnet: nodes["a"].Subnet,
  110. privateIP: nodes["a"].InternalIP,
  111. wireGuardCIDR: &net.IPNet{IP: w1, Mask: net.CIDRMask(16, 32)},
  112. segments: []*segment{
  113. {
  114. allowedIPs: []*net.IPNet{nodes["a"].Subnet, nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  115. endpoint: nodes["a"].Endpoint,
  116. key: nodes["a"].Key,
  117. location: nodes["a"].Location,
  118. cidrs: []*net.IPNet{nodes["a"].Subnet},
  119. hostnames: []string{"a"},
  120. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  121. persistentKeepalive: nodes["a"].PersistentKeepalive,
  122. wireGuardIP: w1,
  123. },
  124. {
  125. allowedIPs: []*net.IPNet{nodes["b"].Subnet, nodes["b"].InternalIP, nodes["c"].Subnet, nodes["c"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  126. endpoint: nodes["b"].Endpoint,
  127. key: nodes["b"].Key,
  128. location: nodes["b"].Location,
  129. cidrs: []*net.IPNet{nodes["b"].Subnet, nodes["c"].Subnet},
  130. hostnames: []string{"b", "c"},
  131. privateIPs: []net.IP{nodes["b"].InternalIP.IP, nodes["c"].InternalIP.IP},
  132. wireGuardIP: w2,
  133. },
  134. },
  135. peers: []*Peer{peers["a"], peers["b"]},
  136. },
  137. },
  138. {
  139. name: "logical from b",
  140. granularity: LogicalGranularity,
  141. hostname: nodes["b"].Name,
  142. result: &Topology{
  143. hostname: nodes["b"].Name,
  144. leader: true,
  145. location: nodes["b"].Location,
  146. subnet: nodes["b"].Subnet,
  147. privateIP: nodes["b"].InternalIP,
  148. wireGuardCIDR: &net.IPNet{IP: w2, Mask: net.CIDRMask(16, 32)},
  149. segments: []*segment{
  150. {
  151. allowedIPs: []*net.IPNet{nodes["a"].Subnet, nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  152. endpoint: nodes["a"].Endpoint,
  153. key: nodes["a"].Key,
  154. location: nodes["a"].Location,
  155. cidrs: []*net.IPNet{nodes["a"].Subnet},
  156. hostnames: []string{"a"},
  157. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  158. persistentKeepalive: nodes["a"].PersistentKeepalive,
  159. wireGuardIP: w1,
  160. },
  161. {
  162. allowedIPs: []*net.IPNet{nodes["b"].Subnet, nodes["b"].InternalIP, nodes["c"].Subnet, nodes["c"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  163. endpoint: nodes["b"].Endpoint,
  164. key: nodes["b"].Key,
  165. location: nodes["b"].Location,
  166. cidrs: []*net.IPNet{nodes["b"].Subnet, nodes["c"].Subnet},
  167. hostnames: []string{"b", "c"},
  168. privateIPs: []net.IP{nodes["b"].InternalIP.IP, nodes["c"].InternalIP.IP},
  169. wireGuardIP: w2,
  170. },
  171. },
  172. peers: []*Peer{peers["a"], peers["b"]},
  173. },
  174. },
  175. {
  176. name: "logical from c",
  177. granularity: LogicalGranularity,
  178. hostname: nodes["c"].Name,
  179. result: &Topology{
  180. hostname: nodes["c"].Name,
  181. leader: false,
  182. location: nodes["b"].Location,
  183. subnet: nodes["c"].Subnet,
  184. privateIP: nodes["c"].InternalIP,
  185. wireGuardCIDR: nil,
  186. segments: []*segment{
  187. {
  188. allowedIPs: []*net.IPNet{nodes["a"].Subnet, nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  189. endpoint: nodes["a"].Endpoint,
  190. key: nodes["a"].Key,
  191. location: nodes["a"].Location,
  192. cidrs: []*net.IPNet{nodes["a"].Subnet},
  193. hostnames: []string{"a"},
  194. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  195. persistentKeepalive: nodes["a"].PersistentKeepalive,
  196. wireGuardIP: w1,
  197. },
  198. {
  199. allowedIPs: []*net.IPNet{nodes["b"].Subnet, nodes["b"].InternalIP, nodes["c"].Subnet, nodes["c"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  200. endpoint: nodes["b"].Endpoint,
  201. key: nodes["b"].Key,
  202. location: nodes["b"].Location,
  203. cidrs: []*net.IPNet{nodes["b"].Subnet, nodes["c"].Subnet},
  204. hostnames: []string{"b", "c"},
  205. privateIPs: []net.IP{nodes["b"].InternalIP.IP, nodes["c"].InternalIP.IP},
  206. wireGuardIP: w2,
  207. },
  208. },
  209. peers: []*Peer{peers["a"], peers["b"]},
  210. },
  211. },
  212. {
  213. name: "full from a",
  214. granularity: FullGranularity,
  215. hostname: nodes["a"].Name,
  216. result: &Topology{
  217. hostname: nodes["a"].Name,
  218. leader: true,
  219. location: nodes["a"].Name,
  220. subnet: nodes["a"].Subnet,
  221. privateIP: nodes["a"].InternalIP,
  222. wireGuardCIDR: &net.IPNet{IP: w1, Mask: net.CIDRMask(16, 32)},
  223. segments: []*segment{
  224. {
  225. allowedIPs: []*net.IPNet{nodes["a"].Subnet, nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  226. endpoint: nodes["a"].Endpoint,
  227. key: nodes["a"].Key,
  228. location: nodes["a"].Name,
  229. cidrs: []*net.IPNet{nodes["a"].Subnet},
  230. hostnames: []string{"a"},
  231. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  232. persistentKeepalive: nodes["a"].PersistentKeepalive,
  233. wireGuardIP: w1,
  234. },
  235. {
  236. allowedIPs: []*net.IPNet{nodes["b"].Subnet, nodes["b"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  237. endpoint: nodes["b"].Endpoint,
  238. key: nodes["b"].Key,
  239. location: nodes["b"].Name,
  240. cidrs: []*net.IPNet{nodes["b"].Subnet},
  241. hostnames: []string{"b"},
  242. privateIPs: []net.IP{nodes["b"].InternalIP.IP},
  243. wireGuardIP: w2,
  244. },
  245. {
  246. allowedIPs: []*net.IPNet{nodes["c"].Subnet, nodes["c"].InternalIP, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  247. endpoint: nodes["c"].Endpoint,
  248. key: nodes["c"].Key,
  249. location: nodes["c"].Name,
  250. cidrs: []*net.IPNet{nodes["c"].Subnet},
  251. hostnames: []string{"c"},
  252. privateIPs: []net.IP{nodes["c"].InternalIP.IP},
  253. wireGuardIP: w3,
  254. },
  255. },
  256. peers: []*Peer{peers["a"], peers["b"]},
  257. },
  258. },
  259. {
  260. name: "full from b",
  261. granularity: FullGranularity,
  262. hostname: nodes["b"].Name,
  263. result: &Topology{
  264. hostname: nodes["b"].Name,
  265. leader: true,
  266. location: nodes["b"].Name,
  267. subnet: nodes["b"].Subnet,
  268. privateIP: nodes["b"].InternalIP,
  269. wireGuardCIDR: &net.IPNet{IP: w2, Mask: net.CIDRMask(16, 32)},
  270. segments: []*segment{
  271. {
  272. allowedIPs: []*net.IPNet{nodes["a"].Subnet, nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  273. endpoint: nodes["a"].Endpoint,
  274. key: nodes["a"].Key,
  275. location: nodes["a"].Name,
  276. cidrs: []*net.IPNet{nodes["a"].Subnet},
  277. hostnames: []string{"a"},
  278. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  279. persistentKeepalive: nodes["a"].PersistentKeepalive,
  280. wireGuardIP: w1,
  281. },
  282. {
  283. allowedIPs: []*net.IPNet{nodes["b"].Subnet, nodes["b"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  284. endpoint: nodes["b"].Endpoint,
  285. key: nodes["b"].Key,
  286. location: nodes["b"].Name,
  287. cidrs: []*net.IPNet{nodes["b"].Subnet},
  288. hostnames: []string{"b"},
  289. privateIPs: []net.IP{nodes["b"].InternalIP.IP},
  290. wireGuardIP: w2,
  291. },
  292. {
  293. allowedIPs: []*net.IPNet{nodes["c"].Subnet, nodes["c"].InternalIP, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  294. endpoint: nodes["c"].Endpoint,
  295. key: nodes["c"].Key,
  296. location: nodes["c"].Name,
  297. cidrs: []*net.IPNet{nodes["c"].Subnet},
  298. hostnames: []string{"c"},
  299. privateIPs: []net.IP{nodes["c"].InternalIP.IP},
  300. wireGuardIP: w3,
  301. },
  302. },
  303. peers: []*Peer{peers["a"], peers["b"]},
  304. },
  305. },
  306. {
  307. name: "full from c",
  308. granularity: FullGranularity,
  309. hostname: nodes["c"].Name,
  310. result: &Topology{
  311. hostname: nodes["c"].Name,
  312. leader: true,
  313. location: nodes["c"].Name,
  314. subnet: nodes["c"].Subnet,
  315. privateIP: nodes["c"].InternalIP,
  316. wireGuardCIDR: &net.IPNet{IP: w3, Mask: net.CIDRMask(16, 32)},
  317. segments: []*segment{
  318. {
  319. allowedIPs: []*net.IPNet{nodes["a"].Subnet, nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}},
  320. endpoint: nodes["a"].Endpoint,
  321. key: nodes["a"].Key,
  322. location: nodes["a"].Name,
  323. cidrs: []*net.IPNet{nodes["a"].Subnet},
  324. hostnames: []string{"a"},
  325. privateIPs: []net.IP{nodes["a"].InternalIP.IP},
  326. persistentKeepalive: nodes["a"].PersistentKeepalive,
  327. wireGuardIP: w1,
  328. },
  329. {
  330. allowedIPs: []*net.IPNet{nodes["b"].Subnet, nodes["b"].InternalIP, {IP: w2, Mask: net.CIDRMask(32, 32)}},
  331. endpoint: nodes["b"].Endpoint,
  332. key: nodes["b"].Key,
  333. location: nodes["b"].Name,
  334. cidrs: []*net.IPNet{nodes["b"].Subnet},
  335. hostnames: []string{"b"},
  336. privateIPs: []net.IP{nodes["b"].InternalIP.IP},
  337. wireGuardIP: w2,
  338. },
  339. {
  340. allowedIPs: []*net.IPNet{nodes["c"].Subnet, nodes["c"].InternalIP, {IP: w3, Mask: net.CIDRMask(32, 32)}},
  341. endpoint: nodes["c"].Endpoint,
  342. key: nodes["c"].Key,
  343. location: nodes["c"].Name,
  344. cidrs: []*net.IPNet{nodes["c"].Subnet},
  345. hostnames: []string{"c"},
  346. privateIPs: []net.IP{nodes["c"].InternalIP.IP},
  347. wireGuardIP: w3,
  348. },
  349. },
  350. peers: []*Peer{peers["a"], peers["b"]},
  351. },
  352. },
  353. } {
  354. tc.result.key = key
  355. tc.result.port = port
  356. topo, err := NewTopology(nodes, peers, tc.granularity, tc.hostname, port, key, DefaultKiloSubnet)
  357. if err != nil {
  358. t.Errorf("test case %q: failed to generate Topology: %v", tc.name, err)
  359. }
  360. if diff := pretty.Compare(topo, tc.result); diff != "" {
  361. t.Errorf("test case %q: got diff: %v", tc.name, diff)
  362. }
  363. }
  364. }
  365. func mustTopo(t *testing.T, nodes map[string]*Node, peers map[string]*Peer, granularity Granularity, hostname string, port uint32, key []byte, subnet *net.IPNet) *Topology {
  366. topo, err := NewTopology(nodes, peers, granularity, hostname, port, key, subnet)
  367. if err != nil {
  368. t.Errorf("failed to generate Topology: %v", err)
  369. }
  370. return topo
  371. }
  372. func TestRoutes(t *testing.T) {
  373. nodes, peers, key, port := setup(t)
  374. kiloIface := 0
  375. privIface := 1
  376. tunlIface := 2
  377. mustTopoForGranularityAndHost := func(granularity Granularity, hostname string) *Topology {
  378. return mustTopo(t, nodes, peers, granularity, hostname, port, key, DefaultKiloSubnet)
  379. }
  380. for _, tc := range []struct {
  381. name string
  382. local bool
  383. topology *Topology
  384. strategy encapsulation.Strategy
  385. routes []*netlink.Route
  386. rules []*netlink.Rule
  387. }{
  388. {
  389. name: "logical from a",
  390. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name),
  391. strategy: encapsulation.Never,
  392. routes: []*netlink.Route{
  393. {
  394. Dst: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].cidrs[0],
  395. Flags: int(netlink.FLAG_ONLINK),
  396. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  397. LinkIndex: kiloIface,
  398. Protocol: unix.RTPROT_STATIC,
  399. },
  400. {
  401. Dst: oneAddressCIDR(nodes["b"].InternalIP.IP),
  402. Flags: int(netlink.FLAG_ONLINK),
  403. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  404. LinkIndex: kiloIface,
  405. Protocol: unix.RTPROT_STATIC,
  406. },
  407. {
  408. Dst: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].cidrs[1],
  409. Flags: int(netlink.FLAG_ONLINK),
  410. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  411. LinkIndex: kiloIface,
  412. Protocol: unix.RTPROT_STATIC,
  413. },
  414. {
  415. Dst: oneAddressCIDR(nodes["c"].InternalIP.IP),
  416. Flags: int(netlink.FLAG_ONLINK),
  417. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  418. LinkIndex: kiloIface,
  419. Protocol: unix.RTPROT_STATIC,
  420. },
  421. {
  422. Dst: peers["a"].AllowedIPs[0],
  423. LinkIndex: kiloIface,
  424. Protocol: unix.RTPROT_STATIC,
  425. },
  426. {
  427. Dst: peers["a"].AllowedIPs[1],
  428. LinkIndex: kiloIface,
  429. Protocol: unix.RTPROT_STATIC,
  430. },
  431. {
  432. Dst: peers["b"].AllowedIPs[0],
  433. LinkIndex: kiloIface,
  434. Protocol: unix.RTPROT_STATIC,
  435. },
  436. },
  437. },
  438. {
  439. name: "logical from b",
  440. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name),
  441. strategy: encapsulation.Never,
  442. routes: []*netlink.Route{
  443. {
  444. Dst: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].cidrs[0],
  445. Flags: int(netlink.FLAG_ONLINK),
  446. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  447. LinkIndex: kiloIface,
  448. Protocol: unix.RTPROT_STATIC,
  449. },
  450. {
  451. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  452. Flags: int(netlink.FLAG_ONLINK),
  453. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  454. LinkIndex: kiloIface,
  455. Protocol: unix.RTPROT_STATIC,
  456. },
  457. {
  458. Dst: peers["a"].AllowedIPs[0],
  459. LinkIndex: kiloIface,
  460. Protocol: unix.RTPROT_STATIC,
  461. },
  462. {
  463. Dst: peers["a"].AllowedIPs[1],
  464. LinkIndex: kiloIface,
  465. Protocol: unix.RTPROT_STATIC,
  466. },
  467. {
  468. Dst: peers["b"].AllowedIPs[0],
  469. LinkIndex: kiloIface,
  470. Protocol: unix.RTPROT_STATIC,
  471. },
  472. },
  473. },
  474. {
  475. name: "logical from c",
  476. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name),
  477. strategy: encapsulation.Never,
  478. routes: []*netlink.Route{
  479. {
  480. Dst: oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[0].wireGuardIP),
  481. Flags: int(netlink.FLAG_ONLINK),
  482. Gw: nodes["b"].InternalIP.IP,
  483. LinkIndex: privIface,
  484. Protocol: unix.RTPROT_STATIC,
  485. },
  486. {
  487. Dst: mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[0].cidrs[0],
  488. Flags: int(netlink.FLAG_ONLINK),
  489. Gw: nodes["b"].InternalIP.IP,
  490. LinkIndex: privIface,
  491. Protocol: unix.RTPROT_STATIC,
  492. },
  493. {
  494. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  495. Flags: int(netlink.FLAG_ONLINK),
  496. Gw: nodes["b"].InternalIP.IP,
  497. LinkIndex: privIface,
  498. Protocol: unix.RTPROT_STATIC,
  499. },
  500. {
  501. Dst: oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[1].wireGuardIP),
  502. Flags: int(netlink.FLAG_ONLINK),
  503. Gw: nodes["b"].InternalIP.IP,
  504. LinkIndex: privIface,
  505. Protocol: unix.RTPROT_STATIC,
  506. },
  507. {
  508. Dst: peers["a"].AllowedIPs[0],
  509. Flags: int(netlink.FLAG_ONLINK),
  510. Gw: nodes["b"].InternalIP.IP,
  511. LinkIndex: privIface,
  512. Protocol: unix.RTPROT_STATIC,
  513. },
  514. {
  515. Dst: peers["a"].AllowedIPs[1],
  516. Flags: int(netlink.FLAG_ONLINK),
  517. Gw: nodes["b"].InternalIP.IP,
  518. LinkIndex: privIface,
  519. Protocol: unix.RTPROT_STATIC,
  520. },
  521. {
  522. Dst: peers["b"].AllowedIPs[0],
  523. Flags: int(netlink.FLAG_ONLINK),
  524. Gw: nodes["b"].InternalIP.IP,
  525. LinkIndex: privIface,
  526. Protocol: unix.RTPROT_STATIC,
  527. },
  528. },
  529. },
  530. {
  531. name: "full from a",
  532. topology: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name),
  533. strategy: encapsulation.Never,
  534. routes: []*netlink.Route{
  535. {
  536. Dst: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].cidrs[0],
  537. Flags: int(netlink.FLAG_ONLINK),
  538. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  539. LinkIndex: kiloIface,
  540. Protocol: unix.RTPROT_STATIC,
  541. },
  542. {
  543. Dst: oneAddressCIDR(nodes["b"].InternalIP.IP),
  544. Flags: int(netlink.FLAG_ONLINK),
  545. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  546. LinkIndex: kiloIface,
  547. Protocol: unix.RTPROT_STATIC,
  548. },
  549. {
  550. Dst: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].cidrs[0],
  551. Flags: int(netlink.FLAG_ONLINK),
  552. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP,
  553. LinkIndex: kiloIface,
  554. Protocol: unix.RTPROT_STATIC,
  555. },
  556. {
  557. Dst: oneAddressCIDR(nodes["c"].InternalIP.IP),
  558. Flags: int(netlink.FLAG_ONLINK),
  559. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP,
  560. LinkIndex: kiloIface,
  561. Protocol: unix.RTPROT_STATIC,
  562. },
  563. {
  564. Dst: peers["a"].AllowedIPs[0],
  565. LinkIndex: kiloIface,
  566. Protocol: unix.RTPROT_STATIC,
  567. },
  568. {
  569. Dst: peers["a"].AllowedIPs[1],
  570. LinkIndex: kiloIface,
  571. Protocol: unix.RTPROT_STATIC,
  572. },
  573. {
  574. Dst: peers["b"].AllowedIPs[0],
  575. LinkIndex: kiloIface,
  576. Protocol: unix.RTPROT_STATIC,
  577. },
  578. },
  579. },
  580. {
  581. name: "full from b",
  582. topology: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name),
  583. strategy: encapsulation.Never,
  584. routes: []*netlink.Route{
  585. {
  586. Dst: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].cidrs[0],
  587. Flags: int(netlink.FLAG_ONLINK),
  588. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  589. LinkIndex: kiloIface,
  590. Protocol: unix.RTPROT_STATIC,
  591. },
  592. {
  593. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  594. Flags: int(netlink.FLAG_ONLINK),
  595. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  596. LinkIndex: kiloIface,
  597. Protocol: unix.RTPROT_STATIC,
  598. },
  599. {
  600. Dst: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].cidrs[0],
  601. Flags: int(netlink.FLAG_ONLINK),
  602. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP,
  603. LinkIndex: kiloIface,
  604. Protocol: unix.RTPROT_STATIC,
  605. },
  606. {
  607. Dst: oneAddressCIDR(nodes["c"].InternalIP.IP),
  608. Flags: int(netlink.FLAG_ONLINK),
  609. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP,
  610. LinkIndex: kiloIface,
  611. Protocol: unix.RTPROT_STATIC,
  612. },
  613. {
  614. Dst: peers["a"].AllowedIPs[0],
  615. LinkIndex: kiloIface,
  616. Protocol: unix.RTPROT_STATIC,
  617. },
  618. {
  619. Dst: peers["a"].AllowedIPs[1],
  620. LinkIndex: kiloIface,
  621. Protocol: unix.RTPROT_STATIC,
  622. },
  623. {
  624. Dst: peers["b"].AllowedIPs[0],
  625. LinkIndex: kiloIface,
  626. Protocol: unix.RTPROT_STATIC,
  627. },
  628. },
  629. },
  630. {
  631. name: "full from c",
  632. topology: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name),
  633. strategy: encapsulation.Never,
  634. routes: []*netlink.Route{
  635. {
  636. Dst: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].cidrs[0],
  637. Flags: int(netlink.FLAG_ONLINK),
  638. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP,
  639. LinkIndex: kiloIface,
  640. Protocol: unix.RTPROT_STATIC,
  641. },
  642. {
  643. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  644. Flags: int(netlink.FLAG_ONLINK),
  645. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP,
  646. LinkIndex: kiloIface,
  647. Protocol: unix.RTPROT_STATIC,
  648. },
  649. {
  650. Dst: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].cidrs[0],
  651. Flags: int(netlink.FLAG_ONLINK),
  652. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
  653. LinkIndex: kiloIface,
  654. Protocol: unix.RTPROT_STATIC,
  655. },
  656. {
  657. Dst: oneAddressCIDR(nodes["b"].InternalIP.IP),
  658. Flags: int(netlink.FLAG_ONLINK),
  659. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
  660. LinkIndex: kiloIface,
  661. Protocol: unix.RTPROT_STATIC,
  662. },
  663. {
  664. Dst: peers["a"].AllowedIPs[0],
  665. LinkIndex: kiloIface,
  666. Protocol: unix.RTPROT_STATIC,
  667. },
  668. {
  669. Dst: peers["a"].AllowedIPs[1],
  670. LinkIndex: kiloIface,
  671. Protocol: unix.RTPROT_STATIC,
  672. },
  673. {
  674. Dst: peers["b"].AllowedIPs[0],
  675. LinkIndex: kiloIface,
  676. Protocol: unix.RTPROT_STATIC,
  677. },
  678. },
  679. },
  680. {
  681. name: "logical from a local",
  682. local: true,
  683. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name),
  684. strategy: encapsulation.Never,
  685. routes: []*netlink.Route{
  686. {
  687. Dst: nodes["b"].Subnet,
  688. Flags: int(netlink.FLAG_ONLINK),
  689. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  690. LinkIndex: kiloIface,
  691. Protocol: unix.RTPROT_STATIC,
  692. },
  693. {
  694. Dst: oneAddressCIDR(nodes["b"].InternalIP.IP),
  695. Flags: int(netlink.FLAG_ONLINK),
  696. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  697. LinkIndex: kiloIface,
  698. Protocol: unix.RTPROT_STATIC,
  699. },
  700. {
  701. Dst: nodes["c"].Subnet,
  702. Flags: int(netlink.FLAG_ONLINK),
  703. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  704. LinkIndex: kiloIface,
  705. Protocol: unix.RTPROT_STATIC,
  706. },
  707. {
  708. Dst: oneAddressCIDR(nodes["c"].InternalIP.IP),
  709. Flags: int(netlink.FLAG_ONLINK),
  710. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  711. LinkIndex: kiloIface,
  712. Protocol: unix.RTPROT_STATIC,
  713. },
  714. {
  715. Dst: peers["a"].AllowedIPs[0],
  716. LinkIndex: kiloIface,
  717. Protocol: unix.RTPROT_STATIC,
  718. },
  719. {
  720. Dst: peers["a"].AllowedIPs[1],
  721. LinkIndex: kiloIface,
  722. Protocol: unix.RTPROT_STATIC,
  723. },
  724. {
  725. Dst: peers["b"].AllowedIPs[0],
  726. LinkIndex: kiloIface,
  727. Protocol: unix.RTPROT_STATIC,
  728. },
  729. },
  730. },
  731. {
  732. name: "logical from a local always",
  733. local: true,
  734. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name),
  735. strategy: encapsulation.Always,
  736. routes: []*netlink.Route{
  737. {
  738. Dst: nodes["b"].Subnet,
  739. Flags: int(netlink.FLAG_ONLINK),
  740. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  741. LinkIndex: kiloIface,
  742. Protocol: unix.RTPROT_STATIC,
  743. },
  744. {
  745. Dst: oneAddressCIDR(nodes["b"].InternalIP.IP),
  746. Flags: int(netlink.FLAG_ONLINK),
  747. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  748. LinkIndex: kiloIface,
  749. Protocol: unix.RTPROT_STATIC,
  750. },
  751. {
  752. Dst: nodes["c"].Subnet,
  753. Flags: int(netlink.FLAG_ONLINK),
  754. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  755. LinkIndex: kiloIface,
  756. Protocol: unix.RTPROT_STATIC,
  757. },
  758. {
  759. Dst: oneAddressCIDR(nodes["c"].InternalIP.IP),
  760. Flags: int(netlink.FLAG_ONLINK),
  761. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  762. LinkIndex: kiloIface,
  763. Protocol: unix.RTPROT_STATIC,
  764. },
  765. {
  766. Dst: peers["a"].AllowedIPs[0],
  767. LinkIndex: kiloIface,
  768. Protocol: unix.RTPROT_STATIC,
  769. },
  770. {
  771. Dst: peers["a"].AllowedIPs[1],
  772. LinkIndex: kiloIface,
  773. Protocol: unix.RTPROT_STATIC,
  774. },
  775. {
  776. Dst: peers["b"].AllowedIPs[0],
  777. LinkIndex: kiloIface,
  778. Protocol: unix.RTPROT_STATIC,
  779. },
  780. },
  781. },
  782. {
  783. name: "logical from b local",
  784. local: true,
  785. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name),
  786. strategy: encapsulation.Never,
  787. routes: []*netlink.Route{
  788. {
  789. Dst: nodes["a"].Subnet,
  790. Flags: int(netlink.FLAG_ONLINK),
  791. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  792. LinkIndex: kiloIface,
  793. Protocol: unix.RTPROT_STATIC,
  794. },
  795. {
  796. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  797. Flags: int(netlink.FLAG_ONLINK),
  798. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  799. LinkIndex: kiloIface,
  800. Protocol: unix.RTPROT_STATIC,
  801. },
  802. {
  803. Dst: nodes["c"].Subnet,
  804. Flags: int(netlink.FLAG_ONLINK),
  805. Gw: nodes["c"].InternalIP.IP,
  806. LinkIndex: privIface,
  807. Protocol: unix.RTPROT_STATIC,
  808. },
  809. {
  810. Dst: peers["a"].AllowedIPs[0],
  811. LinkIndex: kiloIface,
  812. Protocol: unix.RTPROT_STATIC,
  813. },
  814. {
  815. Dst: peers["a"].AllowedIPs[1],
  816. LinkIndex: kiloIface,
  817. Protocol: unix.RTPROT_STATIC,
  818. },
  819. {
  820. Dst: peers["b"].AllowedIPs[0],
  821. LinkIndex: kiloIface,
  822. Protocol: unix.RTPROT_STATIC,
  823. },
  824. },
  825. },
  826. {
  827. name: "logical from b local always",
  828. local: true,
  829. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name),
  830. strategy: encapsulation.Always,
  831. routes: []*netlink.Route{
  832. {
  833. Dst: nodes["a"].Subnet,
  834. Flags: int(netlink.FLAG_ONLINK),
  835. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  836. LinkIndex: kiloIface,
  837. Protocol: unix.RTPROT_STATIC,
  838. },
  839. {
  840. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  841. Flags: int(netlink.FLAG_ONLINK),
  842. Gw: mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  843. LinkIndex: kiloIface,
  844. Protocol: unix.RTPROT_STATIC,
  845. },
  846. {
  847. Dst: nodes["c"].Subnet,
  848. Flags: int(netlink.FLAG_ONLINK),
  849. Gw: nodes["c"].InternalIP.IP,
  850. LinkIndex: tunlIface,
  851. Protocol: unix.RTPROT_STATIC,
  852. },
  853. {
  854. Dst: oneAddressCIDR(nodes["c"].InternalIP.IP),
  855. Flags: int(netlink.FLAG_ONLINK),
  856. Gw: nodes["c"].InternalIP.IP,
  857. LinkIndex: tunlIface,
  858. Protocol: unix.RTPROT_STATIC,
  859. Table: kiloTableIndex,
  860. },
  861. {
  862. Dst: peers["a"].AllowedIPs[0],
  863. LinkIndex: kiloIface,
  864. Protocol: unix.RTPROT_STATIC,
  865. },
  866. {
  867. Dst: peers["a"].AllowedIPs[1],
  868. LinkIndex: kiloIface,
  869. Protocol: unix.RTPROT_STATIC,
  870. },
  871. {
  872. Dst: peers["b"].AllowedIPs[0],
  873. LinkIndex: kiloIface,
  874. Protocol: unix.RTPROT_STATIC,
  875. },
  876. },
  877. rules: []*netlink.Rule{
  878. defaultRule(&netlink.Rule{
  879. Src: nodes["b"].Subnet,
  880. Dst: nodes["c"].InternalIP,
  881. Table: kiloTableIndex,
  882. }),
  883. defaultRule(&netlink.Rule{
  884. Dst: nodes["c"].InternalIP,
  885. IifName: DefaultKiloInterface,
  886. Table: kiloTableIndex,
  887. }),
  888. },
  889. },
  890. {
  891. name: "logical from c local",
  892. local: true,
  893. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name),
  894. strategy: encapsulation.Never,
  895. routes: []*netlink.Route{
  896. {
  897. Dst: oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[0].wireGuardIP),
  898. Flags: int(netlink.FLAG_ONLINK),
  899. Gw: nodes["b"].InternalIP.IP,
  900. LinkIndex: privIface,
  901. Protocol: unix.RTPROT_STATIC,
  902. },
  903. {
  904. Dst: nodes["a"].Subnet,
  905. Flags: int(netlink.FLAG_ONLINK),
  906. Gw: nodes["b"].InternalIP.IP,
  907. LinkIndex: privIface,
  908. Protocol: unix.RTPROT_STATIC,
  909. },
  910. {
  911. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  912. Flags: int(netlink.FLAG_ONLINK),
  913. Gw: nodes["b"].InternalIP.IP,
  914. LinkIndex: privIface,
  915. Protocol: unix.RTPROT_STATIC,
  916. },
  917. {
  918. Dst: oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[1].wireGuardIP),
  919. Flags: int(netlink.FLAG_ONLINK),
  920. Gw: nodes["b"].InternalIP.IP,
  921. LinkIndex: privIface,
  922. Protocol: unix.RTPROT_STATIC,
  923. },
  924. {
  925. Dst: nodes["b"].Subnet,
  926. Flags: int(netlink.FLAG_ONLINK),
  927. Gw: nodes["b"].InternalIP.IP,
  928. LinkIndex: privIface,
  929. Protocol: unix.RTPROT_STATIC,
  930. },
  931. {
  932. Dst: peers["a"].AllowedIPs[0],
  933. Flags: int(netlink.FLAG_ONLINK),
  934. Gw: nodes["b"].InternalIP.IP,
  935. LinkIndex: privIface,
  936. Protocol: unix.RTPROT_STATIC,
  937. },
  938. {
  939. Dst: peers["a"].AllowedIPs[1],
  940. Flags: int(netlink.FLAG_ONLINK),
  941. Gw: nodes["b"].InternalIP.IP,
  942. LinkIndex: privIface,
  943. Protocol: unix.RTPROT_STATIC,
  944. },
  945. {
  946. Dst: peers["b"].AllowedIPs[0],
  947. Flags: int(netlink.FLAG_ONLINK),
  948. Gw: nodes["b"].InternalIP.IP,
  949. LinkIndex: privIface,
  950. Protocol: unix.RTPROT_STATIC,
  951. },
  952. },
  953. },
  954. {
  955. name: "logical from c local always",
  956. local: true,
  957. topology: mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name),
  958. strategy: encapsulation.Always,
  959. routes: []*netlink.Route{
  960. {
  961. Dst: oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[0].wireGuardIP),
  962. Flags: int(netlink.FLAG_ONLINK),
  963. Gw: nodes["b"].InternalIP.IP,
  964. LinkIndex: tunlIface,
  965. Protocol: unix.RTPROT_STATIC,
  966. },
  967. {
  968. Dst: nodes["a"].Subnet,
  969. Flags: int(netlink.FLAG_ONLINK),
  970. Gw: nodes["b"].InternalIP.IP,
  971. LinkIndex: tunlIface,
  972. Protocol: unix.RTPROT_STATIC,
  973. },
  974. {
  975. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  976. Flags: int(netlink.FLAG_ONLINK),
  977. Gw: nodes["b"].InternalIP.IP,
  978. LinkIndex: tunlIface,
  979. Protocol: unix.RTPROT_STATIC,
  980. },
  981. {
  982. Dst: oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[1].wireGuardIP),
  983. Flags: int(netlink.FLAG_ONLINK),
  984. Gw: nodes["b"].InternalIP.IP,
  985. LinkIndex: tunlIface,
  986. Protocol: unix.RTPROT_STATIC,
  987. },
  988. {
  989. Dst: nodes["b"].Subnet,
  990. Flags: int(netlink.FLAG_ONLINK),
  991. Gw: nodes["b"].InternalIP.IP,
  992. LinkIndex: tunlIface,
  993. Protocol: unix.RTPROT_STATIC,
  994. },
  995. {
  996. Dst: nodes["b"].InternalIP,
  997. Flags: int(netlink.FLAG_ONLINK),
  998. Gw: nodes["b"].InternalIP.IP,
  999. LinkIndex: tunlIface,
  1000. Protocol: unix.RTPROT_STATIC,
  1001. Table: kiloTableIndex,
  1002. },
  1003. {
  1004. Dst: peers["a"].AllowedIPs[0],
  1005. Flags: int(netlink.FLAG_ONLINK),
  1006. Gw: nodes["b"].InternalIP.IP,
  1007. LinkIndex: tunlIface,
  1008. Protocol: unix.RTPROT_STATIC,
  1009. },
  1010. {
  1011. Dst: peers["a"].AllowedIPs[1],
  1012. Flags: int(netlink.FLAG_ONLINK),
  1013. Gw: nodes["b"].InternalIP.IP,
  1014. LinkIndex: tunlIface,
  1015. Protocol: unix.RTPROT_STATIC,
  1016. },
  1017. {
  1018. Dst: peers["b"].AllowedIPs[0],
  1019. Flags: int(netlink.FLAG_ONLINK),
  1020. Gw: nodes["b"].InternalIP.IP,
  1021. LinkIndex: tunlIface,
  1022. Protocol: unix.RTPROT_STATIC,
  1023. },
  1024. },
  1025. rules: []*netlink.Rule{
  1026. defaultRule(&netlink.Rule{
  1027. Src: nodes["c"].Subnet,
  1028. Dst: nodes["b"].InternalIP,
  1029. Table: kiloTableIndex,
  1030. }),
  1031. },
  1032. },
  1033. {
  1034. name: "full from a local",
  1035. local: true,
  1036. topology: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name),
  1037. strategy: encapsulation.Never,
  1038. routes: []*netlink.Route{
  1039. {
  1040. Dst: nodes["b"].Subnet,
  1041. Flags: int(netlink.FLAG_ONLINK),
  1042. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  1043. LinkIndex: kiloIface,
  1044. Protocol: unix.RTPROT_STATIC,
  1045. },
  1046. {
  1047. Dst: oneAddressCIDR(nodes["b"].InternalIP.IP),
  1048. Flags: int(netlink.FLAG_ONLINK),
  1049. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
  1050. LinkIndex: kiloIface,
  1051. Protocol: unix.RTPROT_STATIC,
  1052. },
  1053. {
  1054. Dst: nodes["c"].Subnet,
  1055. Flags: int(netlink.FLAG_ONLINK),
  1056. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP,
  1057. LinkIndex: kiloIface,
  1058. Protocol: unix.RTPROT_STATIC,
  1059. },
  1060. {
  1061. Dst: oneAddressCIDR(nodes["c"].InternalIP.IP),
  1062. Flags: int(netlink.FLAG_ONLINK),
  1063. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP,
  1064. LinkIndex: kiloIface,
  1065. Protocol: unix.RTPROT_STATIC,
  1066. },
  1067. {
  1068. Dst: peers["a"].AllowedIPs[0],
  1069. LinkIndex: kiloIface,
  1070. Protocol: unix.RTPROT_STATIC,
  1071. },
  1072. {
  1073. Dst: peers["a"].AllowedIPs[1],
  1074. LinkIndex: kiloIface,
  1075. Protocol: unix.RTPROT_STATIC,
  1076. },
  1077. {
  1078. Dst: peers["b"].AllowedIPs[0],
  1079. LinkIndex: kiloIface,
  1080. Protocol: unix.RTPROT_STATIC,
  1081. },
  1082. },
  1083. },
  1084. {
  1085. name: "full from b local",
  1086. local: true,
  1087. topology: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name),
  1088. strategy: encapsulation.Never,
  1089. routes: []*netlink.Route{
  1090. {
  1091. Dst: nodes["a"].Subnet,
  1092. Flags: int(netlink.FLAG_ONLINK),
  1093. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  1094. LinkIndex: kiloIface,
  1095. Protocol: unix.RTPROT_STATIC,
  1096. },
  1097. {
  1098. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  1099. Flags: int(netlink.FLAG_ONLINK),
  1100. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP,
  1101. LinkIndex: kiloIface,
  1102. Protocol: unix.RTPROT_STATIC,
  1103. },
  1104. {
  1105. Dst: nodes["c"].Subnet,
  1106. Flags: int(netlink.FLAG_ONLINK),
  1107. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP,
  1108. LinkIndex: kiloIface,
  1109. Protocol: unix.RTPROT_STATIC,
  1110. },
  1111. {
  1112. Dst: oneAddressCIDR(nodes["c"].InternalIP.IP),
  1113. Flags: int(netlink.FLAG_ONLINK),
  1114. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP,
  1115. LinkIndex: kiloIface,
  1116. Protocol: unix.RTPROT_STATIC,
  1117. },
  1118. {
  1119. Dst: peers["a"].AllowedIPs[0],
  1120. LinkIndex: kiloIface,
  1121. Protocol: unix.RTPROT_STATIC,
  1122. },
  1123. {
  1124. Dst: peers["a"].AllowedIPs[1],
  1125. LinkIndex: kiloIface,
  1126. Protocol: unix.RTPROT_STATIC,
  1127. },
  1128. {
  1129. Dst: peers["b"].AllowedIPs[0],
  1130. LinkIndex: kiloIface,
  1131. Protocol: unix.RTPROT_STATIC,
  1132. },
  1133. },
  1134. },
  1135. {
  1136. name: "full from c local",
  1137. local: true,
  1138. topology: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name),
  1139. strategy: encapsulation.Never,
  1140. routes: []*netlink.Route{
  1141. {
  1142. Dst: nodes["a"].Subnet,
  1143. Flags: int(netlink.FLAG_ONLINK),
  1144. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP,
  1145. LinkIndex: kiloIface,
  1146. Protocol: unix.RTPROT_STATIC,
  1147. },
  1148. {
  1149. Dst: oneAddressCIDR(nodes["a"].InternalIP.IP),
  1150. Flags: int(netlink.FLAG_ONLINK),
  1151. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP,
  1152. LinkIndex: kiloIface,
  1153. Protocol: unix.RTPROT_STATIC,
  1154. },
  1155. {
  1156. Dst: nodes["b"].Subnet,
  1157. Flags: int(netlink.FLAG_ONLINK),
  1158. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
  1159. LinkIndex: kiloIface,
  1160. Protocol: unix.RTPROT_STATIC,
  1161. },
  1162. {
  1163. Dst: oneAddressCIDR(nodes["b"].InternalIP.IP),
  1164. Flags: int(netlink.FLAG_ONLINK),
  1165. Gw: mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
  1166. LinkIndex: kiloIface,
  1167. Protocol: unix.RTPROT_STATIC,
  1168. },
  1169. {
  1170. Dst: peers["a"].AllowedIPs[0],
  1171. LinkIndex: kiloIface,
  1172. Protocol: unix.RTPROT_STATIC,
  1173. },
  1174. {
  1175. Dst: peers["a"].AllowedIPs[1],
  1176. LinkIndex: kiloIface,
  1177. Protocol: unix.RTPROT_STATIC,
  1178. },
  1179. {
  1180. Dst: peers["b"].AllowedIPs[0],
  1181. LinkIndex: kiloIface,
  1182. Protocol: unix.RTPROT_STATIC,
  1183. },
  1184. },
  1185. },
  1186. } {
  1187. routes, rules := tc.topology.Routes(DefaultKiloInterface, kiloIface, privIface, tunlIface, tc.local, encapsulation.NewIPIP(tc.strategy))
  1188. if diff := pretty.Compare(routes, tc.routes); diff != "" {
  1189. t.Errorf("test case %q: got diff: %v", tc.name, diff)
  1190. }
  1191. if diff := pretty.Compare(rules, tc.rules); diff != "" {
  1192. t.Errorf("test case %q: got diff: %v", tc.name, diff)
  1193. }
  1194. }
  1195. }
  1196. func TestConf(t *testing.T) {
  1197. nodes, peers, key, port := setup(t)
  1198. for _, tc := range []struct {
  1199. name string
  1200. topology *Topology
  1201. result string
  1202. }{
  1203. {
  1204. name: "logical from a",
  1205. topology: mustTopo(t, nodes, peers, LogicalGranularity, nodes["a"].Name, port, key, DefaultKiloSubnet),
  1206. result: `[Interface]
  1207. PrivateKey = private
  1208. ListenPort = 51820
  1209. [Peer]
  1210. PublicKey = key2
  1211. Endpoint = 10.1.0.2:51820
  1212. AllowedIPs = 10.2.2.0/24, 192.168.0.1/32, 10.2.3.0/24, 192.168.0.2/32, 10.4.0.2/32
  1213. [Peer]
  1214. PublicKey = key4
  1215. PersistentKeepalive = 0
  1216. AllowedIPs = 10.5.0.1/24, 10.5.0.2/24
  1217. [Peer]
  1218. PublicKey = key5
  1219. Endpoint = 192.168.0.1:51820
  1220. PersistentKeepalive = 0
  1221. AllowedIPs = 10.5.0.3/24
  1222. `,
  1223. },
  1224. {
  1225. name: "logical from b",
  1226. topology: mustTopo(t, nodes, peers, LogicalGranularity, nodes["b"].Name, port, key, DefaultKiloSubnet),
  1227. result: `[Interface]
  1228. PrivateKey = private
  1229. ListenPort = 51820
  1230. [Peer]
  1231. PublicKey = key1
  1232. Endpoint = 10.1.0.1:51820
  1233. PersistentKeepalive = 25
  1234. AllowedIPs = 10.2.1.0/24, 192.168.0.1/32, 10.4.0.1/32
  1235. [Peer]
  1236. PublicKey = key4
  1237. PersistentKeepalive = 0
  1238. AllowedIPs = 10.5.0.1/24, 10.5.0.2/24
  1239. [Peer]
  1240. PublicKey = key5
  1241. Endpoint = 192.168.0.1:51820
  1242. PersistentKeepalive = 0
  1243. AllowedIPs = 10.5.0.3/24
  1244. `,
  1245. },
  1246. {
  1247. name: "logical from c",
  1248. topology: mustTopo(t, nodes, peers, LogicalGranularity, nodes["c"].Name, port, key, DefaultKiloSubnet),
  1249. result: `[Interface]
  1250. PrivateKey = private
  1251. ListenPort = 51820
  1252. [Peer]
  1253. PublicKey = key1
  1254. Endpoint = 10.1.0.1:51820
  1255. PersistentKeepalive = 25
  1256. AllowedIPs = 10.2.1.0/24, 192.168.0.1/32, 10.4.0.1/32
  1257. [Peer]
  1258. PublicKey = key4
  1259. PersistentKeepalive = 0
  1260. AllowedIPs = 10.5.0.1/24, 10.5.0.2/24
  1261. [Peer]
  1262. PublicKey = key5
  1263. Endpoint = 192.168.0.1:51820
  1264. PersistentKeepalive = 0
  1265. AllowedIPs = 10.5.0.3/24
  1266. `,
  1267. },
  1268. {
  1269. name: "full from a",
  1270. topology: mustTopo(t, nodes, peers, FullGranularity, nodes["a"].Name, port, key, DefaultKiloSubnet),
  1271. result: `[Interface]
  1272. PrivateKey = private
  1273. ListenPort = 51820
  1274. [Peer]
  1275. PublicKey = key2
  1276. Endpoint = 10.1.0.2:51820
  1277. AllowedIPs = 10.2.2.0/24, 192.168.0.1/32, 10.4.0.2/32
  1278. [Peer]
  1279. PublicKey = key3
  1280. Endpoint = 10.1.0.3:51820
  1281. AllowedIPs = 10.2.3.0/24, 192.168.0.2/32, 10.4.0.3/32
  1282. [Peer]
  1283. PublicKey = key4
  1284. PersistentKeepalive = 0
  1285. AllowedIPs = 10.5.0.1/24, 10.5.0.2/24
  1286. [Peer]
  1287. PublicKey = key5
  1288. Endpoint = 192.168.0.1:51820
  1289. PersistentKeepalive = 0
  1290. AllowedIPs = 10.5.0.3/24
  1291. `,
  1292. },
  1293. {
  1294. name: "full from b",
  1295. topology: mustTopo(t, nodes, peers, FullGranularity, nodes["b"].Name, port, key, DefaultKiloSubnet),
  1296. result: `[Interface]
  1297. PrivateKey = private
  1298. ListenPort = 51820
  1299. [Peer]
  1300. PublicKey = key1
  1301. Endpoint = 10.1.0.1:51820
  1302. PersistentKeepalive = 25
  1303. AllowedIPs = 10.2.1.0/24, 192.168.0.1/32, 10.4.0.1/32
  1304. [Peer]
  1305. PublicKey = key3
  1306. Endpoint = 10.1.0.3:51820
  1307. AllowedIPs = 10.2.3.0/24, 192.168.0.2/32, 10.4.0.3/32
  1308. [Peer]
  1309. PublicKey = key4
  1310. PersistentKeepalive = 0
  1311. AllowedIPs = 10.5.0.1/24, 10.5.0.2/24
  1312. [Peer]
  1313. PublicKey = key5
  1314. Endpoint = 192.168.0.1:51820
  1315. PersistentKeepalive = 0
  1316. AllowedIPs = 10.5.0.3/24
  1317. `,
  1318. },
  1319. {
  1320. name: "full from c",
  1321. topology: mustTopo(t, nodes, peers, FullGranularity, nodes["c"].Name, port, key, DefaultKiloSubnet),
  1322. result: `[Interface]
  1323. PrivateKey = private
  1324. ListenPort = 51820
  1325. [Peer]
  1326. PublicKey = key1
  1327. Endpoint = 10.1.0.1:51820
  1328. PersistentKeepalive = 25
  1329. AllowedIPs = 10.2.1.0/24, 192.168.0.1/32, 10.4.0.1/32
  1330. [Peer]
  1331. PublicKey = key2
  1332. Endpoint = 10.1.0.2:51820
  1333. AllowedIPs = 10.2.2.0/24, 192.168.0.1/32, 10.4.0.2/32
  1334. [Peer]
  1335. PublicKey = key4
  1336. PersistentKeepalive = 0
  1337. AllowedIPs = 10.5.0.1/24, 10.5.0.2/24
  1338. [Peer]
  1339. PublicKey = key5
  1340. Endpoint = 192.168.0.1:51820
  1341. PersistentKeepalive = 0
  1342. AllowedIPs = 10.5.0.3/24
  1343. `,
  1344. },
  1345. } {
  1346. conf := tc.topology.Conf()
  1347. if !conf.Equal(wireguard.Parse([]byte(tc.result))) {
  1348. buf, err := conf.Bytes()
  1349. if err != nil {
  1350. t.Errorf("test case %q: failed to render conf: %v", tc.name, err)
  1351. }
  1352. t.Errorf("test case %q: expected %s got %s", tc.name, tc.result, string(buf))
  1353. }
  1354. }
  1355. }
  1356. func TestFindLeader(t *testing.T) {
  1357. ip, e1, err := net.ParseCIDR("10.0.0.1/32")
  1358. if err != nil {
  1359. t.Fatalf("failed to parse external IP CIDR: %v", err)
  1360. }
  1361. e1.IP = ip
  1362. ip, e2, err := net.ParseCIDR("8.8.8.8/32")
  1363. if err != nil {
  1364. t.Fatalf("failed to parse external IP CIDR: %v", err)
  1365. }
  1366. e2.IP = ip
  1367. nodes := []*Node{
  1368. {
  1369. Name: "a",
  1370. Endpoint: &wireguard.Endpoint{DNSOrIP: wireguard.DNSOrIP{IP: e1.IP}, Port: DefaultKiloPort},
  1371. },
  1372. {
  1373. Name: "b",
  1374. Endpoint: &wireguard.Endpoint{DNSOrIP: wireguard.DNSOrIP{IP: e2.IP}, Port: DefaultKiloPort},
  1375. },
  1376. {
  1377. Name: "c",
  1378. Endpoint: &wireguard.Endpoint{DNSOrIP: wireguard.DNSOrIP{IP: e2.IP}, Port: DefaultKiloPort},
  1379. },
  1380. {
  1381. Name: "d",
  1382. Endpoint: &wireguard.Endpoint{DNSOrIP: wireguard.DNSOrIP{IP: e1.IP}, Port: DefaultKiloPort},
  1383. Leader: true,
  1384. },
  1385. {
  1386. Name: "2",
  1387. Endpoint: &wireguard.Endpoint{DNSOrIP: wireguard.DNSOrIP{IP: e2.IP}, Port: DefaultKiloPort},
  1388. Leader: true,
  1389. },
  1390. }
  1391. for _, tc := range []struct {
  1392. name string
  1393. nodes []*Node
  1394. out int
  1395. }{
  1396. {
  1397. name: "nil",
  1398. nodes: nil,
  1399. out: 0,
  1400. },
  1401. {
  1402. name: "one",
  1403. nodes: []*Node{nodes[0]},
  1404. out: 0,
  1405. },
  1406. {
  1407. name: "non-leaders",
  1408. nodes: []*Node{nodes[0], nodes[1], nodes[2]},
  1409. out: 1,
  1410. },
  1411. {
  1412. name: "leaders",
  1413. nodes: []*Node{nodes[3], nodes[4]},
  1414. out: 1,
  1415. },
  1416. {
  1417. name: "public",
  1418. nodes: []*Node{nodes[1], nodes[2], nodes[4]},
  1419. out: 2,
  1420. },
  1421. {
  1422. name: "private",
  1423. nodes: []*Node{nodes[0], nodes[3]},
  1424. out: 1,
  1425. },
  1426. {
  1427. name: "all",
  1428. nodes: nodes,
  1429. out: 4,
  1430. },
  1431. } {
  1432. l := findLeader(tc.nodes)
  1433. if l != tc.out {
  1434. t.Errorf("test case %q: expected %d got %d", tc.name, tc.out, l)
  1435. }
  1436. }
  1437. }
  1438. func TestDeduplicatePeerIPs(t *testing.T) {
  1439. p1 := &Peer{
  1440. Name: "1",
  1441. Peer: wireguard.Peer{
  1442. PublicKey: []byte("key1"),
  1443. AllowedIPs: []*net.IPNet{
  1444. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  1445. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(24, 32)},
  1446. },
  1447. },
  1448. }
  1449. p2 := &Peer{
  1450. Name: "2",
  1451. Peer: wireguard.Peer{
  1452. PublicKey: []byte("key2"),
  1453. AllowedIPs: []*net.IPNet{
  1454. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  1455. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  1456. },
  1457. },
  1458. }
  1459. p3 := &Peer{
  1460. Name: "3",
  1461. Peer: wireguard.Peer{
  1462. PublicKey: []byte("key3"),
  1463. AllowedIPs: []*net.IPNet{
  1464. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(24, 32)},
  1465. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  1466. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  1467. },
  1468. },
  1469. }
  1470. p4 := &Peer{
  1471. Name: "4",
  1472. Peer: wireguard.Peer{
  1473. PublicKey: []byte("key4"),
  1474. AllowedIPs: []*net.IPNet{
  1475. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  1476. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  1477. },
  1478. },
  1479. }
  1480. for _, tc := range []struct {
  1481. name string
  1482. peers []*Peer
  1483. out []*Peer
  1484. }{
  1485. {
  1486. name: "nil",
  1487. peers: nil,
  1488. out: nil,
  1489. },
  1490. {
  1491. name: "simple dupe",
  1492. peers: []*Peer{p1, p2},
  1493. out: []*Peer{
  1494. p1,
  1495. {
  1496. Name: "2",
  1497. Peer: wireguard.Peer{
  1498. PublicKey: []byte("key2"),
  1499. AllowedIPs: []*net.IPNet{
  1500. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  1501. },
  1502. },
  1503. },
  1504. },
  1505. },
  1506. {
  1507. name: "simple dupe reversed",
  1508. peers: []*Peer{p2, p1},
  1509. out: []*Peer{
  1510. p2,
  1511. {
  1512. Name: "1",
  1513. Peer: wireguard.Peer{
  1514. PublicKey: []byte("key1"),
  1515. AllowedIPs: []*net.IPNet{
  1516. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(24, 32)},
  1517. },
  1518. },
  1519. },
  1520. },
  1521. },
  1522. {
  1523. name: "one duplicates all",
  1524. peers: []*Peer{p3, p2, p1, p4},
  1525. out: []*Peer{
  1526. p3,
  1527. {
  1528. Name: "2",
  1529. Peer: wireguard.Peer{
  1530. PublicKey: []byte("key2"),
  1531. },
  1532. },
  1533. {
  1534. Name: "1",
  1535. Peer: wireguard.Peer{
  1536. PublicKey: []byte("key1"),
  1537. },
  1538. },
  1539. {
  1540. Name: "4",
  1541. Peer: wireguard.Peer{
  1542. PublicKey: []byte("key4"),
  1543. },
  1544. },
  1545. },
  1546. },
  1547. {
  1548. name: "one duplicates itself",
  1549. peers: []*Peer{p4, p1},
  1550. out: []*Peer{
  1551. {
  1552. Name: "4",
  1553. Peer: wireguard.Peer{
  1554. PublicKey: []byte("key4"),
  1555. AllowedIPs: []*net.IPNet{
  1556. {IP: net.ParseIP("10.0.0.3"), Mask: net.CIDRMask(24, 32)},
  1557. },
  1558. },
  1559. },
  1560. {
  1561. Name: "1",
  1562. Peer: wireguard.Peer{
  1563. PublicKey: []byte("key1"),
  1564. AllowedIPs: []*net.IPNet{
  1565. {IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(24, 32)},
  1566. {IP: net.ParseIP("10.0.0.2"), Mask: net.CIDRMask(24, 32)},
  1567. },
  1568. },
  1569. },
  1570. },
  1571. },
  1572. } {
  1573. out := deduplicatePeerIPs(tc.peers)
  1574. if diff := pretty.Compare(out, tc.out); diff != "" {
  1575. t.Errorf("test case %q: got diff: %v", tc.name, diff)
  1576. }
  1577. }
  1578. }