condition.go 6.4 KB

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