V2bX/common/rule/rule.go
2022-06-02 01:35:41 +08:00

83 lines
2.2 KiB
Go

// Package rule is to control the audit rule behaviors
package rule
import (
"fmt"
"reflect"
"strconv"
"strings"
"sync"
"github.com/Yuzuki616/V2bX/api"
mapset "github.com/deckarep/golang-set"
)
type RuleManager struct {
InboundRule *sync.Map // Key: Tag, Value: []api.DetectRule
InboundDetectResult *sync.Map // key: Tag, Value: mapset.NewSet []api.DetectResult
}
func New() *RuleManager {
return &RuleManager{
InboundRule: new(sync.Map),
InboundDetectResult: new(sync.Map),
}
}
func (r *RuleManager) UpdateRule(tag string, newRuleList []api.DetectRule) error {
if value, ok := r.InboundRule.LoadOrStore(tag, newRuleList); ok {
oldRuleList := value.([]api.DetectRule)
if !reflect.DeepEqual(oldRuleList, newRuleList) {
r.InboundRule.Store(tag, newRuleList)
}
}
return nil
}
func (r *RuleManager) GetDetectResult(tag string) (*[]api.DetectResult, error) {
detectResult := make([]api.DetectResult, 0)
if value, ok := r.InboundDetectResult.LoadAndDelete(tag); ok {
resultSet := value.(mapset.Set)
it := resultSet.Iterator()
for result := range it.C {
detectResult = append(detectResult, result.(api.DetectResult))
}
}
return &detectResult, nil
}
func (r *RuleManager) Detect(tag string, destination string, email string) (reject bool) {
reject = false
var hitRuleID int = -1
// If we have some rule for this inbound
if value, ok := r.InboundRule.Load(tag); ok {
ruleList := value.([]api.DetectRule)
for _, r := range ruleList {
if r.Pattern.Match([]byte(destination)) {
hitRuleID = r.ID
reject = true
break
}
}
// If we hit some rule
if reject && hitRuleID != -1 {
l := strings.Split(email, "|")
uid, err := strconv.Atoi(l[len(l)-1])
if err != nil {
newError(fmt.Sprintf("Record illegal behavior failed! Cannot find user's uid: %s", email)).AtDebug().WriteToLog()
return reject
}
newSet := mapset.NewSetWith(api.DetectResult{UID: uid, RuleID: hitRuleID})
// If there are any hit history
if v, ok := r.InboundDetectResult.LoadOrStore(tag, newSet); ok {
resultSet := v.(mapset.Set)
// If this is a new record
if resultSet.Add(api.DetectResult{UID: uid, RuleID: hitRuleID}) {
r.InboundDetectResult.Store(tag, resultSet)
}
}
}
}
return reject
}