瀏覽代碼

Add an ability to specify metric for unsafe routes (#474)

Donatas Abraitis 3 年之前
父節點
當前提交
b358bbab80
共有 6 個文件被更改,包括 44 次插入11 次删除
  1. 4 1
      CHANGELOG.md
  2. 4 1
      examples/config.yml
  3. 25 5
      tun_common.go
  4. 1 0
      tun_linux.go
  5. 9 3
      tun_test.go
  6. 1 1
      tun_windows.go

+ 4 - 1
CHANGELOG.md

@@ -18,7 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - New config option `pki.disconnect_invalid` that will tear down tunnels when they become invalid (through expiry or
   removal of root trust). Default is `false`. Note, this will not currently recognize if a remote has changed
   certificates since the last handshake. (#370)
-  
+
+- New config option `unsafe_routes.<route>.metric` will set a metric for a specific unsafe route. It's useful if you have
+  more than one identical route and want to prefer one against the other.
+
 ### Changed
 
 - Build against go 1.17. (#553)

+ 4 - 1
examples/config.yml

@@ -165,10 +165,13 @@ tun:
   # Unsafe routes allows you to route traffic over nebula to non-nebula nodes
   # Unsafe routes should be avoided unless you have hosts/services that cannot run nebula
   # NOTE: The nebula certificate of the "via" node *MUST* have the "route" defined as a subnet in its certificate
+  # `mtu` will default to tun mtu if this option is not specified
+  # `metric` will default to 0 if this option is not specified
   unsafe_routes:
     #- route: 172.16.1.0/24
     #  via: 192.168.100.99
-    #  mtu: 1300 #mtu will default to tun mtu if this option is not sepcified
+    #  mtu: 1300
+    #  metric: 100
 
 
 # TODO

+ 25 - 5
tun_common.go

@@ -2,6 +2,7 @@ package nebula
 
 import (
 	"fmt"
+	"math"
 	"net"
 	"strconv"
 
@@ -11,9 +12,10 @@ import (
 const DEFAULT_MTU = 1300
 
 type route struct {
-	mtu   int
-	route *net.IPNet
-	via   *net.IP
+	mtu    int
+	metric int
+	route  *net.IPNet
+	via    *net.IP
 }
 
 func parseRoutes(c *config.C, network *net.IPNet) ([]route, error) {
@@ -127,6 +129,23 @@ func parseUnsafeRoutes(c *config.C, network *net.IPNet) ([]route, error) {
 			return nil, fmt.Errorf("entry %v.mtu in tun.unsafe_routes is below 500: %v", i+1, mtu)
 		}
 
+		rMetric, ok := m["metric"]
+		if !ok {
+			rMetric = 0
+		}
+
+		metric, ok := rMetric.(int)
+		if !ok {
+			_, err = strconv.ParseInt(rMetric.(string), 10, 32)
+			if err != nil {
+				return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not an integer: %v", i+1, err)
+			}
+		}
+
+		if metric < 0 || metric > math.MaxInt32 {
+			return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not in range (0-%d) : %v", i+1, math.MaxInt32, metric)
+		}
+
 		rVia, ok := m["via"]
 		if !ok {
 			return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes is not present", i+1)
@@ -148,8 +167,9 @@ func parseUnsafeRoutes(c *config.C, network *net.IPNet) ([]route, error) {
 		}
 
 		r := route{
-			via: &nVia,
-			mtu: mtu,
+			via:    &nVia,
+			mtu:    mtu,
+			metric: metric,
 		}
 
 		_, r.route, err = net.ParseCIDR(fmt.Sprintf("%v", rRoute))

+ 1 - 0
tun_linux.go

@@ -300,6 +300,7 @@ func (c Tun) Activate() error {
 			LinkIndex: link.Attrs().Index,
 			Dst:       r.route,
 			MTU:       r.mtu,
+			Priority:  r.metric,
 			AdvMSS:    c.advMSS(r),
 			Scope:     unix.RT_SCOPE_LINK,
 		}

+ 9 - 3
tun_test.go

@@ -208,24 +208,30 @@ func Test_parseUnsafeRoutes(t *testing.T) {
 	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"},
 		map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "8000", "route": "1.0.0.1/32"},
+		map[interface{}]interface{}{"via": "127.0.0.1", "mtu": "1500", "metric": 1234, "route": "1.0.0.2/32"},
 	}}
 	routes, err = parseUnsafeRoutes(c, n)
 	assert.Nil(t, err)
-	assert.Len(t, routes, 2)
+	assert.Len(t, routes, 3)
 
 	tested := 0
 	for _, r := range routes {
 		if r.mtu == 8000 {
 			assert.Equal(t, "1.0.0.1/32", r.route.String())
 			tested++
-		} else {
+		} else if r.mtu == 9000 {
 			assert.Equal(t, 9000, r.mtu)
 			assert.Equal(t, "1.0.0.0/29", r.route.String())
 			tested++
+		} else {
+			assert.Equal(t, 1500, r.mtu)
+			assert.Equal(t, 1234, r.metric)
+			assert.Equal(t, "1.0.0.2/32", r.route.String())
+			tested++
 		}
 	}
 
-	if tested != 2 {
+	if tested != 3 {
 		t.Fatal("Did not see both unsafe_routes")
 	}
 }

+ 1 - 1
tun_windows.go

@@ -92,7 +92,7 @@ func (c *Tun) Activate() error {
 
 	for _, r := range c.UnsafeRoutes {
 		err = exec.Command(
-			"C:\\Windows\\System32\\route.exe", "add", r.route.String(), r.via.String(), "IF", strconv.Itoa(iface.Index),
+			"C:\\Windows\\System32\\route.exe", "add", r.route.String(), r.via.String(), "IF", strconv.Itoa(iface.Index), "METRIC", strconv.Itoa(r.metric),
 		).Run()
 		if err != nil {
 			return fmt.Errorf("failed to add the unsafe_route %s: %v", r.route.String(), err)