condition.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. package router
  2. import (
  3. "context"
  4. "io"
  5. "os"
  6. "path/filepath"
  7. "regexp"
  8. "slices"
  9. "strings"
  10. "github.com/xtls/xray-core/common/errors"
  11. "github.com/xtls/xray-core/common/net"
  12. "github.com/xtls/xray-core/common/strmatcher"
  13. "github.com/xtls/xray-core/features/routing"
  14. )
  15. type Condition interface {
  16. Apply(ctx routing.Context) bool
  17. }
  18. type ConditionChan []Condition
  19. func NewConditionChan() *ConditionChan {
  20. var condChan ConditionChan = make([]Condition, 0, 8)
  21. return &condChan
  22. }
  23. func (v *ConditionChan) Add(cond Condition) *ConditionChan {
  24. *v = append(*v, cond)
  25. return v
  26. }
  27. // Apply applies all conditions registered in this chan.
  28. func (v *ConditionChan) Apply(ctx routing.Context) bool {
  29. for _, cond := range *v {
  30. if !cond.Apply(ctx) {
  31. return false
  32. }
  33. }
  34. return true
  35. }
  36. func (v *ConditionChan) Len() int {
  37. return len(*v)
  38. }
  39. var matcherTypeMap = map[Domain_Type]strmatcher.Type{
  40. Domain_Plain: strmatcher.Substr,
  41. Domain_Regex: strmatcher.Regex,
  42. Domain_Domain: strmatcher.Domain,
  43. Domain_Full: strmatcher.Full,
  44. }
  45. type DomainMatcher struct {
  46. Matchers strmatcher.IndexMatcher
  47. }
  48. func SerializeDomainMatcher(domains []*Domain, w io.Writer) error {
  49. g := strmatcher.NewMphMatcherGroup()
  50. for _, d := range domains {
  51. matcherType, f := matcherTypeMap[d.Type]
  52. if !f {
  53. continue
  54. }
  55. _, err := g.AddPattern(d.Value, matcherType)
  56. if err != nil {
  57. return err
  58. }
  59. }
  60. g.Build()
  61. // serialize
  62. return g.Serialize(w)
  63. }
  64. func NewDomainMatcherFromBuffer(data []byte) (*strmatcher.MphMatcherGroup, error) {
  65. matcher, err := strmatcher.NewMphMatcherGroupFromBuffer(data)
  66. if err != nil {
  67. return nil, err
  68. }
  69. return matcher, nil
  70. }
  71. func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
  72. g := strmatcher.NewMphMatcherGroup()
  73. for i, d := range domains {
  74. domains[i] = nil
  75. matcherType, f := matcherTypeMap[d.Type]
  76. if !f {
  77. errors.LogError(context.Background(), "ignore unsupported domain type ", d.Type, " of rule ", d.Value)
  78. continue
  79. }
  80. _, err := g.AddPattern(d.Value, matcherType)
  81. if err != nil {
  82. errors.LogErrorInner(context.Background(), err, "ignore domain rule ", d.Type, " ", d.Value)
  83. continue
  84. }
  85. }
  86. g.Build()
  87. return &DomainMatcher{
  88. Matchers: g,
  89. }, nil
  90. }
  91. func (m *DomainMatcher) ApplyDomain(domain string) bool {
  92. return len(m.Matchers.Match(strings.ToLower(domain))) > 0
  93. }
  94. // Apply implements Condition.
  95. func (m *DomainMatcher) Apply(ctx routing.Context) bool {
  96. domain := ctx.GetTargetDomain()
  97. if len(domain) == 0 {
  98. return false
  99. }
  100. return m.ApplyDomain(domain)
  101. }
  102. type MatcherAsType byte
  103. const (
  104. MatcherAsType_Local MatcherAsType = iota
  105. MatcherAsType_Source
  106. MatcherAsType_Target
  107. MatcherAsType_VlessRoute // for port
  108. )
  109. type IPMatcher struct {
  110. matcher GeoIPMatcher
  111. asType MatcherAsType
  112. }
  113. func NewIPMatcher(geoips []*GeoIP, asType MatcherAsType) (*IPMatcher, error) {
  114. matcher, err := BuildOptimizedGeoIPMatcher(geoips...)
  115. if err != nil {
  116. return nil, err
  117. }
  118. return &IPMatcher{matcher: matcher, asType: asType}, nil
  119. }
  120. // Apply implements Condition.
  121. func (m *IPMatcher) Apply(ctx routing.Context) bool {
  122. var ips []net.IP
  123. switch m.asType {
  124. case MatcherAsType_Local:
  125. ips = ctx.GetLocalIPs()
  126. case MatcherAsType_Source:
  127. ips = ctx.GetSourceIPs()
  128. case MatcherAsType_Target:
  129. ips = ctx.GetTargetIPs()
  130. default:
  131. panic("unk asType")
  132. }
  133. return m.matcher.AnyMatch(ips)
  134. }
  135. type PortMatcher struct {
  136. port net.MemoryPortList
  137. asType MatcherAsType
  138. }
  139. // NewPortMatcher create a new port matcher that can match source or local or destination port
  140. func NewPortMatcher(list *net.PortList, asType MatcherAsType) *PortMatcher {
  141. return &PortMatcher{
  142. port: net.PortListFromProto(list),
  143. asType: asType,
  144. }
  145. }
  146. // Apply implements Condition.
  147. func (v *PortMatcher) Apply(ctx routing.Context) bool {
  148. switch v.asType {
  149. case MatcherAsType_Local:
  150. return v.port.Contains(ctx.GetLocalPort())
  151. case MatcherAsType_Source:
  152. return v.port.Contains(ctx.GetSourcePort())
  153. case MatcherAsType_Target:
  154. return v.port.Contains(ctx.GetTargetPort())
  155. case MatcherAsType_VlessRoute:
  156. return v.port.Contains(ctx.GetVlessRoute())
  157. default:
  158. panic("unk asType")
  159. }
  160. }
  161. type NetworkMatcher struct {
  162. list [8]bool
  163. }
  164. func NewNetworkMatcher(network []net.Network) NetworkMatcher {
  165. var matcher NetworkMatcher
  166. for _, n := range network {
  167. matcher.list[int(n)] = true
  168. }
  169. return matcher
  170. }
  171. // Apply implements Condition.
  172. func (v NetworkMatcher) Apply(ctx routing.Context) bool {
  173. return v.list[int(ctx.GetNetwork())]
  174. }
  175. type UserMatcher struct {
  176. user []string
  177. pattern []*regexp.Regexp
  178. }
  179. func NewUserMatcher(users []string) *UserMatcher {
  180. usersCopy := make([]string, 0, len(users))
  181. patternsCopy := make([]*regexp.Regexp, 0, len(users))
  182. for _, user := range users {
  183. if len(user) > 0 {
  184. if len(user) > 7 && strings.HasPrefix(user, "regexp:") {
  185. if re, err := regexp.Compile(user[7:]); err == nil {
  186. patternsCopy = append(patternsCopy, re)
  187. }
  188. // Items of users slice with an invalid regexp syntax are ignored.
  189. continue
  190. }
  191. usersCopy = append(usersCopy, user)
  192. }
  193. }
  194. return &UserMatcher{
  195. user: usersCopy,
  196. pattern: patternsCopy,
  197. }
  198. }
  199. // Apply implements Condition.
  200. func (v *UserMatcher) Apply(ctx routing.Context) bool {
  201. user := ctx.GetUser()
  202. if len(user) == 0 {
  203. return false
  204. }
  205. for _, u := range v.user {
  206. if u == user {
  207. return true
  208. }
  209. }
  210. for _, re := range v.pattern {
  211. if re.MatchString(user) {
  212. return true
  213. }
  214. }
  215. return false
  216. }
  217. type InboundTagMatcher struct {
  218. tags []string
  219. }
  220. func NewInboundTagMatcher(tags []string) *InboundTagMatcher {
  221. tagsCopy := make([]string, 0, len(tags))
  222. for _, tag := range tags {
  223. if len(tag) > 0 {
  224. tagsCopy = append(tagsCopy, tag)
  225. }
  226. }
  227. return &InboundTagMatcher{
  228. tags: tagsCopy,
  229. }
  230. }
  231. // Apply implements Condition.
  232. func (v *InboundTagMatcher) Apply(ctx routing.Context) bool {
  233. tag := ctx.GetInboundTag()
  234. if len(tag) == 0 {
  235. return false
  236. }
  237. for _, t := range v.tags {
  238. if t == tag {
  239. return true
  240. }
  241. }
  242. return false
  243. }
  244. type ProtocolMatcher struct {
  245. protocols []string
  246. }
  247. func NewProtocolMatcher(protocols []string) *ProtocolMatcher {
  248. pCopy := make([]string, 0, len(protocols))
  249. for _, p := range protocols {
  250. if len(p) > 0 {
  251. pCopy = append(pCopy, p)
  252. }
  253. }
  254. return &ProtocolMatcher{
  255. protocols: pCopy,
  256. }
  257. }
  258. // Apply implements Condition.
  259. func (m *ProtocolMatcher) Apply(ctx routing.Context) bool {
  260. protocol := ctx.GetProtocol()
  261. if len(protocol) == 0 {
  262. return false
  263. }
  264. for _, p := range m.protocols {
  265. if strings.HasPrefix(protocol, p) {
  266. return true
  267. }
  268. }
  269. return false
  270. }
  271. type AttributeMatcher struct {
  272. configuredKeys map[string]*regexp.Regexp
  273. }
  274. // Match implements attributes matching.
  275. func (m *AttributeMatcher) Match(attrs map[string]string) bool {
  276. // header keys are case insensitive most likely. So we do a convert
  277. httpHeaders := make(map[string]string)
  278. for key, value := range attrs {
  279. httpHeaders[strings.ToLower(key)] = value
  280. }
  281. for key, regex := range m.configuredKeys {
  282. if a, ok := httpHeaders[key]; !ok || !regex.MatchString(a) {
  283. return false
  284. }
  285. }
  286. return true
  287. }
  288. // Apply implements Condition.
  289. func (m *AttributeMatcher) Apply(ctx routing.Context) bool {
  290. attributes := ctx.GetAttributes()
  291. if attributes == nil {
  292. return false
  293. }
  294. return m.Match(attributes)
  295. }
  296. type ProcessNameMatcher struct {
  297. ProcessNames []string
  298. AbsPaths []string
  299. Folders []string
  300. MatchXraySelf bool
  301. }
  302. func NewProcessNameMatcher(names []string) *ProcessNameMatcher {
  303. processNames := []string{}
  304. folders := []string{}
  305. absPaths := []string{}
  306. matchXraySelf := false
  307. for _, name := range names {
  308. if name == "self/" {
  309. matchXraySelf = true
  310. continue
  311. }
  312. // replace xray/ with self executable path
  313. if name == "xray/" {
  314. xrayPath, err := os.Executable()
  315. if err != nil {
  316. errors.LogError(context.Background(), "Failed to get xray executable path: ", err)
  317. continue
  318. }
  319. name = xrayPath
  320. }
  321. name := filepath.ToSlash(name)
  322. // /usr/bin/
  323. if strings.HasSuffix(name, "/") {
  324. folders = append(folders, name)
  325. continue
  326. }
  327. // /usr/bin/curl
  328. if strings.Contains(name, "/") {
  329. absPaths = append(absPaths, name)
  330. continue
  331. }
  332. // curl.exe or curl
  333. processNames = append(processNames, strings.TrimSuffix(name, ".exe"))
  334. }
  335. return &ProcessNameMatcher{
  336. ProcessNames: processNames,
  337. AbsPaths: absPaths,
  338. Folders: folders,
  339. MatchXraySelf: matchXraySelf,
  340. }
  341. }
  342. func (m *ProcessNameMatcher) Apply(ctx routing.Context) bool {
  343. if len(ctx.GetSourceIPs()) == 0 {
  344. return false
  345. }
  346. srcPort := ctx.GetSourcePort().String()
  347. srcIP := ctx.GetSourceIPs()[0].String()
  348. var network string
  349. switch ctx.GetNetwork() {
  350. case net.Network_TCP:
  351. network = "tcp"
  352. case net.Network_UDP:
  353. network = "udp"
  354. default:
  355. return false
  356. }
  357. src, err := net.ParseDestination(strings.Join([]string{network, srcIP, srcPort}, ":"))
  358. if err != nil {
  359. return false
  360. }
  361. pid, name, absPath, err := net.FindProcess(src)
  362. if err != nil {
  363. if err != net.ErrNotLocal {
  364. errors.LogError(context.Background(), "Unables to find local process name: ", err)
  365. }
  366. return false
  367. }
  368. if m.MatchXraySelf {
  369. if pid == os.Getpid() {
  370. return true
  371. }
  372. }
  373. if slices.Contains(m.ProcessNames, name) {
  374. return true
  375. }
  376. if slices.Contains(m.AbsPaths, absPath) {
  377. return true
  378. }
  379. for _, f := range m.Folders {
  380. if strings.HasPrefix(absPath, f) {
  381. return true
  382. }
  383. }
  384. return false
  385. }