router.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. package conf
  2. import (
  3. "encoding/json"
  4. "runtime"
  5. "strconv"
  6. "strings"
  7. "github.com/golang/protobuf/proto"
  8. "github.com/xtls/xray-core/app/router"
  9. "github.com/xtls/xray-core/common/net"
  10. "github.com/xtls/xray-core/common/platform/filesystem"
  11. )
  12. type RouterRulesConfig struct {
  13. RuleList []json.RawMessage `json:"rules"`
  14. DomainStrategy string `json:"domainStrategy"`
  15. }
  16. // StrategyConfig represents a strategy config
  17. type StrategyConfig struct {
  18. Type string `json:"type"`
  19. Settings *json.RawMessage `json:"settings"`
  20. }
  21. type BalancingRule struct {
  22. Tag string `json:"tag"`
  23. Selectors StringList `json:"selector"`
  24. Strategy StrategyConfig `json:"strategy"`
  25. }
  26. func (r *BalancingRule) Build() (*router.BalancingRule, error) {
  27. if r.Tag == "" {
  28. return nil, newError("empty balancer tag")
  29. }
  30. if len(r.Selectors) == 0 {
  31. return nil, newError("empty selector list")
  32. }
  33. var strategy string
  34. switch strings.ToLower(r.Strategy.Type) {
  35. case strategyRandom, "":
  36. strategy = strategyRandom
  37. case strategyLeastPing:
  38. strategy = "leastPing"
  39. default:
  40. return nil, newError("unknown balancing strategy: " + r.Strategy.Type)
  41. }
  42. return &router.BalancingRule{
  43. Tag: r.Tag,
  44. OutboundSelector: []string(r.Selectors),
  45. Strategy: strategy,
  46. }, nil
  47. }
  48. type RouterConfig struct {
  49. Settings *RouterRulesConfig `json:"settings"` // Deprecated
  50. RuleList []json.RawMessage `json:"rules"`
  51. DomainStrategy *string `json:"domainStrategy"`
  52. Balancers []*BalancingRule `json:"balancers"`
  53. DomainMatcher string `json:"domainMatcher"`
  54. }
  55. func (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {
  56. ds := ""
  57. if c.DomainStrategy != nil {
  58. ds = *c.DomainStrategy
  59. } else if c.Settings != nil {
  60. ds = c.Settings.DomainStrategy
  61. }
  62. switch strings.ToLower(ds) {
  63. case "alwaysip":
  64. return router.Config_UseIp
  65. case "ipifnonmatch":
  66. return router.Config_IpIfNonMatch
  67. case "ipondemand":
  68. return router.Config_IpOnDemand
  69. default:
  70. return router.Config_AsIs
  71. }
  72. }
  73. func (c *RouterConfig) Build() (*router.Config, error) {
  74. config := new(router.Config)
  75. config.DomainStrategy = c.getDomainStrategy()
  76. var rawRuleList []json.RawMessage
  77. if c != nil {
  78. rawRuleList = c.RuleList
  79. if c.Settings != nil {
  80. c.RuleList = append(c.RuleList, c.Settings.RuleList...)
  81. rawRuleList = c.RuleList
  82. }
  83. }
  84. for _, rawRule := range rawRuleList {
  85. rule, err := ParseRule(rawRule)
  86. if err != nil {
  87. return nil, err
  88. }
  89. if rule.DomainMatcher == "" {
  90. rule.DomainMatcher = c.DomainMatcher
  91. }
  92. config.Rule = append(config.Rule, rule)
  93. }
  94. for _, rawBalancer := range c.Balancers {
  95. balancer, err := rawBalancer.Build()
  96. if err != nil {
  97. return nil, err
  98. }
  99. config.BalancingRule = append(config.BalancingRule, balancer)
  100. }
  101. return config, nil
  102. }
  103. type RouterRule struct {
  104. Type string `json:"type"`
  105. OutboundTag string `json:"outboundTag"`
  106. BalancerTag string `json:"balancerTag"`
  107. DomainMatcher string `json:"domainMatcher"`
  108. }
  109. func ParseIP(s string) (*router.CIDR, error) {
  110. var addr, mask string
  111. i := strings.Index(s, "/")
  112. if i < 0 {
  113. addr = s
  114. } else {
  115. addr = s[:i]
  116. mask = s[i+1:]
  117. }
  118. ip := net.ParseAddress(addr)
  119. switch ip.Family() {
  120. case net.AddressFamilyIPv4:
  121. bits := uint32(32)
  122. if len(mask) > 0 {
  123. bits64, err := strconv.ParseUint(mask, 10, 32)
  124. if err != nil {
  125. return nil, newError("invalid network mask for router: ", mask).Base(err)
  126. }
  127. bits = uint32(bits64)
  128. }
  129. if bits > 32 {
  130. return nil, newError("invalid network mask for router: ", bits)
  131. }
  132. return &router.CIDR{
  133. Ip: []byte(ip.IP()),
  134. Prefix: bits,
  135. }, nil
  136. case net.AddressFamilyIPv6:
  137. bits := uint32(128)
  138. if len(mask) > 0 {
  139. bits64, err := strconv.ParseUint(mask, 10, 32)
  140. if err != nil {
  141. return nil, newError("invalid network mask for router: ", mask).Base(err)
  142. }
  143. bits = uint32(bits64)
  144. }
  145. if bits > 128 {
  146. return nil, newError("invalid network mask for router: ", bits)
  147. }
  148. return &router.CIDR{
  149. Ip: []byte(ip.IP()),
  150. Prefix: bits,
  151. }, nil
  152. default:
  153. return nil, newError("unsupported address for router: ", s)
  154. }
  155. }
  156. func loadGeoIP(code string) ([]*router.CIDR, error) {
  157. return loadIP("geoip.dat", code)
  158. }
  159. var (
  160. FileCache = make(map[string][]byte)
  161. IPCache = make(map[string]*router.GeoIP)
  162. SiteCache = make(map[string]*router.GeoSite)
  163. )
  164. func loadFile(file string) ([]byte, error) {
  165. if FileCache[file] == nil {
  166. bs, err := filesystem.ReadAsset(file)
  167. if err != nil {
  168. return nil, newError("failed to open file: ", file).Base(err)
  169. }
  170. if len(bs) == 0 {
  171. return nil, newError("empty file: ", file)
  172. }
  173. // Do not cache file, may save RAM when there
  174. // are many files, but consume CPU each time.
  175. return bs, nil
  176. FileCache[file] = bs
  177. }
  178. return FileCache[file], nil
  179. }
  180. func loadIP(file, code string) ([]*router.CIDR, error) {
  181. index := file + ":" + code
  182. if IPCache[index] == nil {
  183. bs, err := loadFile(file)
  184. if err != nil {
  185. return nil, newError("failed to load file: ", file).Base(err)
  186. }
  187. bs = find(bs, []byte(code))
  188. if bs == nil {
  189. return nil, newError("code not found in ", file, ": ", code)
  190. }
  191. var geoip router.GeoIP
  192. if err := proto.Unmarshal(bs, &geoip); err != nil {
  193. return nil, newError("error unmarshal IP in ", file, ": ", code).Base(err)
  194. }
  195. defer runtime.GC() // or debug.FreeOSMemory()
  196. return geoip.Cidr, nil // do not cache geoip
  197. IPCache[index] = &geoip
  198. }
  199. return IPCache[index].Cidr, nil
  200. }
  201. func loadSite(file, code string) ([]*router.Domain, error) {
  202. index := file + ":" + code
  203. if SiteCache[index] == nil {
  204. bs, err := loadFile(file)
  205. if err != nil {
  206. return nil, newError("failed to load file: ", file).Base(err)
  207. }
  208. bs = find(bs, []byte(code))
  209. if bs == nil {
  210. return nil, newError("list not found in ", file, ": ", code)
  211. }
  212. var geosite router.GeoSite
  213. if err := proto.Unmarshal(bs, &geosite); err != nil {
  214. return nil, newError("error unmarshal Site in ", file, ": ", code).Base(err)
  215. }
  216. defer runtime.GC() // or debug.FreeOSMemory()
  217. return geosite.Domain, nil // do not cache geosite
  218. SiteCache[index] = &geosite
  219. }
  220. return SiteCache[index].Domain, nil
  221. }
  222. func find(data, code []byte) []byte {
  223. codeL := len(code)
  224. if codeL == 0 {
  225. return nil
  226. }
  227. for {
  228. dataL := len(data)
  229. if dataL < 2 {
  230. return nil
  231. }
  232. x, y := proto.DecodeVarint(data[1:])
  233. if x == 0 && y == 0 {
  234. return nil
  235. }
  236. headL, bodyL := 1+y, int(x)
  237. dataL -= headL
  238. if dataL < bodyL {
  239. return nil
  240. }
  241. data = data[headL:]
  242. if int(data[1]) == codeL {
  243. for i := 0; i < codeL && data[2+i] == code[i]; i++ {
  244. if i+1 == codeL {
  245. return data[:bodyL]
  246. }
  247. }
  248. }
  249. if dataL == bodyL {
  250. return nil
  251. }
  252. data = data[bodyL:]
  253. }
  254. }
  255. type AttributeMatcher interface {
  256. Match(*router.Domain) bool
  257. }
  258. type BooleanMatcher string
  259. func (m BooleanMatcher) Match(domain *router.Domain) bool {
  260. for _, attr := range domain.Attribute {
  261. if attr.Key == string(m) {
  262. return true
  263. }
  264. }
  265. return false
  266. }
  267. type AttributeList struct {
  268. matcher []AttributeMatcher
  269. }
  270. func (al *AttributeList) Match(domain *router.Domain) bool {
  271. for _, matcher := range al.matcher {
  272. if !matcher.Match(domain) {
  273. return false
  274. }
  275. }
  276. return true
  277. }
  278. func (al *AttributeList) IsEmpty() bool {
  279. return len(al.matcher) == 0
  280. }
  281. func parseAttrs(attrs []string) *AttributeList {
  282. al := new(AttributeList)
  283. for _, attr := range attrs {
  284. lc := strings.ToLower(attr)
  285. al.matcher = append(al.matcher, BooleanMatcher(lc))
  286. }
  287. return al
  288. }
  289. func loadGeositeWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) {
  290. parts := strings.Split(siteWithAttr, "@")
  291. if len(parts) == 0 {
  292. return nil, newError("empty site")
  293. }
  294. country := strings.ToUpper(parts[0])
  295. attrs := parseAttrs(parts[1:])
  296. domains, err := loadSite(file, country)
  297. if err != nil {
  298. return nil, err
  299. }
  300. if attrs.IsEmpty() {
  301. return domains, nil
  302. }
  303. filteredDomains := make([]*router.Domain, 0, len(domains))
  304. for _, domain := range domains {
  305. if attrs.Match(domain) {
  306. filteredDomains = append(filteredDomains, domain)
  307. }
  308. }
  309. return filteredDomains, nil
  310. }
  311. func parseDomainRule(domain string) ([]*router.Domain, error) {
  312. if strings.HasPrefix(domain, "geosite:") {
  313. country := strings.ToUpper(domain[8:])
  314. domains, err := loadGeositeWithAttr("geosite.dat", country)
  315. if err != nil {
  316. return nil, newError("failed to load geosite: ", country).Base(err)
  317. }
  318. return domains, nil
  319. }
  320. isExtDatFile := 0
  321. {
  322. const prefix = "ext:"
  323. if strings.HasPrefix(domain, prefix) {
  324. isExtDatFile = len(prefix)
  325. }
  326. const prefixQualified = "ext-domain:"
  327. if strings.HasPrefix(domain, prefixQualified) {
  328. isExtDatFile = len(prefixQualified)
  329. }
  330. }
  331. if isExtDatFile != 0 {
  332. kv := strings.Split(domain[isExtDatFile:], ":")
  333. if len(kv) != 2 {
  334. return nil, newError("invalid external resource: ", domain)
  335. }
  336. filename := kv[0]
  337. country := kv[1]
  338. domains, err := loadGeositeWithAttr(filename, country)
  339. if err != nil {
  340. return nil, newError("failed to load external sites: ", country, " from ", filename).Base(err)
  341. }
  342. return domains, nil
  343. }
  344. domainRule := new(router.Domain)
  345. switch {
  346. case strings.HasPrefix(domain, "regexp:"):
  347. domainRule.Type = router.Domain_Regex
  348. domainRule.Value = domain[7:]
  349. case strings.HasPrefix(domain, "domain:"):
  350. domainRule.Type = router.Domain_Domain
  351. domainRule.Value = domain[7:]
  352. case strings.HasPrefix(domain, "full:"):
  353. domainRule.Type = router.Domain_Full
  354. domainRule.Value = domain[5:]
  355. case strings.HasPrefix(domain, "keyword:"):
  356. domainRule.Type = router.Domain_Plain
  357. domainRule.Value = domain[8:]
  358. case strings.HasPrefix(domain, "dotless:"):
  359. domainRule.Type = router.Domain_Regex
  360. switch substr := domain[8:]; {
  361. case substr == "":
  362. domainRule.Value = "^[^.]*$"
  363. case !strings.Contains(substr, "."):
  364. domainRule.Value = "^[^.]*" + substr + "[^.]*$"
  365. default:
  366. return nil, newError("substr in dotless rule should not contain a dot: ", substr)
  367. }
  368. default:
  369. domainRule.Type = router.Domain_Plain
  370. domainRule.Value = domain
  371. }
  372. return []*router.Domain{domainRule}, nil
  373. }
  374. func ToCidrList(ips StringList) ([]*router.GeoIP, error) {
  375. var geoipList []*router.GeoIP
  376. var customCidrs []*router.CIDR
  377. for _, ip := range ips {
  378. if strings.HasPrefix(ip, "geoip:") {
  379. country := ip[6:]
  380. isReverseMatch := false
  381. if strings.HasPrefix(ip, "geoip:!") {
  382. country = ip[7:]
  383. isReverseMatch = true
  384. }
  385. if len(country) == 0 {
  386. return nil, newError("empty country name in rule")
  387. }
  388. geoip, err := loadGeoIP(strings.ToUpper(country))
  389. if err != nil {
  390. return nil, newError("failed to load GeoIP: ", country).Base(err)
  391. }
  392. geoipList = append(geoipList, &router.GeoIP{
  393. CountryCode: strings.ToUpper(country),
  394. Cidr: geoip,
  395. ReverseMatch: isReverseMatch,
  396. })
  397. continue
  398. }
  399. isExtDatFile := 0
  400. {
  401. const prefix = "ext:"
  402. if strings.HasPrefix(ip, prefix) {
  403. isExtDatFile = len(prefix)
  404. }
  405. const prefixQualified = "ext-ip:"
  406. if strings.HasPrefix(ip, prefixQualified) {
  407. isExtDatFile = len(prefixQualified)
  408. }
  409. }
  410. if isExtDatFile != 0 {
  411. kv := strings.Split(ip[isExtDatFile:], ":")
  412. if len(kv) != 2 {
  413. return nil, newError("invalid external resource: ", ip)
  414. }
  415. filename := kv[0]
  416. country := kv[1]
  417. if len(filename) == 0 || len(country) == 0 {
  418. return nil, newError("empty filename or empty country in rule")
  419. }
  420. isReverseMatch := false
  421. if strings.HasPrefix(country, "!") {
  422. country = country[1:]
  423. isReverseMatch = true
  424. }
  425. geoip, err := loadIP(filename, strings.ToUpper(country))
  426. if err != nil {
  427. return nil, newError("failed to load IPs: ", country, " from ", filename).Base(err)
  428. }
  429. geoipList = append(geoipList, &router.GeoIP{
  430. CountryCode: strings.ToUpper(filename + "_" + country),
  431. Cidr: geoip,
  432. ReverseMatch: isReverseMatch,
  433. })
  434. continue
  435. }
  436. ipRule, err := ParseIP(ip)
  437. if err != nil {
  438. return nil, newError("invalid IP: ", ip).Base(err)
  439. }
  440. customCidrs = append(customCidrs, ipRule)
  441. }
  442. if len(customCidrs) > 0 {
  443. geoipList = append(geoipList, &router.GeoIP{
  444. Cidr: customCidrs,
  445. })
  446. }
  447. return geoipList, nil
  448. }
  449. func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
  450. type RawFieldRule struct {
  451. RouterRule
  452. Domain *StringList `json:"domain"`
  453. Domains *StringList `json:"domains"`
  454. IP *StringList `json:"ip"`
  455. Port *PortList `json:"port"`
  456. Network *NetworkList `json:"network"`
  457. SourceIP *StringList `json:"source"`
  458. SourcePort *PortList `json:"sourcePort"`
  459. User *StringList `json:"user"`
  460. InboundTag *StringList `json:"inboundTag"`
  461. Protocols *StringList `json:"protocol"`
  462. Attributes string `json:"attrs"`
  463. }
  464. rawFieldRule := new(RawFieldRule)
  465. err := json.Unmarshal(msg, rawFieldRule)
  466. if err != nil {
  467. return nil, err
  468. }
  469. rule := new(router.RoutingRule)
  470. switch {
  471. case len(rawFieldRule.OutboundTag) > 0:
  472. rule.TargetTag = &router.RoutingRule_Tag{
  473. Tag: rawFieldRule.OutboundTag,
  474. }
  475. case len(rawFieldRule.BalancerTag) > 0:
  476. rule.TargetTag = &router.RoutingRule_BalancingTag{
  477. BalancingTag: rawFieldRule.BalancerTag,
  478. }
  479. default:
  480. return nil, newError("neither outboundTag nor balancerTag is specified in routing rule")
  481. }
  482. if rawFieldRule.DomainMatcher != "" {
  483. rule.DomainMatcher = rawFieldRule.DomainMatcher
  484. }
  485. if rawFieldRule.Domain != nil {
  486. for _, domain := range *rawFieldRule.Domain {
  487. rules, err := parseDomainRule(domain)
  488. if err != nil {
  489. return nil, newError("failed to parse domain rule: ", domain).Base(err)
  490. }
  491. rule.Domain = append(rule.Domain, rules...)
  492. }
  493. }
  494. if rawFieldRule.Domains != nil {
  495. for _, domain := range *rawFieldRule.Domains {
  496. rules, err := parseDomainRule(domain)
  497. if err != nil {
  498. return nil, newError("failed to parse domain rule: ", domain).Base(err)
  499. }
  500. rule.Domain = append(rule.Domain, rules...)
  501. }
  502. }
  503. if rawFieldRule.IP != nil {
  504. geoipList, err := ToCidrList(*rawFieldRule.IP)
  505. if err != nil {
  506. return nil, err
  507. }
  508. rule.Geoip = geoipList
  509. }
  510. if rawFieldRule.Port != nil {
  511. rule.PortList = rawFieldRule.Port.Build()
  512. }
  513. if rawFieldRule.Network != nil {
  514. rule.Networks = rawFieldRule.Network.Build()
  515. }
  516. if rawFieldRule.SourceIP != nil {
  517. geoipList, err := ToCidrList(*rawFieldRule.SourceIP)
  518. if err != nil {
  519. return nil, err
  520. }
  521. rule.SourceGeoip = geoipList
  522. }
  523. if rawFieldRule.SourcePort != nil {
  524. rule.SourcePortList = rawFieldRule.SourcePort.Build()
  525. }
  526. if rawFieldRule.User != nil {
  527. for _, s := range *rawFieldRule.User {
  528. rule.UserEmail = append(rule.UserEmail, s)
  529. }
  530. }
  531. if rawFieldRule.InboundTag != nil {
  532. for _, s := range *rawFieldRule.InboundTag {
  533. rule.InboundTag = append(rule.InboundTag, s)
  534. }
  535. }
  536. if rawFieldRule.Protocols != nil {
  537. for _, s := range *rawFieldRule.Protocols {
  538. rule.Protocol = append(rule.Protocol, s)
  539. }
  540. }
  541. if len(rawFieldRule.Attributes) > 0 {
  542. rule.Attributes = rawFieldRule.Attributes
  543. }
  544. return rule, nil
  545. }
  546. func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {
  547. rawRule := new(RouterRule)
  548. err := json.Unmarshal(msg, rawRule)
  549. if err != nil {
  550. return nil, newError("invalid router rule").Base(err)
  551. }
  552. if strings.EqualFold(rawRule.Type, "field") {
  553. fieldrule, err := parseFieldRule(msg)
  554. if err != nil {
  555. return nil, newError("invalid field rule").Base(err)
  556. }
  557. return fieldrule, nil
  558. }
  559. if strings.EqualFold(rawRule.Type, "chinaip") {
  560. chinaiprule, err := parseChinaIPRule(msg)
  561. if err != nil {
  562. return nil, newError("invalid chinaip rule").Base(err)
  563. }
  564. return chinaiprule, nil
  565. }
  566. if strings.EqualFold(rawRule.Type, "chinasites") {
  567. chinasitesrule, err := parseChinaSitesRule(msg)
  568. if err != nil {
  569. return nil, newError("invalid chinasites rule").Base(err)
  570. }
  571. return chinasitesrule, nil
  572. }
  573. return nil, newError("unknown router rule type: ", rawRule.Type)
  574. }
  575. func parseChinaIPRule(data []byte) (*router.RoutingRule, error) {
  576. rawRule := new(RouterRule)
  577. err := json.Unmarshal(data, rawRule)
  578. if err != nil {
  579. return nil, newError("invalid router rule").Base(err)
  580. }
  581. chinaIPs, err := loadGeoIP("CN")
  582. if err != nil {
  583. return nil, newError("failed to load geoip:cn").Base(err)
  584. }
  585. return &router.RoutingRule{
  586. TargetTag: &router.RoutingRule_Tag{
  587. Tag: rawRule.OutboundTag,
  588. },
  589. Cidr: chinaIPs,
  590. }, nil
  591. }
  592. func parseChinaSitesRule(data []byte) (*router.RoutingRule, error) {
  593. rawRule := new(RouterRule)
  594. err := json.Unmarshal(data, rawRule)
  595. if err != nil {
  596. return nil, newError("invalid router rule").Base(err).AtError()
  597. }
  598. domains, err := loadGeositeWithAttr("geosite.dat", "CN")
  599. if err != nil {
  600. return nil, newError("failed to load geosite:cn.").Base(err)
  601. }
  602. return &router.RoutingRule{
  603. TargetTag: &router.RoutingRule_Tag{
  604. Tag: rawRule.OutboundTag,
  605. },
  606. Domain: domains,
  607. }, nil
  608. }