router.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. //go:build !confonly
  2. // +build !confonly
  3. package router
  4. //go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
  5. import (
  6. "context"
  7. core "github.com/v2fly/v2ray-core/v4"
  8. "github.com/v2fly/v2ray-core/v4/common"
  9. "github.com/v2fly/v2ray-core/v4/features/dns"
  10. "github.com/v2fly/v2ray-core/v4/features/outbound"
  11. "github.com/v2fly/v2ray-core/v4/features/routing"
  12. routing_dns "github.com/v2fly/v2ray-core/v4/features/routing/dns"
  13. )
  14. // Router is an implementation of routing.Router.
  15. type Router struct {
  16. domainStrategy Config_DomainStrategy
  17. rules []*Rule
  18. balancers map[string]*Balancer
  19. dns dns.Client
  20. }
  21. // Route is an implementation of routing.Route.
  22. type Route struct {
  23. routing.Context
  24. outboundGroupTags []string
  25. outboundTag string
  26. }
  27. // Init initializes the Router.
  28. func (r *Router) Init(ctx context.Context, config *Config, d dns.Client, ohm outbound.Manager) error {
  29. r.domainStrategy = config.DomainStrategy
  30. r.dns = d
  31. r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
  32. for _, rule := range config.BalancingRule {
  33. balancer, err := rule.Build(ohm)
  34. if err != nil {
  35. return err
  36. }
  37. balancer.InjectContext(ctx)
  38. r.balancers[rule.Tag] = balancer
  39. }
  40. r.rules = make([]*Rule, 0, len(config.Rule))
  41. for _, rule := range config.Rule {
  42. cond, err := rule.BuildCondition()
  43. if err != nil {
  44. return err
  45. }
  46. rr := &Rule{
  47. Condition: cond,
  48. Tag: rule.GetTag(),
  49. }
  50. btag := rule.GetBalancingTag()
  51. if len(btag) > 0 {
  52. brule, found := r.balancers[btag]
  53. if !found {
  54. return newError("balancer ", btag, " not found")
  55. }
  56. rr.Balancer = brule
  57. }
  58. r.rules = append(r.rules, rr)
  59. }
  60. return nil
  61. }
  62. // PickRoute implements routing.Router.
  63. func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
  64. rule, ctx, err := r.pickRouteInternal(ctx)
  65. if err != nil {
  66. return nil, err
  67. }
  68. tag, err := rule.GetTag()
  69. if err != nil {
  70. return nil, err
  71. }
  72. return &Route{Context: ctx, outboundTag: tag}, nil
  73. }
  74. func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
  75. // SkipDNSResolve is set from DNS module.
  76. // the DOH remote server maybe a domain name,
  77. // this prevents cycle resolving dead loop
  78. skipDNSResolve := ctx.GetSkipDNSResolve()
  79. if r.domainStrategy == Config_IpOnDemand && !skipDNSResolve {
  80. ctx = routing_dns.ContextWithDNSClient(ctx, r.dns)
  81. }
  82. for _, rule := range r.rules {
  83. if rule.Apply(ctx) {
  84. return rule, ctx, nil
  85. }
  86. }
  87. if r.domainStrategy != Config_IpIfNonMatch || len(ctx.GetTargetDomain()) == 0 || skipDNSResolve {
  88. return nil, ctx, common.ErrNoClue
  89. }
  90. ctx = routing_dns.ContextWithDNSClient(ctx, r.dns)
  91. // Try applying rules again if we have IPs.
  92. for _, rule := range r.rules {
  93. if rule.Apply(ctx) {
  94. return rule, ctx, nil
  95. }
  96. }
  97. return nil, ctx, common.ErrNoClue
  98. }
  99. // Start implements common.Runnable.
  100. func (*Router) Start() error {
  101. return nil
  102. }
  103. // Close implements common.Closable.
  104. func (*Router) Close() error {
  105. return nil
  106. }
  107. // Type implement common.HasType.
  108. func (*Router) Type() interface{} {
  109. return routing.RouterType()
  110. }
  111. // GetOutboundGroupTags implements routing.Route.
  112. func (r *Route) GetOutboundGroupTags() []string {
  113. return r.outboundGroupTags
  114. }
  115. // GetOutboundTag implements routing.Route.
  116. func (r *Route) GetOutboundTag() string {
  117. return r.outboundTag
  118. }
  119. func init() {
  120. common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
  121. r := new(Router)
  122. if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error {
  123. return r.Init(ctx, config.(*Config), d, ohm)
  124. }); err != nil {
  125. return nil, err
  126. }
  127. return r, nil
  128. }))
  129. }