Files
ctrld/internal/rulematcher/engine.go
Cuong Manh Le d42a78cba9 docs: add comprehensive package documentation for rulematcher
- Add detailed package documentation to engine.go explaining the rule matching
  system, supported rule types (Network, MAC, Domain), and priority ordering
- Include usage example demonstrating typical API usage patterns
- Remove unused Type() method from RuleMatcher interface and implementations
- Maintain backward compatibility while improving code documentation

The documentation explains the policy-based DNS routing system and how different
rule types interact with configurable priority ordering.
2025-10-09 19:12:06 +07:00

149 lines
4.4 KiB
Go

// Package rulematcher provides a flexible rule matching engine for DNS request routing.
//
// The rulematcher package implements a policy-based DNS routing system that allows
// configuring different types of rules to determine which upstream DNS servers should
// handle specific requests. It supports three types of rules:
//
// - Network rules: Match requests based on source IP address ranges
// - MAC rules: Match requests based on source MAC addresses
// - Domain rules: Match requests based on requested domain names
//
// The matching engine uses a configurable priority order to determine which rules
// take precedence when multiple rules match. By default, the priority order is:
// Network -> MAC -> Domain, with Domain rules having the highest priority and
// overriding all other matches.
//
// Example usage:
//
// config := &MatchingConfig{
// Order: []RuleType{RuleTypeNetwork, RuleTypeMac, RuleTypeDomain},
// }
// engine := NewMatchingEngine(config)
//
// request := &MatchRequest{
// SourceIP: net.ParseIP("192.168.1.100"),
// SourceMac: "aa:bb:cc:dd:ee:ff",
// Domain: "example.com",
// Policy: policyConfig,
// Config: appConfig,
// }
//
// result := engine.FindUpstreams(ctx, request)
// if result.Matched {
// // Use result.Upstreams to route the request
// }
//
// The package maintains backward compatibility with existing behavior while
// providing a clean, extensible interface for adding new rule types.
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 implements the original behavior where MAC and domain rules can override network rules
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 networkMatch *MatchResult
var macMatch *MatchResult
var domainMatch *MatchResult
// Check all rule types and store matches
for _, ruleType := range e.config.Order {
matcher, exists := e.matchers[ruleType]
if !exists {
continue
}
matchResult := matcher.Match(ctx, req)
if matchResult.Matched {
switch matchResult.RuleType {
case RuleTypeNetwork:
networkMatch = matchResult
case RuleTypeMac:
macMatch = matchResult
case RuleTypeDomain:
domainMatch = matchResult
}
}
}
// Determine the final match based on original logic:
// Domain rules override everything, MAC rules override network rules
if domainMatch != nil {
result.Upstreams = domainMatch.Targets
result.Matched = true
result.MatchedRuleType = string(domainMatch.RuleType)
result.MatchedRule = domainMatch.MatchedRule
// Special case: domain rules override network rules
if networkMatch != nil {
result.MatchedNetwork = networkMatch.MatchedRule + " (unenforced)"
}
} else if macMatch != nil {
result.Upstreams = macMatch.Targets
result.Matched = true
result.MatchedRuleType = string(macMatch.RuleType)
result.MatchedNetwork = macMatch.MatchedRule
} else if networkMatch != nil {
result.Upstreams = networkMatch.Targets
result.Matched = true
result.MatchedRuleType = string(networkMatch.RuleType)
result.MatchedNetwork = networkMatch.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
}