route_test.go 12 KB

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