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 }