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