router.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package conf
  2. import (
  3. "context"
  4. "encoding/json"
  5. "strings"
  6. "github.com/golang/protobuf/proto"
  7. "github.com/v2fly/v2ray-core/v4/app/router"
  8. "github.com/v2fly/v2ray-core/v4/common/platform"
  9. "github.com/v2fly/v2ray-core/v4/common/serial"
  10. "github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon"
  11. "github.com/v2fly/v2ray-core/v4/infra/conf/geodata"
  12. rule2 "github.com/v2fly/v2ray-core/v4/infra/conf/rule"
  13. )
  14. type RouterRulesConfig struct {
  15. RuleList []json.RawMessage `json:"rules"`
  16. DomainStrategy string `json:"domainStrategy"`
  17. }
  18. // StrategyConfig represents a strategy config
  19. type StrategyConfig struct {
  20. Type string `json:"type"`
  21. Settings *json.RawMessage `json:"settings"`
  22. }
  23. type BalancingRule struct {
  24. Tag string `json:"tag"`
  25. Selectors cfgcommon.StringList `json:"selector"`
  26. Strategy StrategyConfig `json:"strategy"`
  27. FallbackTag string `json:"fallbackTag"`
  28. }
  29. // Build builds the balancing rule
  30. func (r *BalancingRule) Build() (*router.BalancingRule, error) {
  31. if r.Tag == "" {
  32. return nil, newError("empty balancer tag")
  33. }
  34. if len(r.Selectors) == 0 {
  35. return nil, newError("empty selector list")
  36. }
  37. var strategy string
  38. switch strings.ToLower(r.Strategy.Type) {
  39. case strategyRandom, "":
  40. r.Strategy.Type = strategyRandom
  41. strategy = strategyRandom
  42. case strategyLeastLoad:
  43. strategy = strategyLeastLoad
  44. case strategyLeastPing:
  45. strategy = "leastPing"
  46. default:
  47. return nil, newError("unknown balancing strategy: " + r.Strategy.Type)
  48. }
  49. settings := []byte("{}")
  50. if r.Strategy.Settings != nil {
  51. settings = ([]byte)(*r.Strategy.Settings)
  52. }
  53. rawConfig, err := strategyConfigLoader.LoadWithID(settings, r.Strategy.Type)
  54. if err != nil {
  55. return nil, newError("failed to parse to strategy config.").Base(err)
  56. }
  57. var ts proto.Message
  58. if builder, ok := rawConfig.(Buildable); ok {
  59. ts, err = builder.Build()
  60. if err != nil {
  61. return nil, err
  62. }
  63. }
  64. return &router.BalancingRule{
  65. Strategy: strategy,
  66. StrategySettings: serial.ToTypedMessage(ts),
  67. FallbackTag: r.FallbackTag,
  68. OutboundSelector: r.Selectors,
  69. Tag: r.Tag,
  70. }, nil
  71. }
  72. type RouterConfig struct {
  73. Settings *RouterRulesConfig `json:"settings"` // Deprecated
  74. RuleList []json.RawMessage `json:"rules"`
  75. DomainStrategy *string `json:"domainStrategy"`
  76. Balancers []*BalancingRule `json:"balancers"`
  77. DomainMatcher string `json:"domainMatcher"`
  78. }
  79. func (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {
  80. ds := ""
  81. if c.DomainStrategy != nil {
  82. ds = *c.DomainStrategy
  83. } else if c.Settings != nil {
  84. ds = c.Settings.DomainStrategy
  85. }
  86. switch strings.ToLower(ds) {
  87. case "alwaysip", "always_ip", "always-ip":
  88. return router.Config_UseIp
  89. case "ipifnonmatch", "ip_if_non_match", "ip-if-non-match":
  90. return router.Config_IpIfNonMatch
  91. case "ipondemand", "ip_on_demand", "ip-on-demand":
  92. return router.Config_IpOnDemand
  93. default:
  94. return router.Config_AsIs
  95. }
  96. }
  97. func (c *RouterConfig) Build() (*router.Config, error) {
  98. config := new(router.Config)
  99. config.DomainStrategy = c.getDomainStrategy()
  100. cfgctx := cfgcommon.NewConfigureLoadingContext(context.Background())
  101. geoloadername := platform.NewEnvFlag("v2ray.conf.geoloader").GetValue(func() string {
  102. return "standard"
  103. })
  104. if loader, err := geodata.GetGeoDataLoader(geoloadername); err == nil {
  105. cfgcommon.SetGeoDataLoader(cfgctx, loader)
  106. } else {
  107. return nil, newError("unable to create geo data loader ").Base(err)
  108. }
  109. var rawRuleList []json.RawMessage
  110. if c != nil {
  111. rawRuleList = c.RuleList
  112. if c.Settings != nil {
  113. c.RuleList = append(c.RuleList, c.Settings.RuleList...)
  114. rawRuleList = c.RuleList
  115. }
  116. }
  117. for _, rawRule := range rawRuleList {
  118. rule, err := rule2.ParseRule(cfgctx, rawRule)
  119. if err != nil {
  120. return nil, err
  121. }
  122. if rule.DomainMatcher == "" {
  123. rule.DomainMatcher = c.DomainMatcher
  124. }
  125. config.Rule = append(config.Rule, rule)
  126. }
  127. for _, rawBalancer := range c.Balancers {
  128. balancer, err := rawBalancer.Build()
  129. if err != nil {
  130. return nil, err
  131. }
  132. config.BalancingRule = append(config.BalancingRule, balancer)
  133. }
  134. return config, nil
  135. }