condition.go 6.9 KB

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