-
Notifications
You must be signed in to change notification settings - Fork 0
/
router.go
168 lines (143 loc) · 4.45 KB
/
router.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package router
//go:generate go run github.com/bmclab-git/v2ray-core/v5/common/errors/errorgen
import (
"context"
"encoding/json"
"strings"
"github.com/golang/protobuf/proto"
"github.com/bmclab-git/v2ray-core/v5/app/router"
"github.com/bmclab-git/v2ray-core/v5/common/platform"
"github.com/bmclab-git/v2ray-core/v5/common/serial"
"github.com/bmclab-git/v2ray-core/v5/infra/conf/cfgcommon"
"github.com/bmclab-git/v2ray-core/v5/infra/conf/geodata"
rule2 "github.com/bmclab-git/v2ray-core/v5/infra/conf/rule"
)
type RouterRulesConfig struct { // nolint: revive
RuleList []json.RawMessage `json:"rules"`
DomainStrategy string `json:"domainStrategy"`
}
// StrategyConfig represents a strategy config
type StrategyConfig struct {
Type string `json:"type"`
Settings *json.RawMessage `json:"settings"`
}
type BalancingRule struct {
Tag string `json:"tag"`
Selectors cfgcommon.StringList `json:"selector"`
Strategy StrategyConfig `json:"strategy"`
FallbackTag string `json:"fallbackTag"`
}
// Build builds the balancing rule
func (r *BalancingRule) Build() (*router.BalancingRule, error) {
if r.Tag == "" {
return nil, newError("empty balancer tag")
}
if len(r.Selectors) == 0 {
return nil, newError("empty selector list")
}
var strategy string
switch strings.ToLower(r.Strategy.Type) {
case strategyRandom, "":
r.Strategy.Type = strategyRandom
strategy = strategyRandom
case strategyLeastLoad:
strategy = strategyLeastLoad
case strategyLeastPing:
strategy = "leastping"
default:
return nil, newError("unknown balancing strategy: " + r.Strategy.Type)
}
settings := []byte("{}")
if r.Strategy.Settings != nil {
settings = ([]byte)(*r.Strategy.Settings)
}
rawConfig, err := strategyConfigLoader.LoadWithID(settings, r.Strategy.Type)
if err != nil {
return nil, newError("failed to parse to strategy config.").Base(err)
}
var ts proto.Message
if builder, ok := rawConfig.(cfgcommon.Buildable); ok {
ts, err = builder.Build()
if err != nil {
return nil, err
}
}
return &router.BalancingRule{
Strategy: strategy,
StrategySettings: serial.ToTypedMessage(ts),
FallbackTag: r.FallbackTag,
OutboundSelector: r.Selectors,
Tag: r.Tag,
}, nil
}
type RouterConfig struct { // nolint: revive
Settings *RouterRulesConfig `json:"settings"` // Deprecated
RuleList []json.RawMessage `json:"rules"`
DomainStrategy *string `json:"domainStrategy"`
Balancers []*BalancingRule `json:"balancers"`
DomainMatcher string `json:"domainMatcher"`
cfgctx context.Context
}
func (c *RouterConfig) getDomainStrategy() router.DomainStrategy {
ds := ""
if c.DomainStrategy != nil {
ds = *c.DomainStrategy
} else if c.Settings != nil {
ds = c.Settings.DomainStrategy
}
switch strings.ToLower(ds) {
case "alwaysip", "always_ip", "always-ip":
return router.DomainStrategy_UseIp
case "ipifnonmatch", "ip_if_non_match", "ip-if-non-match":
return router.DomainStrategy_IpIfNonMatch
case "ipondemand", "ip_on_demand", "ip-on-demand":
return router.DomainStrategy_IpOnDemand
default:
return router.DomainStrategy_AsIs
}
}
func (c *RouterConfig) BuildV5(ctx context.Context) (*router.Config, error) {
c.cfgctx = ctx
return c.Build()
}
func (c *RouterConfig) Build() (*router.Config, error) {
config := new(router.Config)
config.DomainStrategy = c.getDomainStrategy()
if c.cfgctx == nil {
c.cfgctx = cfgcommon.NewConfigureLoadingContext(context.Background())
geoloadername := platform.NewEnvFlag("v2ray.conf.geoloader").GetValue(func() string {
return "standard"
})
if loader, err := geodata.GetGeoDataLoader(geoloadername); err == nil {
cfgcommon.SetGeoDataLoader(c.cfgctx, loader)
} else {
return nil, newError("unable to create geo data loader ").Base(err)
}
}
var rawRuleList []json.RawMessage
if c != nil {
rawRuleList = c.RuleList
if c.Settings != nil {
c.RuleList = append(c.RuleList, c.Settings.RuleList...)
rawRuleList = c.RuleList
}
}
for _, rawRule := range rawRuleList {
rule, err := rule2.ParseRule(c.cfgctx, rawRule)
if err != nil {
return nil, err
}
if rule.DomainMatcher == "" {
rule.DomainMatcher = c.DomainMatcher
}
config.Rule = append(config.Rule, rule)
}
for _, rawBalancer := range c.Balancers {
balancer, err := rawBalancer.Build()
if err != nil {
return nil, err
}
config.BalancingRule = append(config.BalancingRule, balancer)
}
return config, nil
}