Skip to content

Commit 603f3ad

Browse files
authored
Multi network integration tests (#2464)
1 parent 707438f commit 603f3ad

29 files changed

+2374
-1438
lines changed

.github/workflows/test-integration-policyv2.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ jobs:
7070
- TestAutoApprovedSubRoute2068
7171
- TestSubnetRouteACL
7272
- TestEnablingExitRoutes
73+
- TestSubnetRouterMultiNetwork
74+
- TestSubnetRouterMultiNetworkExitNode
7375
- TestHeadscale
74-
- TestCreateTailscale
7576
- TestTailscaleNodesJoiningHeadcale
7677
- TestSSHOneUserToAll
7778
- TestSSHMultipleUsersAllToAll

.github/workflows/test-integration.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ jobs:
7070
- TestAutoApprovedSubRoute2068
7171
- TestSubnetRouteACL
7272
- TestEnablingExitRoutes
73+
- TestSubnetRouterMultiNetwork
74+
- TestSubnetRouterMultiNetworkExitNode
7375
- TestHeadscale
74-
- TestCreateTailscale
7576
- TestTailscaleNodesJoiningHeadcale
7677
- TestSSHOneUserToAll
7778
- TestSSHMultipleUsersAllToAll

hscontrol/mapper/mapper_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,13 @@ func Test_fullMapResponse(t *testing.T) {
165165
),
166166
Addresses: []netip.Prefix{netip.MustParsePrefix("100.64.0.1/32")},
167167
AllowedIPs: []netip.Prefix{
168-
netip.MustParsePrefix("100.64.0.1/32"),
169168
tsaddr.AllIPv4(),
170169
netip.MustParsePrefix("192.168.0.0/24"),
170+
netip.MustParsePrefix("100.64.0.1/32"),
171+
tsaddr.AllIPv6(),
172+
},
173+
PrimaryRoutes: []netip.Prefix{
174+
netip.MustParsePrefix("192.168.0.0/24"),
171175
},
172176
HomeDERP: 0,
173177
LegacyDERPString: "127.3.3.40:0",

hscontrol/mapper/tail.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ package mapper
22

33
import (
44
"fmt"
5-
"net/netip"
65
"time"
76

87
"github.com/juanfont/headscale/hscontrol/policy"
98
"github.com/juanfont/headscale/hscontrol/routes"
109
"github.com/juanfont/headscale/hscontrol/types"
1110
"github.com/samber/lo"
11+
"tailscale.com/net/tsaddr"
1212
"tailscale.com/tailcfg"
1313
)
1414

@@ -49,14 +49,6 @@ func tailNode(
4949
) (*tailcfg.Node, error) {
5050
addrs := node.Prefixes()
5151

52-
allowedIPs := append(
53-
[]netip.Prefix{},
54-
addrs...) // we append the node own IP, as it is required by the clients
55-
56-
for _, route := range node.SubnetRoutes() {
57-
allowedIPs = append(allowedIPs, netip.Prefix(route))
58-
}
59-
6052
var derp int
6153

6254
// TODO(kradalby): legacyDERP was removed in tailscale/tailscale@2fc4455e6dd9ab7f879d4e2f7cffc2be81f14077
@@ -89,6 +81,10 @@ func tailNode(
8981
}
9082
tags = lo.Uniq(append(tags, node.ForcedTags...))
9183

84+
allowed := append(node.Prefixes(), primary.PrimaryRoutes(node.ID)...)
85+
allowed = append(allowed, node.ExitRoutes()...)
86+
tsaddr.SortPrefixes(allowed)
87+
9288
tNode := tailcfg.Node{
9389
ID: tailcfg.NodeID(node.ID), // this is the actual ID
9490
StableID: node.ID.StableID(),
@@ -104,7 +100,7 @@ func tailNode(
104100
DiscoKey: node.DiscoKey,
105101
Addresses: addrs,
106102
PrimaryRoutes: primary.PrimaryRoutes(node.ID),
107-
AllowedIPs: allowedIPs,
103+
AllowedIPs: allowed,
108104
Endpoints: node.Endpoints,
109105
HomeDERP: derp,
110106
LegacyDERPString: legacyDERP,

hscontrol/mapper/tail_test.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ func TestTailNode(t *testing.T) {
6767
want: &tailcfg.Node{
6868
Name: "empty",
6969
StableID: "0",
70-
Addresses: []netip.Prefix{},
71-
AllowedIPs: []netip.Prefix{},
7270
HomeDERP: 0,
7371
LegacyDERPString: "127.3.3.40:0",
7472
Hostinfo: hiview(tailcfg.Hostinfo{}),
@@ -139,9 +137,13 @@ func TestTailNode(t *testing.T) {
139137
),
140138
Addresses: []netip.Prefix{netip.MustParsePrefix("100.64.0.1/32")},
141139
AllowedIPs: []netip.Prefix{
142-
netip.MustParsePrefix("100.64.0.1/32"),
143140
tsaddr.AllIPv4(),
144141
netip.MustParsePrefix("192.168.0.0/24"),
142+
netip.MustParsePrefix("100.64.0.1/32"),
143+
tsaddr.AllIPv6(),
144+
},
145+
PrimaryRoutes: []netip.Prefix{
146+
netip.MustParsePrefix("192.168.0.0/24"),
145147
},
146148
HomeDERP: 0,
147149
LegacyDERPString: "127.3.3.40:0",
@@ -156,10 +158,6 @@ func TestTailNode(t *testing.T) {
156158

157159
Tags: []string{},
158160

159-
PrimaryRoutes: []netip.Prefix{
160-
netip.MustParsePrefix("192.168.0.0/24"),
161-
},
162-
163161
LastSeen: &lastSeen,
164162
MachineAuthorized: true,
165163

hscontrol/routes/primary.go

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/juanfont/headscale/hscontrol/types"
1212
"github.com/juanfont/headscale/hscontrol/util"
1313
xmaps "golang.org/x/exp/maps"
14+
"tailscale.com/net/tsaddr"
1415
"tailscale.com/util/set"
1516
)
1617

@@ -74,18 +75,12 @@ func (pr *PrimaryRoutes) updatePrimaryLocked() bool {
7475
// If the current primary is not available, select a new one.
7576
for prefix, nodes := range allPrimaries {
7677
if node, ok := pr.primaries[prefix]; ok {
77-
if len(nodes) < 2 {
78-
delete(pr.primaries, prefix)
79-
changed = true
80-
continue
81-
}
82-
8378
// If the current primary is still available, continue.
8479
if slices.Contains(nodes, node) {
8580
continue
8681
}
8782
}
88-
if len(nodes) >= 2 {
83+
if len(nodes) >= 1 {
8984
pr.primaries[prefix] = nodes[0]
9085
changed = true
9186
}
@@ -107,12 +102,16 @@ func (pr *PrimaryRoutes) updatePrimaryLocked() bool {
107102
return changed
108103
}
109104

110-
func (pr *PrimaryRoutes) SetRoutes(node types.NodeID, prefix ...netip.Prefix) bool {
105+
// SetRoutes sets the routes for a given Node ID and recalculates the primary routes
106+
// of the headscale.
107+
// It returns true if there was a change in primary routes.
108+
// All exit routes are ignored as they are not used in primary route context.
109+
func (pr *PrimaryRoutes) SetRoutes(node types.NodeID, prefixes ...netip.Prefix) bool {
111110
pr.mu.Lock()
112111
defer pr.mu.Unlock()
113112

114113
// If no routes are being set, remove the node from the routes map.
115-
if len(prefix) == 0 {
114+
if len(prefixes) == 0 {
116115
if _, ok := pr.routes[node]; ok {
117116
delete(pr.routes, node)
118117
return pr.updatePrimaryLocked()
@@ -121,12 +120,17 @@ func (pr *PrimaryRoutes) SetRoutes(node types.NodeID, prefix ...netip.Prefix) bo
121120
return false
122121
}
123122

124-
if _, ok := pr.routes[node]; !ok {
125-
pr.routes[node] = make(set.Set[netip.Prefix], len(prefix))
123+
rs := make(set.Set[netip.Prefix], len(prefixes))
124+
for _, prefix := range prefixes {
125+
if !tsaddr.IsExitRoute(prefix) {
126+
rs.Add(prefix)
127+
}
126128
}
127129

128-
for _, p := range prefix {
129-
pr.routes[node].Add(p)
130+
if rs.Len() != 0 {
131+
pr.routes[node] = rs
132+
} else {
133+
delete(pr.routes, node)
130134
}
131135

132136
return pr.updatePrimaryLocked()
@@ -153,6 +157,7 @@ func (pr *PrimaryRoutes) PrimaryRoutes(id types.NodeID) []netip.Prefix {
153157
}
154158
}
155159

160+
tsaddr.SortPrefixes(routes)
156161
return routes
157162
}
158163

0 commit comments

Comments
 (0)