github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/app/router/condition.go (about) 1 // +build !confonly 2 3 package router 4 5 import ( 6 "strings" 7 8 "go.starlark.net/starlark" 9 "go.starlark.net/syntax" 10 11 "v2ray.com/core/common/net" 12 "v2ray.com/core/common/strmatcher" 13 "v2ray.com/core/features/routing" 14 ) 15 16 type Condition interface { 17 Apply(ctx routing.Context) bool 18 } 19 20 type ConditionChan []Condition 21 22 func NewConditionChan() *ConditionChan { 23 var condChan ConditionChan = make([]Condition, 0, 8) 24 return &condChan 25 } 26 27 func (v *ConditionChan) Add(cond Condition) *ConditionChan { 28 *v = append(*v, cond) 29 return v 30 } 31 32 // Apply applies all conditions registered in this chan. 33 func (v *ConditionChan) Apply(ctx routing.Context) bool { 34 for _, cond := range *v { 35 if !cond.Apply(ctx) { 36 return false 37 } 38 } 39 return true 40 } 41 42 func (v *ConditionChan) Len() int { 43 return len(*v) 44 } 45 46 var matcherTypeMap = map[Domain_Type]strmatcher.Type{ 47 Domain_Plain: strmatcher.Substr, 48 Domain_Regex: strmatcher.Regex, 49 Domain_Domain: strmatcher.Domain, 50 Domain_Full: strmatcher.Full, 51 } 52 53 func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) { 54 matcherType, f := matcherTypeMap[domain.Type] 55 if !f { 56 return nil, newError("unsupported domain type", domain.Type) 57 } 58 59 matcher, err := matcherType.New(domain.Value) 60 if err != nil { 61 return nil, newError("failed to create domain matcher").Base(err) 62 } 63 64 return matcher, nil 65 } 66 67 type DomainMatcher struct { 68 matchers strmatcher.IndexMatcher 69 } 70 71 func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) { 72 g := new(strmatcher.MatcherGroup) 73 for _, d := range domains { 74 m, err := domainToMatcher(d) 75 if err != nil { 76 return nil, err 77 } 78 g.Add(m) 79 } 80 81 return &DomainMatcher{ 82 matchers: g, 83 }, nil 84 } 85 86 func (m *DomainMatcher) ApplyDomain(domain string) bool { 87 return len(m.matchers.Match(domain)) > 0 88 } 89 90 // Apply implements Condition. 91 func (m *DomainMatcher) Apply(ctx routing.Context) bool { 92 domain := ctx.GetTargetDomain() 93 if len(domain) == 0 { 94 return false 95 } 96 return m.ApplyDomain(domain) 97 } 98 99 type MultiGeoIPMatcher struct { 100 matchers []*GeoIPMatcher 101 onSource bool 102 } 103 104 func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) { 105 var matchers []*GeoIPMatcher 106 for _, geoip := range geoips { 107 matcher, err := globalGeoIPContainer.Add(geoip) 108 if err != nil { 109 return nil, err 110 } 111 matchers = append(matchers, matcher) 112 } 113 114 matcher := &MultiGeoIPMatcher{ 115 matchers: matchers, 116 onSource: onSource, 117 } 118 119 return matcher, nil 120 } 121 122 // Apply implements Condition. 123 func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool { 124 var ips []net.IP 125 if m.onSource { 126 ips = ctx.GetSourceIPs() 127 } else { 128 ips = ctx.GetTargetIPs() 129 } 130 for _, ip := range ips { 131 for _, matcher := range m.matchers { 132 if matcher.Match(ip) { 133 return true 134 } 135 } 136 } 137 return false 138 } 139 140 type PortMatcher struct { 141 port net.MemoryPortList 142 onSource bool 143 } 144 145 // NewPortMatcher create a new port matcher that can match source or destination port 146 func NewPortMatcher(list *net.PortList, onSource bool) *PortMatcher { 147 return &PortMatcher{ 148 port: net.PortListFromProto(list), 149 onSource: onSource, 150 } 151 } 152 153 // Apply implements Condition. 154 func (v *PortMatcher) Apply(ctx routing.Context) bool { 155 if v.onSource { 156 return v.port.Contains(ctx.GetSourcePort()) 157 } else { 158 return v.port.Contains(ctx.GetTargetPort()) 159 } 160 } 161 162 type NetworkMatcher struct { 163 list [8]bool 164 } 165 166 func NewNetworkMatcher(network []net.Network) NetworkMatcher { 167 var matcher NetworkMatcher 168 for _, n := range network { 169 matcher.list[int(n)] = true 170 } 171 return matcher 172 } 173 174 // Apply implements Condition. 175 func (v NetworkMatcher) Apply(ctx routing.Context) bool { 176 return v.list[int(ctx.GetNetwork())] 177 } 178 179 type UserMatcher struct { 180 user []string 181 } 182 183 func NewUserMatcher(users []string) *UserMatcher { 184 usersCopy := make([]string, 0, len(users)) 185 for _, user := range users { 186 if len(user) > 0 { 187 usersCopy = append(usersCopy, user) 188 } 189 } 190 return &UserMatcher{ 191 user: usersCopy, 192 } 193 } 194 195 // Apply implements Condition. 196 func (v *UserMatcher) Apply(ctx routing.Context) bool { 197 user := ctx.GetUser() 198 if len(user) == 0 { 199 return false 200 } 201 for _, u := range v.user { 202 if u == user { 203 return true 204 } 205 } 206 return false 207 } 208 209 type InboundTagMatcher struct { 210 tags []string 211 } 212 213 func NewInboundTagMatcher(tags []string) *InboundTagMatcher { 214 tagsCopy := make([]string, 0, len(tags)) 215 for _, tag := range tags { 216 if len(tag) > 0 { 217 tagsCopy = append(tagsCopy, tag) 218 } 219 } 220 return &InboundTagMatcher{ 221 tags: tagsCopy, 222 } 223 } 224 225 // Apply implements Condition. 226 func (v *InboundTagMatcher) Apply(ctx routing.Context) bool { 227 tag := ctx.GetInboundTag() 228 if len(tag) == 0 { 229 return false 230 } 231 for _, t := range v.tags { 232 if t == tag { 233 return true 234 } 235 } 236 return false 237 } 238 239 type ProtocolMatcher struct { 240 protocols []string 241 } 242 243 func NewProtocolMatcher(protocols []string) *ProtocolMatcher { 244 pCopy := make([]string, 0, len(protocols)) 245 246 for _, p := range protocols { 247 if len(p) > 0 { 248 pCopy = append(pCopy, p) 249 } 250 } 251 252 return &ProtocolMatcher{ 253 protocols: pCopy, 254 } 255 } 256 257 // Apply implements Condition. 258 func (m *ProtocolMatcher) Apply(ctx routing.Context) bool { 259 protocol := ctx.GetProtocol() 260 if len(protocol) == 0 { 261 return false 262 } 263 for _, p := range m.protocols { 264 if strings.HasPrefix(protocol, p) { 265 return true 266 } 267 } 268 return false 269 } 270 271 type AttributeMatcher struct { 272 program *starlark.Program 273 } 274 275 func NewAttributeMatcher(code string) (*AttributeMatcher, error) { 276 starFile, err := syntax.Parse("attr.star", "satisfied=("+code+")", 0) 277 if err != nil { 278 return nil, newError("attr rule").Base(err) 279 } 280 p, err := starlark.FileProgram(starFile, func(name string) bool { 281 return name == "attrs" 282 }) 283 if err != nil { 284 return nil, err 285 } 286 return &AttributeMatcher{ 287 program: p, 288 }, nil 289 } 290 291 // Match implements attributes matching. 292 func (m *AttributeMatcher) Match(attrs map[string]string) bool { 293 attrsDict := new(starlark.Dict) 294 for key, value := range attrs { 295 attrsDict.SetKey(starlark.String(key), starlark.String(value)) 296 } 297 298 predefined := make(starlark.StringDict) 299 predefined["attrs"] = attrsDict 300 301 thread := &starlark.Thread{ 302 Name: "matcher", 303 } 304 results, err := m.program.Init(thread, predefined) 305 if err != nil { 306 newError("attr matcher").Base(err).WriteToLog() 307 } 308 satisfied := results["satisfied"] 309 return satisfied != nil && bool(satisfied.Truth()) 310 } 311 312 // Apply implements Condition. 313 func (m *AttributeMatcher) Apply(ctx routing.Context) bool { 314 attributes := ctx.GetAttributes() 315 if attributes == nil { 316 return false 317 } 318 return m.Match(attributes) 319 }