condition.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. package router
  2. import (
  3. "strings"
  4. "go.starlark.net/starlark"
  5. "go.starlark.net/syntax"
  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. func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
  41. matcherType, f := matcherTypeMap[domain.Type]
  42. if !f {
  43. return nil, newError("unsupported domain type", domain.Type)
  44. }
  45. matcher, err := matcherType.New(domain.Value)
  46. if err != nil {
  47. return nil, newError("failed to create domain matcher").Base(err)
  48. }
  49. return matcher, nil
  50. }
  51. type DomainMatcher struct {
  52. matchers strmatcher.IndexMatcher
  53. }
  54. func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
  55. g := new(strmatcher.MatcherGroup)
  56. for _, d := range domains {
  57. m, err := domainToMatcher(d)
  58. if err != nil {
  59. return nil, err
  60. }
  61. g.Add(m)
  62. }
  63. return &DomainMatcher{
  64. matchers: g,
  65. }, nil
  66. }
  67. func (m *DomainMatcher) ApplyDomain(domain string) bool {
  68. return len(m.matchers.Match(domain)) > 0
  69. }
  70. // Apply implements Condition.
  71. func (m *DomainMatcher) Apply(ctx routing.Context) bool {
  72. domain := ctx.GetTargetDomain()
  73. if len(domain) == 0 {
  74. return false
  75. }
  76. return m.ApplyDomain(strings.ToLower(domain))
  77. }
  78. type MultiGeoIPMatcher struct {
  79. matchers []*GeoIPMatcher
  80. onSource bool
  81. }
  82. func NewMultiGeoIPMatcher(geoips []*GeoIP, onSource bool) (*MultiGeoIPMatcher, error) {
  83. var matchers []*GeoIPMatcher
  84. for _, geoip := range geoips {
  85. matcher, err := globalGeoIPContainer.Add(geoip)
  86. if err != nil {
  87. return nil, err
  88. }
  89. matchers = append(matchers, matcher)
  90. }
  91. matcher := &MultiGeoIPMatcher{
  92. matchers: matchers,
  93. onSource: onSource,
  94. }
  95. return matcher, nil
  96. }
  97. // Apply implements Condition.
  98. func (m *MultiGeoIPMatcher) Apply(ctx routing.Context) bool {
  99. var ips []net.IP
  100. if m.onSource {
  101. ips = ctx.GetSourceIPs()
  102. } else {
  103. ips = ctx.GetTargetIPs()
  104. }
  105. for _, ip := range ips {
  106. for _, matcher := range m.matchers {
  107. if matcher.Match(ip) {
  108. return true
  109. }
  110. }
  111. }
  112. return false
  113. }
  114. type PortMatcher struct {
  115. port net.MemoryPortList
  116. onSource bool
  117. }
  118. // NewPortMatcher create a new port matcher that can match source or destination port
  119. func NewPortMatcher(list *net.PortList, onSource bool) *PortMatcher {
  120. return &PortMatcher{
  121. port: net.PortListFromProto(list),
  122. onSource: onSource,
  123. }
  124. }
  125. // Apply implements Condition.
  126. func (v *PortMatcher) Apply(ctx routing.Context) bool {
  127. if v.onSource {
  128. return v.port.Contains(ctx.GetSourcePort())
  129. } else {
  130. return v.port.Contains(ctx.GetTargetPort())
  131. }
  132. }
  133. type NetworkMatcher struct {
  134. list [8]bool
  135. }
  136. func NewNetworkMatcher(network []net.Network) NetworkMatcher {
  137. var matcher NetworkMatcher
  138. for _, n := range network {
  139. matcher.list[int(n)] = true
  140. }
  141. return matcher
  142. }
  143. // Apply implements Condition.
  144. func (v NetworkMatcher) Apply(ctx routing.Context) bool {
  145. return v.list[int(ctx.GetNetwork())]
  146. }
  147. type UserMatcher struct {
  148. user []string
  149. }
  150. func NewUserMatcher(users []string) *UserMatcher {
  151. usersCopy := make([]string, 0, len(users))
  152. for _, user := range users {
  153. if len(user) > 0 {
  154. usersCopy = append(usersCopy, user)
  155. }
  156. }
  157. return &UserMatcher{
  158. user: usersCopy,
  159. }
  160. }
  161. // Apply implements Condition.
  162. func (v *UserMatcher) Apply(ctx routing.Context) bool {
  163. user := ctx.GetUser()
  164. if len(user) == 0 {
  165. return false
  166. }
  167. for _, u := range v.user {
  168. if u == user {
  169. return true
  170. }
  171. }
  172. return false
  173. }
  174. type InboundTagMatcher struct {
  175. tags []string
  176. }
  177. func NewInboundTagMatcher(tags []string) *InboundTagMatcher {
  178. tagsCopy := make([]string, 0, len(tags))
  179. for _, tag := range tags {
  180. if len(tag) > 0 {
  181. tagsCopy = append(tagsCopy, tag)
  182. }
  183. }
  184. return &InboundTagMatcher{
  185. tags: tagsCopy,
  186. }
  187. }
  188. // Apply implements Condition.
  189. func (v *InboundTagMatcher) Apply(ctx routing.Context) bool {
  190. tag := ctx.GetInboundTag()
  191. if len(tag) == 0 {
  192. return false
  193. }
  194. for _, t := range v.tags {
  195. if t == tag {
  196. return true
  197. }
  198. }
  199. return false
  200. }
  201. type ProtocolMatcher struct {
  202. protocols []string
  203. }
  204. func NewProtocolMatcher(protocols []string) *ProtocolMatcher {
  205. pCopy := make([]string, 0, len(protocols))
  206. for _, p := range protocols {
  207. if len(p) > 0 {
  208. pCopy = append(pCopy, p)
  209. }
  210. }
  211. return &ProtocolMatcher{
  212. protocols: pCopy,
  213. }
  214. }
  215. // Apply implements Condition.
  216. func (m *ProtocolMatcher) Apply(ctx routing.Context) bool {
  217. protocol := ctx.GetProtocol()
  218. if len(protocol) == 0 {
  219. return false
  220. }
  221. for _, p := range m.protocols {
  222. if strings.HasPrefix(protocol, p) {
  223. return true
  224. }
  225. }
  226. return false
  227. }
  228. type AttributeMatcher struct {
  229. program *starlark.Program
  230. }
  231. func NewAttributeMatcher(code string) (*AttributeMatcher, error) {
  232. starFile, err := syntax.Parse("attr.star", "satisfied=("+code+")", 0)
  233. if err != nil {
  234. return nil, newError("attr rule").Base(err)
  235. }
  236. p, err := starlark.FileProgram(starFile, func(name string) bool {
  237. return name == "attrs"
  238. })
  239. if err != nil {
  240. return nil, err
  241. }
  242. return &AttributeMatcher{
  243. program: p,
  244. }, nil
  245. }
  246. // Match implements attributes matching.
  247. func (m *AttributeMatcher) Match(attrs map[string]string) bool {
  248. attrsDict := new(starlark.Dict)
  249. for key, value := range attrs {
  250. attrsDict.SetKey(starlark.String(key), starlark.String(value))
  251. }
  252. predefined := make(starlark.StringDict)
  253. predefined["attrs"] = attrsDict
  254. thread := &starlark.Thread{
  255. Name: "matcher",
  256. }
  257. results, err := m.program.Init(thread, predefined)
  258. if err != nil {
  259. newError("attr matcher").Base(err).WriteToLog()
  260. }
  261. satisfied := results["satisfied"]
  262. return satisfied != nil && bool(satisfied.Truth())
  263. }
  264. // Apply implements Condition.
  265. func (m *AttributeMatcher) Apply(ctx routing.Context) bool {
  266. attributes := ctx.GetAttributes()
  267. if attributes == nil {
  268. return false
  269. }
  270. return m.Match(attributes)
  271. }