This repository has been archived by the owner on Mar 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 106
/
route.go
252 lines (201 loc) · 5.89 KB
/
route.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
package netLayer
import (
"math/rand"
"net/netip"
"regexp"
"strings"
"github.com/yl2chen/cidranger"
)
//用于 HasFullOrSubDomain函数
type DomainHaser interface {
HasDomain(string) bool
}
type MapDomainHaser map[string]bool
func (mdh MapDomainHaser) HasDomain(d string) bool {
_, found := mdh[d]
return found
}
//会以点号分裂domain判断每一个子域名是否被包含,最终会试图匹配整个字符串.
func HasFullOrSubDomain(domain string, ds DomainHaser) bool {
lastDotIndex := len(domain)
var suffix string
for {
lastDotIndex = strings.LastIndex(domain[:lastDotIndex], ".")
suffix = domain[lastDotIndex+1:]
if ds.HasDomain(suffix) {
return true
}
if lastDotIndex == -1 {
return false
}
}
}
// TargetDescription 可以完整地描述一个网络层/传输层上的一个特定目标,
// 一般来说,一个具体的监听配置就会分配一个tag
type TargetDescription struct {
Addr Addr
Tag string
}
// Set 是 “集合” 的意思, 是一组相同类型的数据放到一起。
// 这里的相同点,就是它们同属于 将发往一个方向, 即同属一个路由策略
// 任意一个参数匹配后,都将发往相同的方向,由该方向OutTag 指定
// RouteSet 只负责把一些属性相同的 “网络层/传输层 特征” 放到一起
type RouteSet struct {
//网络层
NetRanger cidranger.Ranger //一个范围
IPs map[netip.Addr]bool //一个确定值
//Match 匹配任意字符串
//Domains匹配子域名,当此域名是目标域名或其子域名时,该规则生效
//Full只匹配完整域名
Domains, Full, InTags, Countries map[string]bool // Countries 使用 ISO 3166 字符串 作为key
//Regex是正则匹配域名
Regex []*regexp.Regexp
Match, Geosites []string
//传输层
AllowedTransportLayerProtocols uint16
OutTag string //目标
OutTags []string //目标列表
}
func NewRouteSetForMyCountry(iso string) *RouteSet {
if len(iso) != 2 {
return nil
}
rs := &RouteSet{
Countries: make(map[string]bool),
Domains: make(map[string]bool),
OutTag: "direct",
AllowedTransportLayerProtocols: TCP | UDP, //默认即支持tcp和udp
}
rs.Countries[strings.ToUpper(iso)] = true
rs.Domains[strings.ToLower(iso)] = true //iso字符串的小写正好可以作为顶级域名
return rs
}
func NewFullRouteSet() *RouteSet {
return &RouteSet{
NetRanger: cidranger.NewPCTrieRanger(),
IPs: make(map[netip.Addr]bool),
Match: make([]string, 0),
Domains: make(map[string]bool),
Full: make(map[string]bool),
Geosites: make([]string, 0),
InTags: make(map[string]bool),
Countries: make(map[string]bool),
AllowedTransportLayerProtocols: TCP | UDP, //默认即支持tcp和udp
}
}
func (sg *RouteSet) IsIn(td *TargetDescription) bool {
if td.Tag != "" && sg.InTags != nil {
if _, found := sg.InTags[td.Tag]; found {
return true
}
}
return sg.IsAddrIn(td.Addr)
}
func (sg *RouteSet) IsTransportProtocolAllowed(p uint16) bool {
return sg.AllowedTransportLayerProtocols&p > 0
}
func (sg *RouteSet) IsAddrNetworkAllowed(a Addr) bool {
if a.Network == "" {
return sg.IsTransportProtocolAllowed(TCP)
}
p := StrToTransportProtocol(a.Network)
return sg.IsTransportProtocolAllowed(p)
}
func (sg *RouteSet) IsUDPAllowed() bool {
return sg.IsTransportProtocolAllowed(UDP)
}
func (sg *RouteSet) IsTCPAllowed() bool {
return sg.IsTransportProtocolAllowed(TCP)
}
func (sg *RouteSet) IsAddrIn(a Addr) bool {
//我们先过滤传输层,再过滤网络层
if !sg.IsAddrNetworkAllowed(a) {
return false
} else if sg.NetRanger == nil && sg.IPs == nil && sg.Domains == nil && sg.Countries == nil {
//如果仅限制了一个传输层协议,且本集合里没有任何其它内容,那就直接通过
return true
}
//开始网络层判断
if len(a.IP) > 0 {
if sg.NetRanger != nil {
if has, _ := sg.NetRanger.Contains(a.IP); has {
return true
}
}
if sg.Countries != nil {
if isoStr := GetIP_ISO(a.IP); isoStr != "" {
if _, found := sg.Countries[isoStr]; found {
return true
}
}
}
if sg.IPs != nil {
if _, found := sg.IPs[a.GetNetIPAddr()]; found {
return true
}
}
}
if a.Name != "" {
if len(sg.Full) > 0 {
if _, found := sg.Full[a.Name]; found {
return true
}
}
if len(sg.Domains) > 0 {
return HasFullOrSubDomain(a.Name, MapDomainHaser(sg.Domains))
}
if len(sg.Match) > 0 {
for _, m := range sg.Match {
if strings.Contains(a.Name, m) {
return true
}
}
}
if len(sg.Regex) > 0 {
for _, reg := range sg.Regex {
if reg.MatchString(a.Name) {
return true
}
}
}
if len(sg.Geosites) > 0 && len(GeositeListMap) > 0 {
for _, g := range sg.Geosites {
if IsDomainInsideGeosite(g, a.Name) {
return true
}
}
}
}
return false
}
//一个完整的 所有RouteSet的列表,进行路由时,直接遍历即可
// 所谓的路由实际上就是分流。
type RoutePolicy struct {
List []*RouteSet
}
func NewRoutePolicy() *RoutePolicy {
return &RoutePolicy{
List: make([]*RouteSet, 0, 2),
}
}
func (rp *RoutePolicy) AddRouteSet(rs *RouteSet) {
rp.List = append(rp.List, rs)
}
// 返回一个 proxy.Client 的 tag
// 默认情况下,始终具有direct这个tag以及 proxy这个tag,无需用户额外在配置文件中指定
// 默认如果不匹配任何值的话,就会流向 "proxy" tag,也就是客户设置的 remoteClient的值
func (rp *RoutePolicy) GetOutTag(td *TargetDescription) string {
for _, s := range rp.List {
if s.IsIn(td) {
switch n := len(s.OutTags); n {
case 0:
return s.OutTag
case 1:
return s.OutTags[0]
default:
return s.OutTags[rand.Intn(n)]
}
}
}
return "proxy"
}