2022-06-01 13:35:41 -04:00
|
|
|
// 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"
|
|
|
|
)
|
|
|
|
|
2022-06-04 05:12:28 -04:00
|
|
|
type Rule struct {
|
2022-06-01 13:35:41 -04:00
|
|
|
InboundRule *sync.Map // Key: Tag, Value: []api.DetectRule
|
|
|
|
InboundDetectResult *sync.Map // key: Tag, Value: mapset.NewSet []api.DetectResult
|
|
|
|
}
|
|
|
|
|
2022-06-04 05:12:28 -04:00
|
|
|
func New() *Rule {
|
|
|
|
return &Rule{
|
2022-06-01 13:35:41 -04:00
|
|
|
InboundRule: new(sync.Map),
|
|
|
|
InboundDetectResult: new(sync.Map),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-04 05:12:28 -04:00
|
|
|
func (r *Rule) UpdateRule(tag string, newRuleList []api.DetectRule) error {
|
2022-06-01 13:35:41 -04:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-06-04 05:12:28 -04:00
|
|
|
func (r *Rule) GetDetectResult(tag string) (*[]api.DetectResult, error) {
|
2022-06-01 13:35:41 -04:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-06-04 05:12:28 -04:00
|
|
|
func (r *Rule) Detect(tag string, destination string, email string) (reject bool) {
|
2022-06-01 13:35:41 -04:00
|
|
|
reject = false
|
2022-06-04 05:12:28 -04:00
|
|
|
var hitRuleID = -1
|
2022-06-01 13:35:41 -04:00
|
|
|
// 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
|
|
|
|
}
|