github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/app/router/router.go (about)

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