Add CNAME blocking support
This commit is contained in:
@@ -30,6 +30,9 @@ var (
|
||||
CfgOptionFilterSubDomainsKey = "filter/includeSubdomains"
|
||||
cfgOptionFilterSubDomains config.IntOption // security level option
|
||||
|
||||
CfgOptionFilterCNAMEKey = "filter/includeCNAMEs"
|
||||
cfgOptionFilterCNAME config.IntOption // security level option
|
||||
|
||||
CfgOptionBlockScopeLocalKey = "filter/blockLocal"
|
||||
cfgOptionBlockScopeLocal config.IntOption // security level option
|
||||
|
||||
@@ -180,6 +183,23 @@ Examples:
|
||||
cfgOptionFilterLists = config.Concurrent.GetAsStringArray(CfgOptionFilterListKey, []string{})
|
||||
cfgStringArrayOptions[CfgOptionFilterListKey] = cfgOptionFilterLists
|
||||
|
||||
// Include CNAMEs
|
||||
err = config.Register(&config.Option{
|
||||
Name: "Filter CNAMEs",
|
||||
Key: CfgOptionFilterCNAMEKey,
|
||||
Description: "Also filter requests where a CNAME would be blocked",
|
||||
OptType: config.OptTypeInt,
|
||||
ExternalOptType: "security level",
|
||||
DefaultValue: status.SecurityLevelsAll,
|
||||
ValidationRegex: "^(7|6|4)$",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfgOptionFilterCNAME = config.Concurrent.GetAsInt(CfgOptionFilterCNAMEKey, int64(status.SecurityLevelsAll))
|
||||
cfgIntOptions[CfgOptionFilterCNAMEKey] = cfgOptionFilterCNAME
|
||||
|
||||
// Include subdomains
|
||||
err = config.Register(&config.Option{
|
||||
Name: "Filter SubDomains",
|
||||
Key: CfgOptionFilterSubDomainsKey,
|
||||
|
||||
@@ -31,35 +31,77 @@ type EndpointDomain struct {
|
||||
Reason string
|
||||
}
|
||||
|
||||
func (ep *EndpointDomain) check(entity *intel.Entity, domain string) (EPResult, string) {
|
||||
switch ep.MatchType {
|
||||
case domainMatchTypeExact:
|
||||
if domain == ep.Domain {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeZone:
|
||||
if domain == ep.Domain {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
if strings.HasSuffix(domain, ep.DomainZone) {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeSuffix:
|
||||
if strings.HasSuffix(domain, ep.Domain) {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypePrefix:
|
||||
if strings.HasPrefix(domain, ep.Domain) {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeContains:
|
||||
if strings.Contains(domain, ep.Domain) {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
}
|
||||
return NoMatch, ""
|
||||
}
|
||||
|
||||
// Matches checks whether the given entity matches this endpoint definition.
|
||||
func (ep *EndpointDomain) Matches(entity *intel.Entity) (result EPResult, reason string) {
|
||||
if entity.Domain == "" {
|
||||
return NoMatch, ""
|
||||
}
|
||||
|
||||
switch ep.MatchType {
|
||||
case domainMatchTypeExact:
|
||||
if entity.Domain == ep.Domain {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeZone:
|
||||
if entity.Domain == ep.Domain {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
if strings.HasSuffix(entity.Domain, ep.DomainZone) {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeSuffix:
|
||||
if strings.HasSuffix(entity.Domain, ep.Domain) {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypePrefix:
|
||||
if strings.HasPrefix(entity.Domain, ep.Domain) {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeContains:
|
||||
if strings.Contains(entity.Domain, ep.Domain) {
|
||||
return ep.matchesPPP(entity), ep.Reason
|
||||
result, reason = ep.check(entity, entity.Domain)
|
||||
if result != NoMatch {
|
||||
return
|
||||
}
|
||||
|
||||
if entity.CNAMECheckEnabled() {
|
||||
for _, domain := range entity.CNAME {
|
||||
switch ep.MatchType {
|
||||
case domainMatchTypeExact:
|
||||
if domain == ep.Domain {
|
||||
result, reason = ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeZone:
|
||||
if domain == ep.Domain {
|
||||
result, reason = ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
if strings.HasSuffix(domain, ep.DomainZone) {
|
||||
result, reason = ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeSuffix:
|
||||
if strings.HasSuffix(domain, ep.Domain) {
|
||||
result, reason = ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypePrefix:
|
||||
if strings.HasPrefix(domain, ep.Domain) {
|
||||
result, reason = ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
case domainMatchTypeContains:
|
||||
if strings.Contains(domain, ep.Domain) {
|
||||
result, reason = ep.matchesPPP(entity), ep.Reason
|
||||
}
|
||||
}
|
||||
|
||||
if result == Denied {
|
||||
return result, reason
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ type LayeredProfile struct {
|
||||
RemoveOutOfScopeDNS config.BoolOption
|
||||
RemoveBlockedDNS config.BoolOption
|
||||
FilterSubDomains config.BoolOption
|
||||
FilterCNAMEs config.BoolOption
|
||||
PreventBypassing config.BoolOption
|
||||
}
|
||||
|
||||
@@ -99,6 +100,10 @@ func NewLayeredProfile(localProfile *Profile) *LayeredProfile {
|
||||
CfgOptionFilterSubDomainsKey,
|
||||
cfgOptionFilterSubDomains,
|
||||
)
|
||||
new.FilterCNAMEs = new.wrapSecurityLevelOption(
|
||||
CfgOptionFilterCNAMEKey,
|
||||
cfgOptionFilterCNAME,
|
||||
)
|
||||
new.PreventBypassing = new.wrapSecurityLevelOption(
|
||||
CfgOptionPreventBypassingKey,
|
||||
cfgOptionPreventBypassing,
|
||||
@@ -236,6 +241,7 @@ func (lp *LayeredProfile) MatchServiceEndpoint(entity *intel.Entity) (result end
|
||||
// lists.
|
||||
func (lp *LayeredProfile) MatchFilterLists(entity *intel.Entity) (endpoints.EPResult, string) {
|
||||
entity.ResolveSubDomainLists(lp.FilterSubDomains())
|
||||
entity.EnableCNAMECheck(lp.FilterCNAMEs())
|
||||
|
||||
lookupMap, hasLists := entity.GetListsMap()
|
||||
if !hasLists {
|
||||
|
||||
Reference in New Issue
Block a user