Kaynağa Gözat

mesh: set preferred source for WireGuard routes

Set Route.Src for routes installed via the kilo interface to the node private IP when available.

Without an explicit source, the kernel may pick the WireGuard overlay address (for example 100.66.0.x). In environments like Azure SDN this can break return traffic because the overlay address is not routable by the underlay.

Update route expectations in TestRoutes to assert Src across the affected logical and full topology cases.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Andrei Kvapil 3 ay önce
ebeveyn
işleme
0d246e5aa2
2 değiştirilmiş dosya ile 109 ekleme ve 0 silme
  1. 12 0
      pkg/mesh/routes.go
  2. 97 0
      pkg/mesh/routes_test.go

+ 12 - 0
pkg/mesh/routes.go

@@ -135,6 +135,14 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface
 		}
 		return routes, rules
 	}
+	// Compute the preferred source address for routes through the WireGuard interface.
+	// Without this, the kernel picks the WireGuard overlay IP (e.g. 100.66.0.x) as the
+	// source, which can cause issues in environments like Azure SDN where the overlay
+	// IP is unknown to the network fabric and reply packets cannot be routed back.
+	var src net.IP
+	if t.privateIP != nil {
+		src = t.privateIP.IP
+	}
 	for _, segment := range t.segments {
 		// Add routes for the current segment if local is true.
 		if segment.location == t.location {
@@ -190,6 +198,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface
 				Flags:     int(netlink.FLAG_ONLINK),
 				Gw:        segment.wireGuardIP,
 				LinkIndex: kiloIface,
+				Src:       src,
 				Protocol:  unix.RTPROT_STATIC,
 			})
 			// Don't add routes through Kilo if the private IP
@@ -207,6 +216,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface
 				Flags:     int(netlink.FLAG_ONLINK),
 				Gw:        segment.wireGuardIP,
 				LinkIndex: kiloIface,
+				Src:       src,
 				Protocol:  unix.RTPROT_STATIC,
 			})
 		}
@@ -218,6 +228,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface
 				Flags:     int(netlink.FLAG_ONLINK),
 				Gw:        segment.wireGuardIP,
 				LinkIndex: kiloIface,
+				Src:       src,
 				Protocol:  unix.RTPROT_STATIC,
 			})
 		}
@@ -228,6 +239,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface
 			routes = append(routes, &netlink.Route{
 				Dst:       &peer.AllowedIPs[i],
 				LinkIndex: kiloIface,
+				Src:       src,
 				Protocol:  unix.RTPROT_STATIC,
 			})
 		}

+ 97 - 0
pkg/mesh/routes_test.go

@@ -51,6 +51,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -58,6 +59,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -65,6 +67,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -72,6 +75,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -79,6 +83,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -86,21 +91,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -115,6 +124,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -122,6 +132,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -129,21 +140,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -299,6 +314,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -306,6 +322,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -313,6 +330,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -320,6 +338,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -327,6 +346,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -334,21 +354,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[3].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -363,6 +387,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -370,6 +395,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -377,6 +403,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -384,6 +411,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -391,21 +419,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[3].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -420,6 +452,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -427,6 +460,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -434,6 +468,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -441,6 +476,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -448,6 +484,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -455,21 +492,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[3].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -485,6 +526,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -492,6 +534,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -499,6 +542,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -506,6 +550,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -513,6 +558,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -520,21 +566,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -550,6 +600,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -557,6 +608,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -564,6 +616,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -571,6 +624,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -578,6 +632,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -585,21 +640,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -615,6 +674,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -622,6 +682,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -636,21 +697,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -666,6 +731,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -673,6 +739,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -695,21 +762,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -908,6 +979,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -915,6 +987,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -922,6 +995,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -929,6 +1003,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -936,6 +1011,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -943,21 +1019,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[3].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["a"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -973,6 +1053,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -980,6 +1061,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -987,6 +1069,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -994,6 +1077,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -1001,21 +1085,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[3].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["b"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},
@@ -1031,6 +1119,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -1038,6 +1127,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -1045,6 +1135,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -1052,6 +1143,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -1059,6 +1151,7 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
@@ -1066,21 +1159,25 @@ func TestRoutes(t *testing.T) {
 					Flags:     int(netlink.FLAG_ONLINK),
 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[3].wireGuardIP,
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["a"].AllowedIPs[1],
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 				{
 					Dst:       &peers["b"].AllowedIPs[0],
 					LinkIndex: kiloIface,
+					Src:       nodes["c"].InternalIP.IP,
 					Protocol:  unix.RTPROT_STATIC,
 				},
 			},