route_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. package overlay
  2. import (
  3. "fmt"
  4. "net/netip"
  5. "testing"
  6. "github.com/slackhq/nebula/config"
  7. "github.com/slackhq/nebula/test"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func Test_parseRoutes(t *testing.T) {
  11. l := test.NewLogger()
  12. c := config.NewC(l)
  13. n, err := netip.ParsePrefix("10.0.0.0/24")
  14. assert.NoError(t, err)
  15. // test no routes config
  16. routes, err := parseRoutes(c, []netip.Prefix{n})
  17. assert.Nil(t, err)
  18. assert.Len(t, routes, 0)
  19. // not an array
  20. c.Settings["tun"] = map[interface{}]interface{}{"routes": "hi"}
  21. routes, err = parseRoutes(c, []netip.Prefix{n})
  22. assert.Nil(t, routes)
  23. assert.EqualError(t, err, "tun.routes is not an array")
  24. // no routes
  25. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{}}
  26. routes, err = parseRoutes(c, []netip.Prefix{n})
  27. assert.Nil(t, err)
  28. assert.Len(t, routes, 0)
  29. // weird route
  30. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{"asdf"}}
  31. routes, err = parseRoutes(c, []netip.Prefix{n})
  32. assert.Nil(t, routes)
  33. assert.EqualError(t, err, "entry 1 in tun.routes is invalid")
  34. // no mtu
  35. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{map[interface{}]interface{}{}}}
  36. routes, err = parseRoutes(c, []netip.Prefix{n})
  37. assert.Nil(t, routes)
  38. assert.EqualError(t, err, "entry 1.mtu in tun.routes is not present")
  39. // bad mtu
  40. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{map[interface{}]interface{}{"mtu": "nope"}}}
  41. routes, err = parseRoutes(c, []netip.Prefix{n})
  42. assert.Nil(t, routes)
  43. assert.EqualError(t, err, "entry 1.mtu in tun.routes is not an integer: strconv.Atoi: parsing \"nope\": invalid syntax")
  44. // low mtu
  45. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{map[interface{}]interface{}{"mtu": "499"}}}
  46. routes, err = parseRoutes(c, []netip.Prefix{n})
  47. assert.Nil(t, routes)
  48. assert.EqualError(t, err, "entry 1.mtu in tun.routes is below 500: 499")
  49. // missing route
  50. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{map[interface{}]interface{}{"mtu": "500"}}}
  51. routes, err = parseRoutes(c, []netip.Prefix{n})
  52. assert.Nil(t, routes)
  53. assert.EqualError(t, err, "entry 1.route in tun.routes is not present")
  54. // unparsable route
  55. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{map[interface{}]interface{}{"mtu": "500", "route": "nope"}}}
  56. routes, err = parseRoutes(c, []netip.Prefix{n})
  57. assert.Nil(t, routes)
  58. assert.EqualError(t, err, "entry 1.route in tun.routes failed to parse: netip.ParsePrefix(\"nope\"): no '/'")
  59. // below network range
  60. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{map[interface{}]interface{}{"mtu": "500", "route": "1.0.0.0/8"}}}
  61. routes, err = parseRoutes(c, []netip.Prefix{n})
  62. assert.Nil(t, routes)
  63. assert.EqualError(t, err, "entry 1.route in tun.routes is not contained within the configured vpn networks; route: 1.0.0.0/8, networks: [10.0.0.0/24]")
  64. // above network range
  65. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{map[interface{}]interface{}{"mtu": "500", "route": "10.0.1.0/24"}}}
  66. routes, err = parseRoutes(c, []netip.Prefix{n})
  67. assert.Nil(t, routes)
  68. assert.EqualError(t, err, "entry 1.route in tun.routes is not contained within the configured vpn networks; route: 10.0.1.0/24, networks: [10.0.0.0/24]")
  69. // Not in multiple ranges
  70. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{map[interface{}]interface{}{"mtu": "500", "route": "192.0.0.0/24"}}}
  71. routes, err = parseRoutes(c, []netip.Prefix{n, netip.MustParsePrefix("192.1.0.0/24")})
  72. assert.Nil(t, routes)
  73. assert.EqualError(t, err, "entry 1.route in tun.routes is not contained within the configured vpn networks; route: 192.0.0.0/24, networks: [10.0.0.0/24 192.1.0.0/24]")
  74. // happy case
  75. c.Settings["tun"] = map[interface{}]interface{}{"routes": []interface{}{
  76. map[interface{}]interface{}{"mtu": "9000", "route": "10.0.0.0/29"},
  77. map[interface{}]interface{}{"mtu": "8000", "route": "10.0.0.1/32"},
  78. }}
  79. routes, err = parseRoutes(c, []netip.Prefix{n})
  80. assert.Nil(t, err)
  81. assert.Len(t, routes, 2)
  82. tested := 0
  83. for _, r := range routes {
  84. assert.True(t, r.Install)
  85. if r.MTU == 8000 {
  86. assert.Equal(t, "10.0.0.1/32", r.Cidr.String())
  87. tested++
  88. } else {
  89. assert.Equal(t, 9000, r.MTU)
  90. assert.Equal(t, "10.0.0.0/29", r.Cidr.String())
  91. tested++
  92. }
  93. }
  94. if tested != 2 {
  95. t.Fatal("Did not see both routes")
  96. }
  97. }
  98. func Test_parseUnsafeRoutes(t *testing.T) {
  99. l := test.NewLogger()
  100. c := config.NewC(l)
  101. n, err := netip.ParsePrefix("10.0.0.0/24")
  102. assert.NoError(t, err)
  103. // test no routes config
  104. routes, err := parseUnsafeRoutes(c, []netip.Prefix{n})
  105. assert.Nil(t, err)
  106. assert.Len(t, routes, 0)
  107. // not an array
  108. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": "hi"}
  109. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  110. assert.Nil(t, routes)
  111. assert.EqualError(t, err, "tun.unsafe_routes is not an array")
  112. // no routes
  113. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{}}
  114. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  115. assert.Nil(t, err)
  116. assert.Len(t, routes, 0)
  117. // weird route
  118. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{"asdf"}}
  119. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  120. assert.Nil(t, routes)
  121. assert.EqualError(t, err, "entry 1 in tun.unsafe_routes is invalid")
  122. // no via
  123. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{}}}
  124. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  125. assert.Nil(t, routes)
  126. assert.EqualError(t, err, "entry 1.via in tun.unsafe_routes is not present")
  127. // invalid via
  128. for _, invalidValue := range []interface{}{
  129. 127, false, nil, 1.0, []string{"1", "2"},
  130. } {
  131. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": invalidValue}}}
  132. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  133. assert.Nil(t, routes)
  134. assert.EqualError(t, err, fmt.Sprintf("entry 1.via in tun.unsafe_routes is not a string: found %T", invalidValue))
  135. }
  136. // unparsable via
  137. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"mtu": "500", "via": "nope"}}}
  138. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  139. assert.Nil(t, routes)
  140. assert.EqualError(t, err, "entry 1.via in tun.unsafe_routes failed to parse address: ParseAddr(\"nope\"): unable to parse IP")
  141. // missing route
  142. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "500"}}}
  143. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  144. assert.Nil(t, routes)
  145. assert.EqualError(t, err, "entry 1.route in tun.unsafe_routes is not present")
  146. // unparsable route
  147. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "500", "route": "nope"}}}
  148. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  149. assert.Nil(t, routes)
  150. assert.EqualError(t, err, "entry 1.route in tun.unsafe_routes failed to parse: netip.ParsePrefix(\"nope\"): no '/'")
  151. // within network range
  152. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "route": "10.0.0.0/24"}}}
  153. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  154. assert.Nil(t, routes)
  155. assert.EqualError(t, err, "entry 1.route in tun.unsafe_routes is contained within the configured vpn networks; route: 10.0.0.0/24, network: 10.0.0.0/24")
  156. // below network range
  157. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "route": "1.0.0.0/8"}}}
  158. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  159. assert.Len(t, routes, 1)
  160. assert.Nil(t, err)
  161. // above network range
  162. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "route": "10.0.1.0/24"}}}
  163. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  164. assert.Len(t, routes, 1)
  165. assert.Nil(t, err)
  166. // no mtu
  167. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "route": "1.0.0.0/8"}}}
  168. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  169. assert.Len(t, routes, 1)
  170. assert.Equal(t, 0, routes[0].MTU)
  171. // bad mtu
  172. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "nope"}}}
  173. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  174. assert.Nil(t, routes)
  175. assert.EqualError(t, err, "entry 1.mtu in tun.unsafe_routes is not an integer: strconv.Atoi: parsing \"nope\": invalid syntax")
  176. // low mtu
  177. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "499"}}}
  178. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  179. assert.Nil(t, routes)
  180. assert.EqualError(t, err, "entry 1.mtu in tun.unsafe_routes is below 500: 499")
  181. // bad install
  182. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "9000", "route": "1.0.0.0/29", "install": "nope"}}}
  183. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  184. assert.Nil(t, routes)
  185. assert.EqualError(t, err, "entry 1.install in tun.unsafe_routes is not a boolean: strconv.ParseBool: parsing \"nope\": invalid syntax")
  186. // happy case
  187. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{
  188. map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "9000", "route": "1.0.0.0/29", "install": "t"},
  189. map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "8000", "route": "1.0.0.1/32", "install": 0},
  190. map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "1500", "metric": 1234, "route": "1.0.0.2/32", "install": 1},
  191. map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "1500", "metric": 1234, "route": "1.0.0.2/32"},
  192. }}
  193. routes, err = parseUnsafeRoutes(c, []netip.Prefix{n})
  194. assert.Nil(t, err)
  195. assert.Len(t, routes, 4)
  196. tested := 0
  197. for _, r := range routes {
  198. if r.MTU == 8000 {
  199. assert.Equal(t, "1.0.0.1/32", r.Cidr.String())
  200. assert.False(t, r.Install)
  201. tested++
  202. } else if r.MTU == 9000 {
  203. assert.Equal(t, 9000, r.MTU)
  204. assert.Equal(t, "1.0.0.0/29", r.Cidr.String())
  205. assert.True(t, r.Install)
  206. tested++
  207. } else {
  208. assert.Equal(t, 1500, r.MTU)
  209. assert.Equal(t, 1234, r.Metric)
  210. assert.Equal(t, "1.0.0.2/32", r.Cidr.String())
  211. assert.True(t, r.Install)
  212. tested++
  213. }
  214. }
  215. if tested != 4 {
  216. t.Fatal("Did not see all unsafe_routes")
  217. }
  218. }
  219. func Test_makeRouteTree(t *testing.T) {
  220. l := test.NewLogger()
  221. c := config.NewC(l)
  222. n, err := netip.ParsePrefix("10.0.0.0/24")
  223. assert.NoError(t, err)
  224. c.Settings["tun"] = map[interface{}]interface{}{"unsafe_routes": []interface{}{
  225. map[interface{}]interface{}{"via": "192.168.0.1", "route": "1.0.0.0/28"},
  226. map[interface{}]interface{}{"via": "192.168.0.2", "route": "1.0.0.1/32"},
  227. }}
  228. routes, err := parseUnsafeRoutes(c, []netip.Prefix{n})
  229. assert.NoError(t, err)
  230. assert.Len(t, routes, 2)
  231. routeTree, err := makeRouteTree(l, routes, true)
  232. assert.NoError(t, err)
  233. ip, err := netip.ParseAddr("1.0.0.2")
  234. assert.NoError(t, err)
  235. r, ok := routeTree.Lookup(ip)
  236. assert.True(t, ok)
  237. nip, err := netip.ParseAddr("192.168.0.1")
  238. assert.NoError(t, err)
  239. assert.Equal(t, nip, r)
  240. ip, err = netip.ParseAddr("1.0.0.1")
  241. assert.NoError(t, err)
  242. r, ok = routeTree.Lookup(ip)
  243. assert.True(t, ok)
  244. nip, err = netip.ParseAddr("192.168.0.2")
  245. assert.NoError(t, err)
  246. assert.Equal(t, nip, r)
  247. ip, err = netip.ParseAddr("1.1.0.1")
  248. assert.NoError(t, err)
  249. r, ok = routeTree.Lookup(ip)
  250. assert.False(t, ok)
  251. }