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

This commit is contained in:
Donatas Abraitis 2021-11-04 04:53:28 +02:00 committed by GitHub
parent bcabcfdaca
commit b358bbab80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 44 additions and 11 deletions

View File

@ -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 - 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 removal of root trust). Default is `false`. Note, this will not currently recognize if a remote has changed
certificates since the last handshake. (#370) 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 ### Changed
- Build against go 1.17. (#553) - Build against go 1.17. (#553)

View File

@ -165,10 +165,13 @@ tun:
# Unsafe routes allows you to route traffic over nebula to non-nebula nodes # 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 # 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 # 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: unsafe_routes:
#- route: 172.16.1.0/24 #- route: 172.16.1.0/24
# via: 192.168.100.99 # via: 192.168.100.99
# mtu: 1300 #mtu will default to tun mtu if this option is not sepcified # mtu: 1300
# metric: 100
# TODO # TODO

View File

@ -2,6 +2,7 @@ package nebula
import ( import (
"fmt" "fmt"
"math"
"net" "net"
"strconv" "strconv"
@ -11,9 +12,10 @@ import (
const DEFAULT_MTU = 1300 const DEFAULT_MTU = 1300
type route struct { type route struct {
mtu int mtu int
route *net.IPNet metric int
via *net.IP route *net.IPNet
via *net.IP
} }
func parseRoutes(c *config.C, network *net.IPNet) ([]route, error) { 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) 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"] rVia, ok := m["via"]
if !ok { if !ok {
return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes is not present", i+1) 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{ r := route{
via: &nVia, via: &nVia,
mtu: mtu, mtu: mtu,
metric: metric,
} }
_, r.route, err = net.ParseCIDR(fmt.Sprintf("%v", rRoute)) _, r.route, err = net.ParseCIDR(fmt.Sprintf("%v", rRoute))

View File

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

View File

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

View File

@ -92,7 +92,7 @@ func (c *Tun) Activate() error {
for _, r := range c.UnsafeRoutes { for _, r := range c.UnsafeRoutes {
err = exec.Command( 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() ).Run()
if err != nil { if err != nil {
return fmt.Errorf("failed to add the unsafe_route %s: %v", r.route.String(), err) return fmt.Errorf("failed to add the unsafe_route %s: %v", r.route.String(), err)