Skip to content

Commit bbaed46

Browse files
committed
only send relevant filterrules to nodes
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
1 parent 1c9c472 commit bbaed46

File tree

4 files changed

+464
-429
lines changed

4 files changed

+464
-429
lines changed

hscontrol/db/acls_test.go

-116
Original file line numberDiff line numberDiff line change
@@ -125,122 +125,6 @@ func TestInvalidTagValidUser(t *testing.T) {
125125
}
126126
}
127127

128-
func TestPortGroup(t *testing.T) {
129-
machine := types.Machine{
130-
ID: 0,
131-
MachineKey: "foo",
132-
NodeKey: "bar",
133-
DiscoKey: "faa",
134-
Hostname: "testmachine",
135-
UserID: 0,
136-
User: types.User{
137-
Name: "testuser",
138-
},
139-
RegisterMethod: util.RegisterMethodAuthKey,
140-
IPAddresses: types.MachineAddresses{netip.MustParseAddr("100.64.0.5")},
141-
}
142-
143-
acl := []byte(`
144-
{
145-
"groups": {
146-
"group:example": [
147-
"testuser",
148-
],
149-
},
150-
151-
"hosts": {
152-
"host-1": "100.100.100.100",
153-
"subnet-1": "100.100.101.100/24",
154-
},
155-
156-
"acls": [
157-
{
158-
"action": "accept",
159-
"src": [
160-
"group:example",
161-
],
162-
"dst": [
163-
"host-1:*",
164-
],
165-
},
166-
],
167-
}
168-
`)
169-
pol, err := policy.LoadACLPolicyFromBytes(acl, "hujson")
170-
assert.NoError(t, err)
171-
172-
got, _, err := policy.GenerateFilterRules(pol, &machine, types.Machines{})
173-
assert.NoError(t, err)
174-
175-
want := []tailcfg.FilterRule{
176-
{
177-
SrcIPs: []string{"100.64.0.5/32"},
178-
DstPorts: []tailcfg.NetPortRange{
179-
{IP: "100.100.100.100/32", Ports: tailcfg.PortRange{Last: 65535}},
180-
},
181-
},
182-
}
183-
184-
if diff := cmp.Diff(want, got); diff != "" {
185-
t.Errorf("TestPortGroup() unexpected result (-want +got):\n%s", diff)
186-
}
187-
}
188-
189-
func TestPortUser(t *testing.T) {
190-
machine := types.Machine{
191-
ID: 0,
192-
MachineKey: "12345",
193-
NodeKey: "bar",
194-
DiscoKey: "faa",
195-
Hostname: "testmachine",
196-
UserID: 0,
197-
User: types.User{
198-
Name: "testuser",
199-
},
200-
RegisterMethod: util.RegisterMethodAuthKey,
201-
IPAddresses: types.MachineAddresses{netip.MustParseAddr("100.64.0.9")},
202-
}
203-
204-
acl := []byte(`
205-
{
206-
"hosts": {
207-
"host-1": "100.100.100.100",
208-
"subnet-1": "100.100.101.100/24",
209-
},
210-
211-
"acls": [
212-
{
213-
"action": "accept",
214-
"src": [
215-
"testuser",
216-
],
217-
"dst": [
218-
"host-1:*",
219-
],
220-
},
221-
],
222-
}
223-
`)
224-
pol, err := policy.LoadACLPolicyFromBytes(acl, "hujson")
225-
assert.NoError(t, err)
226-
227-
got, _, err := policy.GenerateFilterRules(pol, &machine, types.Machines{})
228-
assert.NoError(t, err)
229-
230-
want := []tailcfg.FilterRule{
231-
{
232-
SrcIPs: []string{"100.64.0.9/32"},
233-
DstPorts: []tailcfg.NetPortRange{
234-
{IP: "100.100.100.100/32", Ports: tailcfg.PortRange{Last: 65535}},
235-
},
236-
},
237-
}
238-
239-
if diff := cmp.Diff(want, got); diff != "" {
240-
t.Errorf("TestPortUser() unexpected result (-want +got):\n%s", diff)
241-
}
242-
}
243-
244128
// this test should validate that we can expand a group in a TagOWner section and
245129
// match properly the IP's of the related hosts. The owner is valid and the tag is also valid.
246130
// the tag is matched in the Destinations section.

