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