-
Notifications
You must be signed in to change notification settings - Fork 158
/
matcher_builder.go
130 lines (117 loc) · 3.21 KB
/
matcher_builder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) 2022-2024, daeuniverse Organization <dae@v2raya.org>
*/
package routing
import (
"fmt"
"github.com/daeuniverse/dae/common/consts"
"github.com/daeuniverse/dae/pkg/config_parser"
"github.com/sirupsen/logrus"
"strconv"
)
type DomainSet struct {
Key consts.RoutingDomainKey
RuleIndex int
Domains []string
}
type Outbound struct {
Name string
Mark uint32
Must bool
}
type RulesBuilder struct {
log *logrus.Logger
parsers map[string]FunctionParser
}
func NewRulesBuilder(log *logrus.Logger) *RulesBuilder {
return &RulesBuilder{
log: log,
parsers: make(map[string]FunctionParser),
}
}
func (b *RulesBuilder) RegisterFunctionParser(funcName string, parser FunctionParser) {
b.parsers[funcName] = parser
}
func (b *RulesBuilder) Apply(rules []*config_parser.RoutingRule) (err error) {
for _, rule := range rules {
b.log.Debugln("[rule]", rule.String(true, false, false))
outbound, err := ParseOutbound(&rule.Outbound)
if err != nil {
return err
}
// rule is like: domain(domain:baidu.com) && port(443) -> proxy
for iFunc, f := range rule.AndFunctions {
// f is like: domain(domain:baidu.com)
functionParser, ok := b.parsers[f.Name]
if !ok {
return fmt.Errorf("unknown function: %v", f.Name)
}
paramValueGroups, keyOrder := groupParamValuesByKey(f.Params)
for jMatchSet, key := range keyOrder {
paramValueGroup := paramValueGroups[key]
// Preprocess the outbound.
overrideOutbound := &Outbound{
Name: consts.OutboundLogicalOr.String(),
Mark: outbound.Mark,
Must: outbound.Must,
}
if jMatchSet == len(keyOrder)-1 {
overrideOutbound.Name = consts.OutboundLogicalAnd.String()
if iFunc == len(rule.AndFunctions)-1 {
overrideOutbound.Name = outbound.Name
}
}
{
// Debug
symNot := ""
if f.Not {
symNot = "!"
}
b.log.Debugf("\t%v%v(%v) -> %v", symNot, f.Name, key, overrideOutbound.Name)
}
if err = functionParser(b.log, f, key, paramValueGroup, overrideOutbound); err != nil {
return fmt.Errorf("failed to parse '%v': %w", f.String(false, false, false), err)
}
}
}
}
return nil
}
func groupParamValuesByKey(params []*config_parser.Param) (keyToValues map[string][]string, keyOrder []string) {
groups := make(map[string][]string)
for _, param := range params {
if _, ok := groups[param.Key]; !ok {
keyOrder = append(keyOrder, param.Key)
}
groups[param.Key] = append(groups[param.Key], param.Val)
}
return groups, keyOrder
}
func ParseOutbound(rawOutbound *config_parser.Function) (outbound *Outbound, err error) {
outbound = &Outbound{
Name: rawOutbound.Name,
Mark: 0,
Must: false,
}
for _, p := range rawOutbound.Params {
switch p.Key {
case consts.OutboundParam_Mark:
var _mark uint64
_mark, err = strconv.ParseUint(p.Val, 0, 32)
if err != nil {
return nil, fmt.Errorf("failed to parse mark: %v", err)
}
outbound.Mark = uint32(_mark)
case "":
if p.Val == "must" {
outbound.Must = true
} else {
return nil, fmt.Errorf("unknown outbound param: %v", p.Val)
}
default:
return nil, fmt.Errorf("unknown outbound param key: %v", p.Key)
}
}
return outbound, nil
}