config.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //go:build !confonly
  2. // +build !confonly
  3. package router
  4. import (
  5. "context"
  6. "encoding/json"
  7. "github.com/golang/protobuf/jsonpb"
  8. "github.com/v2fly/v2ray-core/v5/app/router/routercommon"
  9. "github.com/v2fly/v2ray-core/v5/common/net"
  10. "github.com/v2fly/v2ray-core/v5/common/serial"
  11. "github.com/v2fly/v2ray-core/v5/features/outbound"
  12. "github.com/v2fly/v2ray-core/v5/features/routing"
  13. "github.com/v2fly/v2ray-core/v5/infra/conf/v5cfg"
  14. )
  15. type Rule struct {
  16. Tag string
  17. Balancer *Balancer
  18. Condition Condition
  19. }
  20. func (r *Rule) GetTag() (string, error) {
  21. if r.Balancer != nil {
  22. return r.Balancer.PickOutbound()
  23. }
  24. return r.Tag, nil
  25. }
  26. // Apply checks rule matching of current routing context.
  27. func (r *Rule) Apply(ctx routing.Context) bool {
  28. return r.Condition.Apply(ctx)
  29. }
  30. func (rr *RoutingRule) BuildCondition() (Condition, error) {
  31. conds := NewConditionChan()
  32. if len(rr.Domain) > 0 {
  33. cond, err := NewDomainMatcher(rr.DomainMatcher, rr.Domain)
  34. if err != nil {
  35. return nil, newError("failed to build domain condition").Base(err)
  36. }
  37. conds.Add(cond)
  38. }
  39. var geoDomains []*routercommon.Domain
  40. for _, geo := range rr.GeoDomain {
  41. geoDomains = append(geoDomains, geo.Domain...)
  42. }
  43. if len(geoDomains) > 0 {
  44. cond, err := NewDomainMatcher(rr.DomainMatcher, geoDomains)
  45. if err != nil {
  46. return nil, newError("failed to build geo domain condition").Base(err)
  47. }
  48. conds.Add(cond)
  49. }
  50. if len(rr.UserEmail) > 0 {
  51. conds.Add(NewUserMatcher(rr.UserEmail))
  52. }
  53. if len(rr.InboundTag) > 0 {
  54. conds.Add(NewInboundTagMatcher(rr.InboundTag))
  55. }
  56. if rr.PortList != nil {
  57. conds.Add(NewPortMatcher(rr.PortList, false))
  58. } else if rr.PortRange != nil {
  59. conds.Add(NewPortMatcher(&net.PortList{Range: []*net.PortRange{rr.PortRange}}, false))
  60. }
  61. if rr.SourcePortList != nil {
  62. conds.Add(NewPortMatcher(rr.SourcePortList, true))
  63. }
  64. if len(rr.Networks) > 0 {
  65. conds.Add(NewNetworkMatcher(rr.Networks))
  66. } else if rr.NetworkList != nil {
  67. conds.Add(NewNetworkMatcher(rr.NetworkList.Network))
  68. }
  69. if len(rr.Geoip) > 0 {
  70. cond, err := NewMultiGeoIPMatcher(rr.Geoip, false)
  71. if err != nil {
  72. return nil, err
  73. }
  74. conds.Add(cond)
  75. } else if len(rr.Cidr) > 0 {
  76. cond, err := NewMultiGeoIPMatcher([]*routercommon.GeoIP{{Cidr: rr.Cidr}}, false)
  77. if err != nil {
  78. return nil, err
  79. }
  80. conds.Add(cond)
  81. }
  82. if len(rr.SourceGeoip) > 0 {
  83. cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, true)
  84. if err != nil {
  85. return nil, err
  86. }
  87. conds.Add(cond)
  88. } else if len(rr.SourceCidr) > 0 {
  89. cond, err := NewMultiGeoIPMatcher([]*routercommon.GeoIP{{Cidr: rr.SourceCidr}}, true)
  90. if err != nil {
  91. return nil, err
  92. }
  93. conds.Add(cond)
  94. }
  95. if len(rr.Protocol) > 0 {
  96. conds.Add(NewProtocolMatcher(rr.Protocol))
  97. }
  98. if len(rr.Attributes) > 0 {
  99. cond, err := NewAttributeMatcher(rr.Attributes)
  100. if err != nil {
  101. return nil, err
  102. }
  103. conds.Add(cond)
  104. }
  105. if conds.Len() == 0 {
  106. return nil, newError("this rule has no effective fields").AtWarning()
  107. }
  108. return conds, nil
  109. }
  110. // Build builds the balancing rule
  111. func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatcher) (*Balancer, error) {
  112. switch br.Strategy {
  113. case "leastping":
  114. i, err := serial.GetInstanceOf(br.StrategySettings)
  115. if err != nil {
  116. return nil, err
  117. }
  118. s, ok := i.(*StrategyLeastPingConfig)
  119. if !ok {
  120. return nil, newError("not a StrategyLeastPingConfig").AtError()
  121. }
  122. return &Balancer{
  123. selectors: br.OutboundSelector,
  124. strategy: &LeastPingStrategy{config: s},
  125. ohm: ohm,
  126. }, nil
  127. case "leastload":
  128. i, err := serial.GetInstanceOf(br.StrategySettings)
  129. if err != nil {
  130. return nil, err
  131. }
  132. s, ok := i.(*StrategyLeastLoadConfig)
  133. if !ok {
  134. return nil, newError("not a StrategyLeastLoadConfig").AtError()
  135. }
  136. leastLoadStrategy := NewLeastLoadStrategy(s)
  137. return &Balancer{
  138. selectors: br.OutboundSelector,
  139. ohm: ohm, fallbackTag: br.FallbackTag,
  140. strategy: leastLoadStrategy,
  141. }, nil
  142. case "random":
  143. fallthrough
  144. case "":
  145. var randomStrategy *RandomStrategy
  146. if br.StrategySettings != nil {
  147. i, err := serial.GetInstanceOf(br.StrategySettings)
  148. if err != nil {
  149. return nil, err
  150. }
  151. s, ok := i.(*StrategyRandomConfig)
  152. if !ok {
  153. return nil, newError("not a StrategyRandomConfig").AtError()
  154. }
  155. randomStrategy = NewRandomStrategy(s)
  156. }
  157. return &Balancer{
  158. selectors: br.OutboundSelector,
  159. ohm: ohm, fallbackTag: br.FallbackTag,
  160. strategy: randomStrategy,
  161. }, nil
  162. default:
  163. return nil, newError("unrecognized balancer type")
  164. }
  165. }
  166. func (br *BalancingRule) UnmarshalJSONPB(unmarshaler *jsonpb.Unmarshaler, bytes []byte) error {
  167. type BalancingRuleStub struct {
  168. Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
  169. OutboundSelector []string `protobuf:"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3" json:"outbound_selector,omitempty"`
  170. Strategy string `protobuf:"bytes,3,opt,name=strategy,proto3" json:"strategy,omitempty"`
  171. StrategySettings json.RawMessage `protobuf:"bytes,4,opt,name=strategy_settings,json=strategySettings,proto3" json:"strategy_settings,omitempty"`
  172. FallbackTag string `protobuf:"bytes,5,opt,name=fallback_tag,json=fallbackTag,proto3" json:"fallback_tag,omitempty"`
  173. }
  174. var stub BalancingRuleStub
  175. if err := json.Unmarshal(bytes, &stub); err != nil {
  176. return err
  177. }
  178. if stub.Strategy == "" {
  179. stub.Strategy = "random"
  180. }
  181. settingsPack, err := v5cfg.LoadHeterogeneousConfigFromRawJSON(context.TODO(), "balancer", stub.Strategy, stub.StrategySettings)
  182. if err != nil {
  183. return err
  184. }
  185. br.StrategySettings = serial.ToTypedMessage(settingsPack)
  186. br.Tag = stub.Tag
  187. br.Strategy = stub.Strategy
  188. br.OutboundSelector = stub.OutboundSelector
  189. br.FallbackTag = stub.FallbackTag
  190. return nil
  191. }