mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00:00
Implement MatchingEngine in internal/rulematcher package to enable configurable DNS policy rule evaluation order and behavior. New components: - MatchingConfig: Configuration for rule order and stop behavior - MatchingEngine: Orchestrates rule matching with configurable order - MatchingResult: Standardized result structure - DefaultMatchingConfig(): Maintains backward compatibility Key features: - Configurable rule evaluation order (e.g., domain-first, MAC-first) - StopOnFirstMatch configuration option - Graceful handling of invalid rule types - Comprehensive test coverage for all scenarios The engine supports custom matching strategies while preserving the default Networks → Macs → Domains order for backward compatibility. This enables future configuration-driven rule matching without breaking existing functionality.
119 lines
3.2 KiB
Go
119 lines
3.2 KiB
Go
package rulematcher
|
|
|
|
import (
|
|
"context"
|
|
)
|
|
|
|
// MatchingEngine orchestrates rule matching based on configurable order
|
|
type MatchingEngine struct {
|
|
config *MatchingConfig
|
|
matchers map[RuleType]RuleMatcher
|
|
}
|
|
|
|
// NewMatchingEngine creates a new matching engine with the given configuration
|
|
func NewMatchingEngine(config *MatchingConfig) *MatchingEngine {
|
|
if config == nil {
|
|
config = DefaultMatchingConfig()
|
|
}
|
|
|
|
engine := &MatchingEngine{
|
|
config: config,
|
|
matchers: map[RuleType]RuleMatcher{
|
|
RuleTypeNetwork: &NetworkRuleMatcher{},
|
|
RuleTypeMac: &MacRuleMatcher{},
|
|
RuleTypeDomain: &DomainRuleMatcher{},
|
|
},
|
|
}
|
|
|
|
return engine
|
|
}
|
|
|
|
// FindUpstreams determines which upstreams should handle a request based on policy rules
|
|
// It evaluates rules in the configured order and returns the first match (if StopOnFirstMatch is true)
|
|
// or all matches (if StopOnFirstMatch is false)
|
|
func (e *MatchingEngine) FindUpstreams(ctx context.Context, req *MatchRequest) *MatchingResult {
|
|
result := &MatchingResult{
|
|
Upstreams: []string{},
|
|
MatchedPolicy: "no policy",
|
|
MatchedNetwork: "no network",
|
|
MatchedRule: "no rule",
|
|
Matched: false,
|
|
SrcAddr: req.SourceIP.String(),
|
|
MatchedRuleType: "",
|
|
MatchingOrder: e.config.Order,
|
|
}
|
|
|
|
if req.Policy == nil {
|
|
return result
|
|
}
|
|
|
|
result.MatchedPolicy = req.Policy.Name
|
|
|
|
var allMatches []*MatchResult
|
|
|
|
// Evaluate rules in the configured order
|
|
for _, ruleType := range e.config.Order {
|
|
matcher, exists := e.matchers[ruleType]
|
|
if !exists {
|
|
continue
|
|
}
|
|
|
|
matchResult := matcher.Match(ctx, req)
|
|
if matchResult.Matched {
|
|
allMatches = append(allMatches, matchResult)
|
|
|
|
// If we should stop on first match, return immediately
|
|
if e.config.StopOnFirstMatch {
|
|
result.Upstreams = matchResult.Targets
|
|
result.Matched = true
|
|
result.MatchedRuleType = string(matchResult.RuleType)
|
|
|
|
// Set the appropriate matched field based on rule type
|
|
switch matchResult.RuleType {
|
|
case RuleTypeNetwork:
|
|
result.MatchedNetwork = matchResult.MatchedRule
|
|
case RuleTypeMac:
|
|
result.MatchedNetwork = matchResult.MatchedRule
|
|
case RuleTypeDomain:
|
|
result.MatchedRule = matchResult.MatchedRule
|
|
}
|
|
|
|
return result
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we get here, either no matches were found or StopOnFirstMatch is false
|
|
if len(allMatches) > 0 {
|
|
// For now, we'll use the first match's targets
|
|
// In the future, we could implement more sophisticated target merging
|
|
result.Upstreams = allMatches[0].Targets
|
|
result.Matched = true
|
|
result.MatchedRuleType = string(allMatches[0].RuleType)
|
|
|
|
// Set the appropriate matched field based on rule type
|
|
switch allMatches[0].RuleType {
|
|
case RuleTypeNetwork:
|
|
result.MatchedNetwork = allMatches[0].MatchedRule
|
|
case RuleTypeMac:
|
|
result.MatchedNetwork = allMatches[0].MatchedRule
|
|
case RuleTypeDomain:
|
|
result.MatchedRule = allMatches[0].MatchedRule
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// MatchingResult represents the result of the matching engine
|
|
type MatchingResult struct {
|
|
Upstreams []string
|
|
MatchedPolicy string
|
|
MatchedNetwork string
|
|
MatchedRule string
|
|
Matched bool
|
|
SrcAddr string
|
|
MatchedRuleType string
|
|
MatchingOrder []RuleType
|
|
}
|