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  }