diff --git a/firewall/inspection/inspection.go b/firewall/inspection/inspection.go index 55629b19..7dc59494 100644 --- a/firewall/inspection/inspection.go +++ b/firewall/inspection/inspection.go @@ -85,11 +85,11 @@ func RunInspectors(conn *network.Connection, pkt packet.Packet) (network.Verdict verdict = network.VerdictDrop continueInspection = true case BLOCK_CONN: - conn.SetVerdict(network.VerdictBlock) + conn.SetVerdict(network.VerdictBlock, "", nil) verdict = conn.Verdict activeInspectors[key] = true case DROP_CONN: - conn.SetVerdict(network.VerdictDrop) + conn.SetVerdict(network.VerdictDrop, "", nil) verdict = conn.Verdict activeInspectors[key] = true case STOP_INSPECTING: diff --git a/firewall/master.go b/firewall/master.go index 86196e36..cafd11f2 100644 --- a/firewall/master.go +++ b/firewall/master.go @@ -143,9 +143,6 @@ func DecideOnConnection(conn *network.Connection, pkt packet.Packet) { //nolint: } } - var result endpoints.EPResult - var reason string - if p.PreventBypassing() { // check for bypass protection result, reason := PreventBypassing(conn) @@ -160,6 +157,9 @@ func DecideOnConnection(conn *network.Connection, pkt packet.Packet) { //nolint: } } + var result endpoints.EPResult + var reason endpoints.Reason + // check endpoints list if conn.Inbound { result, reason = p.MatchServiceEndpoint(conn.Entity) @@ -168,10 +168,10 @@ func DecideOnConnection(conn *network.Connection, pkt packet.Packet) { //nolint: } switch result { case endpoints.Denied: - conn.Deny("endpoint is blacklisted: " + reason) // Block Outbound / Drop Inbound + conn.DenyWithContext(reason.String(), reason.Context()) return case endpoints.Permitted: - conn.Accept("endpoint is whitelisted: " + reason) + conn.AcceptWithContext(reason.String(), reason.Context()) return } // continuing with result == NoMatch @@ -180,7 +180,7 @@ func DecideOnConnection(conn *network.Connection, pkt packet.Packet) { //nolint: result, reason = p.MatchFilterLists(conn.Entity) switch result { case endpoints.Denied: - conn.Deny("endpoint in filterlists: " + reason) + conn.DenyWithContext(reason.String(), reason.Context()) return case endpoints.NoMatch: // nothing to do diff --git a/intel/block_reason.go b/intel/block_reason.go new file mode 100644 index 00000000..5a14c6cd --- /dev/null +++ b/intel/block_reason.go @@ -0,0 +1,51 @@ +package intel + +import ( + "fmt" + "strings" +) + +// ListMatch represents an entity that has been +// matched against filterlists. +type ListMatch struct { + Entity string + ActiveLists []string + InactiveLists []string +} + +func (lm *ListMatch) String() string { + inactive := "" + if len(lm.InactiveLists) > 0 { + inactive = " and in deactivated lists " + strings.Join(lm.InactiveLists, ", ") + } + return fmt.Sprintf( + "%s in activated lists %s%s", + lm.Entity, + strings.Join(lm.ActiveLists, ","), + inactive, + ) +} + +// ListBlockReason is a list of list matches. +type ListBlockReason []ListMatch + +func (br ListBlockReason) String() string { + if len(br) == 0 { + return "" + } + + matches := make([]string, len(br)) + for idx, lm := range br { + matches[idx] = lm.String() + } + + return strings.Join(matches, " and ") +} + +// Context returns br wrapped into a map. It implements +// the endpoints.Reason interface. +func (br ListBlockReason) Context() interface{} { + return map[string]interface{}{ + "filterlists": br, + } +} diff --git a/intel/entity.go b/intel/entity.go index e46ac041..8d2e21fb 100644 --- a/intel/entity.go +++ b/intel/entity.go @@ -16,43 +16,6 @@ import ( "golang.org/x/net/publicsuffix" ) -// ListMatch represents an entity that has been -// matched against filterlists. -type ListMatch struct { - Entity string - ActiveLists []string - InactiveLists []string -} - -func (lm *ListMatch) String() string { - inactive := "" - if len(lm.InactiveLists) > 0 { - inactive = " and in deactivated lists " + strings.Join(lm.InactiveLists, ", ") - } - return fmt.Sprintf( - "%s in activated lists %s%s", - lm.Entity, - strings.Join(lm.ActiveLists, ","), - inactive, - ) -} - -// ListBlockReason is a list of list matches. -type ListBlockReason []ListMatch - -func (br ListBlockReason) String() string { - if len(br) == 0 { - return "" - } - - matches := make([]string, len(br)) - for idx, lm := range br { - matches[idx] = lm.String() - } - - return strings.Join(matches, " and ") -} - // Entity describes a remote endpoint in many different ways. // It embeddes a sync.Mutex but none of the endpoints own // functions performs locking. The caller MUST ENSURE diff --git a/nameserver/nameserver.go b/nameserver/nameserver.go index a30d933c..9b3d8016 100644 --- a/nameserver/nameserver.go +++ b/nameserver/nameserver.go @@ -278,7 +278,7 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, query *dns.Msg) er result, reason := conn.Process().Profile().MatchEndpoint(conn.Entity) if result == endpoints.Denied { - conn.Block("endpoint in blocklist: " + reason) + conn.BlockWithContext(reason.String(), reason.Context()) returnNXDomain(w, query, conn.Reason) return nil } @@ -286,7 +286,7 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, query *dns.Msg) er if result == endpoints.NoMatch { result, reason = conn.Process().Profile().MatchFilterLists(conn.Entity) if result == endpoints.Denied { - conn.Block("endpoint in filterlists: " + reason) + conn.BlockWithContext(reason.String(), reason.Context()) returnNXDomain(w, query, conn.Reason) return nil } diff --git a/network/connection.go b/network/connection.go index e0af4c01..bbc088dc 100644 --- a/network/connection.go +++ b/network/connection.go @@ -31,9 +31,10 @@ type Connection struct { //nolint:maligned // TODO: fix alignment Entity *intel.Entity // needs locking, instance is never shared process *process.Process - Verdict Verdict - Reason string - ReasonID string // format source[:id[:id]] // TODO + Verdict Verdict + Reason string + ReasonContext interface{} + ReasonID string // format source[:id[:id]] // TODO Started int64 Ended int64 @@ -164,59 +165,82 @@ func GetConnection(id string) (*Connection, bool) { return conn, ok } -// Accept accepts the connection. -func (conn *Connection) Accept(reason string) { - if conn.SetVerdict(VerdictAccept) { - conn.Reason = reason +// AcceptWithContext accepts the connection. +func (conn *Connection) AcceptWithContext(reason string, ctx interface{}) { + if conn.SetVerdict(VerdictAccept, reason, ctx) { log.Infof("filter: granting connection %s, %s", conn, conn.Reason) } else { log.Warningf("filter: tried to accept %s, but current verdict is %s", conn, conn.Verdict) } } -// Block blocks the connection. -func (conn *Connection) Block(reason string) { - if conn.SetVerdict(VerdictBlock) { - conn.Reason = reason +// Accept is like AcceptWithContext but only accepts a reason. +func (conn *Connection) Accept(reason string) { + conn.AcceptWithContext(reason, nil) +} + +// BlockWithContext blocks the connection. +func (conn *Connection) BlockWithContext(reason string, ctx interface{}) { + if conn.SetVerdict(VerdictBlock, reason, ctx) { log.Infof("filter: blocking connection %s, %s", conn, conn.Reason) } else { log.Warningf("filter: tried to block %s, but current verdict is %s", conn, conn.Verdict) } } -// Drop drops the connection. -func (conn *Connection) Drop(reason string) { - if conn.SetVerdict(VerdictDrop) { - conn.Reason = reason +// Block is like BlockWithContext but does only accepts a reason. +func (conn *Connection) Block(reason string) { + conn.BlockWithContext(reason, nil) +} + +// DropWithContext drops the connection. +func (conn *Connection) DropWithContext(reason string, ctx interface{}) { + if conn.SetVerdict(VerdictDrop, reason, ctx) { log.Infof("filter: dropping connection %s, %s", conn, conn.Reason) } else { log.Warningf("filter: tried to drop %s, but current verdict is %s", conn, conn.Verdict) } } -// Deny blocks or drops the link depending on the connection direction. -func (conn *Connection) Deny(reason string) { +// Drop is like DropWithContext but does only accepts a reason. +func (conn *Connection) Drop(reason string) { + conn.DropWithContext(reason, nil) +} + +// DenyWithContext blocks or drops the link depending on the connection direction. +func (conn *Connection) DenyWithContext(reason string, ctx interface{}) { if conn.Inbound { - conn.Drop(reason) + conn.DropWithContext(reason, ctx) } else { - conn.Block(reason) + conn.BlockWithContext(reason, ctx) } } -// Failed marks the connection with VerdictFailed and stores the reason. -func (conn *Connection) Failed(reason string) { - if conn.SetVerdict(VerdictFailed) { - conn.Reason = reason +// Deny is like DenyWithContext but only accepts a reason. +func (conn *Connection) Deny(reason string) { + conn.DenyWithContext(reason, nil) +} + +// FailedWithContext marks the connection with VerdictFailed and stores the reason. +func (conn *Connection) FailedWithContext(reason string, ctx interface{}) { + if conn.SetVerdict(VerdictFailed, reason, ctx) { log.Infof("filter: dropping connection %s because of an internal error: %s", conn, reason) } else { log.Warningf("filter: tried to drop %s due to error but current verdict is %s", conn, conn.Verdict) } } +// Failed is like FailedWithContext but only accepts a string. +func (conn *Connection) Failed(reason string) { + conn.FailedWithContext(reason, nil) +} + // SetVerdict sets a new verdict for the connection, making sure it does not interfere with previous verdicts. -func (conn *Connection) SetVerdict(newVerdict Verdict) (ok bool) { +func (conn *Connection) SetVerdict(newVerdict Verdict, reason string, ctx interface{}) (ok bool) { if newVerdict >= conn.Verdict { conn.Verdict = newVerdict + conn.Reason = reason + conn.ReasonContext = ctx return true } return false diff --git a/profile/endpoints/endpoint-any.go b/profile/endpoints/endpoint-any.go index 34fd65b4..8e8deb98 100644 --- a/profile/endpoints/endpoint-any.go +++ b/profile/endpoints/endpoint-any.go @@ -8,8 +8,8 @@ type EndpointAny struct { } // Matches checks whether the given entity matches this endpoint definition. -func (ep *EndpointAny) Matches(entity *intel.Entity) (result EPResult, reason string) { - return ep.matchesPPP(entity), "matches *" +func (ep *EndpointAny) Matches(entity *intel.Entity) (EPResult, Reason) { + return ep.match(ep, entity, "*", "matches") } func (ep *EndpointAny) String() string { diff --git a/profile/endpoints/endpoint-asn.go b/profile/endpoints/endpoint-asn.go index dee94f2d..6713d199 100644 --- a/profile/endpoints/endpoint-asn.go +++ b/profile/endpoints/endpoint-asn.go @@ -16,24 +16,22 @@ var ( type EndpointASN struct { EndpointBase - ASN uint - Reason string + ASN uint } // Matches checks whether the given entity matches this endpoint definition. -func (ep *EndpointASN) Matches(entity *intel.Entity) (result EPResult, reason string) { - if entity.IP == nil { - return Undeterminable, "" - } - +func (ep *EndpointASN) Matches(entity *intel.Entity) (EPResult, Reason) { asn, ok := entity.GetASN() if !ok { - return Undeterminable, "" + return Undeterminable, nil } + if asn == ep.ASN { - return ep.matchesPPP(entity), ep.Reason + asnStr := strconv.Itoa(int(ep.ASN)) + return ep.match(ep, entity, asnStr, "IP is part of AS") } - return NoMatch, "" + + return NoMatch, nil } func (ep *EndpointASN) String() string { @@ -48,8 +46,7 @@ func parseTypeASN(fields []string) (Endpoint, error) { } ep := &EndpointASN{ - ASN: uint(asn), - Reason: "IP is part of AS" + strconv.FormatInt(int64(asn), 10), + ASN: uint(asn), } return ep.parsePPP(ep, fields) } diff --git a/profile/endpoints/endpoint-country.go b/profile/endpoints/endpoint-country.go index 63d21bfc..85449cf5 100644 --- a/profile/endpoints/endpoint-country.go +++ b/profile/endpoints/endpoint-country.go @@ -19,19 +19,16 @@ type EndpointCountry struct { } // Matches checks whether the given entity matches this endpoint definition. -func (ep *EndpointCountry) Matches(entity *intel.Entity) (result EPResult, reason string) { - if entity.IP == nil { - return Undeterminable, "" - } - +func (ep *EndpointCountry) Matches(entity *intel.Entity) (EPResult, Reason) { country, ok := entity.GetCountry() if !ok { - return Undeterminable, "" + return Undeterminable, nil } + if country == ep.Country { - return ep.matchesPPP(entity), "IP is located in " + country + return ep.match(ep, entity, country, "IP is located in") } - return NoMatch, "" + return NoMatch, nil } func (ep *EndpointCountry) String() string { diff --git a/profile/endpoints/endpoint-domain.go b/profile/endpoints/endpoint-domain.go index 2691ba13..fbd0dcf9 100644 --- a/profile/endpoints/endpoint-domain.go +++ b/profile/endpoints/endpoint-domain.go @@ -28,47 +28,48 @@ type EndpointDomain struct { Domain string DomainZone string MatchType uint8 - Reason string } -func (ep *EndpointDomain) check(entity *intel.Entity, domain string) (EPResult, string) { +func (ep *EndpointDomain) check(entity *intel.Entity, domain string) (EPResult, Reason) { + result, reason := ep.match(ep, entity, ep.Domain, "domain matches") + switch ep.MatchType { case domainMatchTypeExact: if domain == ep.Domain { - return ep.matchesPPP(entity), ep.Reason + return result, reason } case domainMatchTypeZone: if domain == ep.Domain { - return ep.matchesPPP(entity), ep.Reason + return result, reason } if strings.HasSuffix(domain, ep.DomainZone) { - return ep.matchesPPP(entity), ep.Reason + return result, reason } case domainMatchTypeSuffix: if strings.HasSuffix(domain, ep.Domain) { - return ep.matchesPPP(entity), ep.Reason + return result, reason } case domainMatchTypePrefix: if strings.HasPrefix(domain, ep.Domain) { - return ep.matchesPPP(entity), ep.Reason + return result, reason } case domainMatchTypeContains: if strings.Contains(domain, ep.Domain) { - return ep.matchesPPP(entity), ep.Reason + return result, reason } } - return NoMatch, "" + return NoMatch, nil } // Matches checks whether the given entity matches this endpoint definition. -func (ep *EndpointDomain) Matches(entity *intel.Entity) (result EPResult, reason string) { +func (ep *EndpointDomain) Matches(entity *intel.Entity) (EPResult, Reason) { if entity.Domain == "" { - return NoMatch, "" + return NoMatch, nil } - result, reason = ep.check(entity, entity.Domain) + result, reason := ep.check(entity, entity.Domain) if result != NoMatch { - return + return result, reason } if entity.CNAMECheckEnabled() { @@ -80,7 +81,7 @@ func (ep *EndpointDomain) Matches(entity *intel.Entity) (result EPResult, reason } } - return NoMatch, "" + return NoMatch, nil } func (ep *EndpointDomain) String() string { @@ -93,7 +94,6 @@ func parseTypeDomain(fields []string) (Endpoint, error) { if domainRegex.MatchString(domain) || altDomainRegex.MatchString(domain) { ep := &EndpointDomain{ OriginalValue: domain, - Reason: "domain matches " + domain, } // fix domain ending diff --git a/profile/endpoints/endpoint-ip.go b/profile/endpoints/endpoint-ip.go index 6fa742c0..43ea47f7 100644 --- a/profile/endpoints/endpoint-ip.go +++ b/profile/endpoints/endpoint-ip.go @@ -10,19 +10,19 @@ import ( type EndpointIP struct { EndpointBase - IP net.IP - Reason string + IP net.IP } // Matches checks whether the given entity matches this endpoint definition. -func (ep *EndpointIP) Matches(entity *intel.Entity) (result EPResult, reason string) { +func (ep *EndpointIP) Matches(entity *intel.Entity) (EPResult, Reason) { if entity.IP == nil { - return Undeterminable, "" + return Undeterminable, nil } + if ep.IP.Equal(entity.IP) { - return ep.matchesPPP(entity), ep.Reason + return ep.match(ep, entity, ep.IP.String(), "IP matches") } - return NoMatch, "" + return NoMatch, nil } func (ep *EndpointIP) String() string { @@ -33,8 +33,7 @@ func parseTypeIP(fields []string) (Endpoint, error) { ip := net.ParseIP(fields[1]) if ip != nil { ep := &EndpointIP{ - IP: ip, - Reason: "IP is " + ip.String(), + IP: ip, } return ep.parsePPP(ep, fields) } diff --git a/profile/endpoints/endpoint-iprange.go b/profile/endpoints/endpoint-iprange.go index 16afa4bb..bc0d22fe 100644 --- a/profile/endpoints/endpoint-iprange.go +++ b/profile/endpoints/endpoint-iprange.go @@ -10,19 +10,18 @@ import ( type EndpointIPRange struct { EndpointBase - Net *net.IPNet - Reason string + Net *net.IPNet } // Matches checks whether the given entity matches this endpoint definition. -func (ep *EndpointIPRange) Matches(entity *intel.Entity) (result EPResult, reason string) { +func (ep *EndpointIPRange) Matches(entity *intel.Entity) (EPResult, Reason) { if entity.IP == nil { - return Undeterminable, "" + return Undeterminable, nil } if ep.Net.Contains(entity.IP) { - return ep.matchesPPP(entity), ep.Reason + return ep.match(ep, entity, ep.Net.String(), "IP is in") } - return NoMatch, "" + return NoMatch, nil } func (ep *EndpointIPRange) String() string { @@ -33,8 +32,7 @@ func parseTypeIPRange(fields []string) (Endpoint, error) { _, net, err := net.ParseCIDR(fields[1]) if err == nil { ep := &EndpointIPRange{ - Net: net, - Reason: "IP is part of " + net.String(), + Net: net, } return ep.parsePPP(ep, fields) } diff --git a/profile/endpoints/endpoint-lists.go b/profile/endpoints/endpoint-lists.go index b11da060..27ec8b00 100644 --- a/profile/endpoints/endpoint-lists.go +++ b/profile/endpoints/endpoint-lists.go @@ -12,18 +12,19 @@ type EndpointLists struct { ListSet []string Lists string - Reason string } // Matches checks whether the given entity matches this endpoint definition. -func (ep *EndpointLists) Matches(entity *intel.Entity) (result EPResult, reason string) { - entity.LoadLists() - - if entity.MatchLists(ep.ListSet) { - return ep.matchesPPP(entity), entity.ListBlockReason().String() +func (ep *EndpointLists) Matches(entity *intel.Entity) (EPResult, Reason) { + if !entity.LoadLists() { + return Undeterminable, nil } - return NoMatch, "" + if entity.MatchLists(ep.ListSet) { + return ep.match(ep, entity, ep.Lists, "filterlist contains", "filterlist", entity.ListBlockReason()) + } + + return NoMatch, nil } func (ep *EndpointLists) String() string { @@ -36,7 +37,6 @@ func parseTypeList(fields []string) (Endpoint, error) { ep := &EndpointLists{ ListSet: lists, Lists: "L:" + strings.Join(lists, ","), - Reason: "matched lists " + strings.Join(lists, ","), } return ep.parsePPP(ep, fields) } diff --git a/profile/endpoints/endpoint.go b/profile/endpoints/endpoint.go index b634b911..43741c40 100644 --- a/profile/endpoints/endpoint.go +++ b/profile/endpoints/endpoint.go @@ -11,7 +11,7 @@ import ( // Endpoint describes an Endpoint Matcher type Endpoint interface { - Matches(entity *intel.Entity) (EPResult, string) + Matches(entity *intel.Entity) (EPResult, Reason) String() string } @@ -24,6 +24,35 @@ type EndpointBase struct { //nolint:maligned // TODO Permitted bool } +func (ep *EndpointBase) match(s fmt.Stringer, entity *intel.Entity, value, desc string, keval ...interface{}) (EPResult, Reason) { + result := ep.matchesPPP(entity) + if result == Undeterminable || result == NoMatch { + return result, nil + } + + return result, ep.makeReason(s, value, desc) +} + +func (ep *EndpointBase) makeReason(s fmt.Stringer, value, desc string, keyval ...interface{}) Reason { + r := &reason{ + description: desc, + Filter: ep.renderPPP(s.String()), + Permitted: ep.Permitted, + Value: value, + } + + r.Extra = make(map[string]interface{}) + + for idx := 0; idx < int(len(keyval)/2); idx += 2 { + key := keyval[idx] + val := keyval[idx+1] + + r.Extra[key.(string)] = val + } + + return r +} + func (ep *EndpointBase) matchesPPP(entity *intel.Entity) (result EPResult) { // only check if protocol is defined if ep.Protocol > 0 { diff --git a/profile/endpoints/endpoints.go b/profile/endpoints/endpoints.go index 7a49a0c8..d8af9423 100644 --- a/profile/endpoints/endpoints.go +++ b/profile/endpoints/endpoints.go @@ -21,6 +21,12 @@ const ( Permitted ) +// IsDecision returns true if result represents a decision +// and false if result is NoMatch or Undeterminable. +func IsDecision(result EPResult) bool { + return result == Denied || result == Permitted +} + // ParseEndpoints parses a list of endpoints and returns a list of Endpoints for matching. func ParseEndpoints(entries []string) (Endpoints, error) { var firstErr error @@ -57,7 +63,7 @@ func (e Endpoints) IsSet() bool { } // Match checks whether the given entity matches any of the endpoint definitions in the list. -func (e Endpoints) Match(entity *intel.Entity) (result EPResult, reason string) { +func (e Endpoints) Match(entity *intel.Entity) (result EPResult, reason Reason) { for _, entry := range e { if entry != nil { if result, reason = entry.Matches(entity); result != NoMatch { @@ -66,7 +72,7 @@ func (e Endpoints) Match(entity *intel.Entity) (result EPResult, reason string) } } - return NoMatch, "" + return NoMatch, nil } func (e Endpoints) String() string { diff --git a/profile/endpoints/reason.go b/profile/endpoints/reason.go new file mode 100644 index 00000000..d137c3b3 --- /dev/null +++ b/profile/endpoints/reason.go @@ -0,0 +1,34 @@ +package endpoints + +// Reason describes the reason why an endpoint has been +// permitted or blocked. +type Reason interface { + // String should return a human readable string + // describing the decision reason. + String() string + + // Context returns the context that was used + // for the decision. + Context() interface{} +} + +type reason struct { + description string + Filter string + Value string + Permitted bool + Extra map[string]interface{} +} + +func (r *reason) String() string { + prefix := "endpoint in blocklist: " + if r.Permitted { + prefix = "endpoint in whitelist: " + } + + return prefix + r.description + " " + r.Value +} + +func (r *reason) Context() interface{} { + return r +} diff --git a/profile/profile-layered.go b/profile/profile-layered.go index edb8a8a2..45311662 100644 --- a/profile/profile-layered.go +++ b/profile/profile-layered.go @@ -204,12 +204,12 @@ func (lp *LayeredProfile) DefaultAction() uint8 { } // MatchEndpoint checks if the given endpoint matches an entry in any of the profiles. -func (lp *LayeredProfile) MatchEndpoint(entity *intel.Entity) (result endpoints.EPResult, reason string) { +func (lp *LayeredProfile) MatchEndpoint(entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) { for _, layer := range lp.layers { if layer.endpoints.IsSet() { - result, reason = layer.endpoints.Match(entity) - if result != endpoints.NoMatch { - return + result, reason := layer.endpoints.Match(entity) + if endpoints.IsDecision(result) { + return result, reason } } } @@ -220,14 +220,14 @@ func (lp *LayeredProfile) MatchEndpoint(entity *intel.Entity) (result endpoints. } // MatchServiceEndpoint checks if the given endpoint of an inbound connection matches an entry in any of the profiles. -func (lp *LayeredProfile) MatchServiceEndpoint(entity *intel.Entity) (result endpoints.EPResult, reason string) { +func (lp *LayeredProfile) MatchServiceEndpoint(entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) { entity.EnableReverseResolving() for _, layer := range lp.layers { if layer.serviceEndpoints.IsSet() { - result, reason = layer.serviceEndpoints.Match(entity) - if result != endpoints.NoMatch { - return + result, reason := layer.serviceEndpoints.Match(entity) + if endpoints.IsDecision(result) { + return result, reason } } } @@ -239,7 +239,7 @@ func (lp *LayeredProfile) MatchServiceEndpoint(entity *intel.Entity) (result end // MatchFilterLists matches the entity against the set of filter // lists. -func (lp *LayeredProfile) MatchFilterLists(entity *intel.Entity) (endpoints.EPResult, string) { +func (lp *LayeredProfile) MatchFilterLists(entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) { entity.ResolveSubDomainLists(lp.FilterSubDomains()) entity.EnableCNAMECheck(lp.FilterCNAMEs()) @@ -249,10 +249,10 @@ func (lp *LayeredProfile) MatchFilterLists(entity *intel.Entity) (endpoints.EPRe entity.LoadLists() if entity.MatchLists(layer.filterListIDs) { - return endpoints.Denied, entity.ListBlockReason().String() + return endpoints.Denied, entity.ListBlockReason() } - return endpoints.NoMatch, "" + return endpoints.NoMatch, nil } } @@ -262,11 +262,11 @@ func (lp *LayeredProfile) MatchFilterLists(entity *intel.Entity) (endpoints.EPRe entity.LoadLists() if entity.MatchLists(cfgFilterLists) { - return endpoints.Denied, entity.ListBlockReason().String() + return endpoints.Denied, entity.ListBlockReason() } } - return endpoints.NoMatch, "" + return endpoints.NoMatch, nil } // AddEndpoint adds an endpoint to the local endpoint list, saves the local profile and reloads the configuration.