fix: send empty PacketFilter when no rules match

This commit is contained in:
Johan Siebens
2024-01-19 09:56:28 +01:00
parent 123ca99665
commit 980ab1bc46
3 changed files with 36 additions and 16 deletions
+7 -11
View File
@@ -252,9 +252,9 @@ func (a ACLPolicy) NodeCapabilities(m *Machine) []tailcfg.NodeCapability {
} }
func (a ACLPolicy) BuildFilterRules(srcs []Machine, dst *Machine) []tailcfg.FilterRule { func (a ACLPolicy) BuildFilterRules(srcs []Machine, dst *Machine) []tailcfg.FilterRule {
var rules []tailcfg.FilterRule var rules = make([]tailcfg.FilterRule, 0)
transform := func(src []string, destPorts []tailcfg.NetPortRange, u *User) tailcfg.FilterRule { appendRules := func(rules []tailcfg.FilterRule, src []string, destPorts []tailcfg.NetPortRange, u *User) []tailcfg.FilterRule {
var allSrcIPsSet = &StringSet{} var allSrcIPsSet = &StringSet{}
for _, alias := range src { for _, alias := range src {
for _, src := range srcs { for _, src := range srcs {
@@ -266,29 +266,25 @@ func (a ACLPolicy) BuildFilterRules(srcs []Machine, dst *Machine) []tailcfg.Filt
allSrcIPs := allSrcIPsSet.Items() allSrcIPs := allSrcIPsSet.Items()
if len(allSrcIPs) == 0 { if len(allSrcIPs) == 0 {
allSrcIPs = nil return rules
} }
return tailcfg.FilterRule{ return append(rules, tailcfg.FilterRule{
SrcIPs: allSrcIPs, SrcIPs: allSrcIPs,
DstPorts: destPorts, DstPorts: destPorts,
} })
} }
for _, acl := range a.ACLs { for _, acl := range a.ACLs {
selfDestPorts, allDestPorts := a.expandMachineToDstPorts(dst, acl.Dst) selfDestPorts, allDestPorts := a.expandMachineToDstPorts(dst, acl.Dst)
if len(selfDestPorts) != 0 { if len(selfDestPorts) != 0 {
rules = append(rules, transform(acl.Src, selfDestPorts, &dst.User)) rules = appendRules(rules, acl.Src, selfDestPorts, &dst.User)
} }
if len(allDestPorts) != 0 { if len(allDestPorts) != 0 {
rules = append(rules, transform(acl.Src, allDestPorts, nil)) rules = appendRules(rules, acl.Src, allDestPorts, nil)
} }
} }
if len(rules) == 0 {
return []tailcfg.FilterRule{{}}
}
return rules return rules
} }
+16
View File
@@ -104,6 +104,22 @@ func TestACLPolicy_NodeAttributesWithUserAndTags(t *testing.T) {
assert.Equal(t, expectedAttrs, actualAttrs) assert.Equal(t, expectedAttrs, actualAttrs)
} }
func TestACLPolicy_BuildFilterRulesEmptyACL(t *testing.T) {
p1 := createMachine("john@example.com")
p2 := createMachine("jane@example.com")
policy := ACLPolicy{
ACLs: []ACL{},
}
dst := createMachine("john@example.com")
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2}, dst)
expectedRules := []tailcfg.FilterRule{}
assert.Equal(t, expectedRules, actualRules)
}
func TestACLPolicy_BuildFilterRulesWildcards(t *testing.T) { func TestACLPolicy_BuildFilterRulesWildcards(t *testing.T) {
p1 := createMachine("john@example.com") p1 := createMachine("john@example.com")
p2 := createMachine("jane@example.com") p2 := createMachine("jane@example.com")
+13 -5
View File
@@ -11,6 +11,14 @@ import (
"time" "time"
) )
// MapResponse is a custom tailcfg.MapResponse
// for marshalling non-nil zero-length slices (meaning explicitly now empty)
// see tailcfg.MapResponse documentation
type MapResponse struct {
tailcfg.MapResponse
PacketFilter []tailcfg.FilterRule
}
func NewPollNetMapper(req *tailcfg.MapRequest, machineID uint64, repository domain.Repository, sessionManager core.PollMapSessionManager) *PollNetMapper { func NewPollNetMapper(req *tailcfg.MapRequest, machineID uint64, repository domain.Repository, sessionManager core.PollMapSessionManager) *PollNetMapper {
return &PollNetMapper{ return &PollNetMapper{
req: req, req: req,
@@ -34,7 +42,7 @@ type PollNetMapper struct {
sessionManager core.PollMapSessionManager sessionManager core.PollMapSessionManager
} }
func (h *PollNetMapper) CreateMapResponse(ctx context.Context, delta bool) (*tailcfg.MapResponse, error) { func (h *PollNetMapper) CreateMapResponse(ctx context.Context, delta bool) (*MapResponse, error) {
h.Lock() h.Lock()
defer h.Unlock() defer h.Unlock()
@@ -106,10 +114,10 @@ func (h *PollNetMapper) CreateMapResponse(ctx context.Context, delta bool) (*tai
filterRules := policies.BuildFilterRules(candidatePeers, m) filterRules := policies.BuildFilterRules(candidatePeers, m)
controlTime := time.Now().UTC() controlTime := time.Now().UTC()
var mapResponse *tailcfg.MapResponse var mapResponse tailcfg.MapResponse
if !delta { if !delta {
mapResponse = &tailcfg.MapResponse{ mapResponse = tailcfg.MapResponse{
KeepAlive: false, KeepAlive: false,
Node: node, Node: node,
DNSConfig: ToDNSConfig(m, &m.Tailnet, &dnsConfig), DNSConfig: ToDNSConfig(m, &m.Tailnet, &dnsConfig),
@@ -125,7 +133,7 @@ func (h *PollNetMapper) CreateMapResponse(ctx context.Context, delta bool) (*tai
}, },
} }
} else { } else {
mapResponse = &tailcfg.MapResponse{ mapResponse = tailcfg.MapResponse{
Node: node, Node: node,
DNSConfig: ToDNSConfig(m, &m.Tailnet, &dnsConfig), DNSConfig: ToDNSConfig(m, &m.Tailnet, &dnsConfig),
PacketFilter: filterRules, PacketFilter: filterRules,
@@ -155,7 +163,7 @@ func (h *PollNetMapper) CreateMapResponse(ctx context.Context, delta bool) (*tai
h.prevSyncedPeerIDs = syncedPeerIDs h.prevSyncedPeerIDs = syncedPeerIDs
h.prevDerpMapChecksum = derpMap.Checksum h.prevDerpMapChecksum = derpMap.Checksum
return mapResponse, nil return &MapResponse{MapResponse: mapResponse, PacketFilter: filterRules}, nil
} }
type primaryRoutesCollector struct { type primaryRoutesCollector struct {