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