hscontrol/mapper/mapper_test.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,8 @@ func Test_fullMapResponse(t *testing.T) {
403403
ACLs: []policy.ACL{
404404
{
405405
Action: "accept",
406-
Sources: []string{"mini"},
407-
Destinations: []string{"100.64.0.2:*"},
406+
Sources: []string{"100.64.0.2"},
407+
Destinations: []string{"mini:*"},
408408
},
409409
},
410410
},
@@ -430,8 +430,9 @@ func Test_fullMapResponse(t *testing.T) {
430430
CollectServices: "false",
431431
PacketFilter: []tailcfg.FilterRule{
432432
{
433-
SrcIPs: []string{"100.64.0.1/32", "100.64.0.2/32"},
433+
SrcIPs: []string{"100.64.0.2/32"},
434434
DstPorts: []tailcfg.NetPortRange{
435+
{IP: "100.64.0.1/32", Ports: tailcfg.PortRangeAny},
435436
{IP: "100.64.0.2/32", Ports: tailcfg.PortRangeAny},
436437
},
437438
},

hscontrol/policy/acls.go

+39-50
Original file line numberDiff line numberDiff line change
@@ -177,33 +177,60 @@ func (pol *ACLPolicy) generateFilterRules(
177177
srcIPs = append(srcIPs, srcs...)
178178
}
179179

180-
protocols, needsWildcard, err := parseProtocol(acl.Protocol)
180+
protocols, isWildcard, err := parseProtocol(acl.Protocol)
181181
if err != nil {
182182
log.Error().
183183
Msgf("Error parsing ACL %d. protocol unknown %s", index, acl.Protocol)
184184

185185
return nil, err
186186
}
187187

188+
// record if the rule is actually relevant for the given machine.
189+
isRelevant := false
190+
188191
destPorts := []tailcfg.NetPortRange{}
189-
for destIndex, dest := range acl.Destinations {
190-
dests, err := pol.getNetPortRangeFromDestination(
191-
dest,
192+
for _, dest := range acl.Destinations {
193+
alias, port, err := parseDestination(dest)
194+
if err != nil {
195+
return nil, err
196+
}
197+
198+
expanded, err := pol.ExpandAlias(
192199
machines,
193-
needsWildcard,
200+
alias,
194201
)
195202
if err != nil {
196-
log.Error().
197-
Interface("dest", dest).
198-
Int("ACL index", index).
199-
Int("dest index", destIndex).
200-
Msgf("Error parsing ACL")
203+
return nil, err
204+
}
201205

206+
if machine.IPAddresses.InIPSet(expanded) {
207+
isRelevant = true
208+
}
209+
210+
ports, err := expandPorts(port, isWildcard)
211+
if err != nil {
202212
return nil, err
203213
}
214+
215+
dests := []tailcfg.NetPortRange{}
216+
for _, dest := range expanded.Prefixes() {
217+
for _, port := range *ports {
218+
pr := tailcfg.NetPortRange{
219+
IP: dest.String(),
220+
Ports: port,
221+
}
222+
dests = append(dests, pr)
223+
}
224+
}
204225
destPorts = append(destPorts, dests...)
205226
}
206227

228+
// if the rule does not apply to the machine we are evaluating,
229+
// do not add it to the list and continue.
230+
if !isRelevant {
231+
continue
232+
}
233+
207234
rules = append(rules, tailcfg.FilterRule{
208235
SrcIPs: srcIPs,
209236
DstPorts: destPorts,
@@ -368,44 +395,6 @@ func (pol *ACLPolicy) getIPsFromSource(
368395
return prefixes, nil
369396
}
370397

371-
// getNetPortRangeFromDestination returns a set of tailcfg.NetPortRange
372-
// which are associated with the dest alias.
373-
func (pol *ACLPolicy) getNetPortRangeFromDestination(
374-
dest string,
375-
machines types.Machines,
376-
needsWildcard bool,
377-
) ([]tailcfg.NetPortRange, error) {
378-
alias, port, err := parseDestination(dest)
379-
if err != nil {
380-
return nil, err
381-
}
382-
383-
expanded, err := pol.ExpandAlias(
384-
machines,
385-
alias,
386-
)
387-
if err != nil {
388-
return nil, err
389-
}
390-
ports, err := expandPorts(port, needsWildcard)
391-
if err != nil {
392-
return nil, err
393-
}
394-
395-
dests := []tailcfg.NetPortRange{}
396-
for _, dest := range expanded.Prefixes() {
397-
for _, port := range *ports {
398-
pr := tailcfg.NetPortRange{
399-
IP: dest.String(),
400-
Ports: port,
401-
}
402-
dests = append(dests, pr)
403-
}
404-
}
405-
406-
return dests, nil
407-
}
408-
409398
func parseDestination(dest string) (string, string, error) {
410399
var tokens []string
411400

@@ -605,14 +594,14 @@ func excludeCorrectlyTaggedNodes(
605594
return out
606595
}
607596

608-
func expandPorts(portsStr string, needsWildcard bool) (*[]tailcfg.PortRange, error) {
597+
func expandPorts(portsStr string, isWild bool) (*[]tailcfg.PortRange, error) {
609598
if isWildcard(portsStr) {
610599
return &[]tailcfg.PortRange{
611600
{First: portRangeBegin, Last: portRangeEnd},
612601
}, nil
613602
}
614603

615-
if needsWildcard {
604+
if isWild {
616605
return nil, ErrWildcardIsNeeded
617606
}
618607

0 commit comments

Comments
 (0)