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