github.com/imannamdari/v2ray-core/v5@v5.0.5/app/router/router.go (about) 1 package router 2 3 //go:generate go run github.com/imannamdari/v2ray-core/v5/common/errors/errorgen 4 5 import ( 6 "context" 7 8 core "github.com/imannamdari/v2ray-core/v5" 9 "github.com/imannamdari/v2ray-core/v5/common" 10 "github.com/imannamdari/v2ray-core/v5/common/platform" 11 "github.com/imannamdari/v2ray-core/v5/features/dns" 12 "github.com/imannamdari/v2ray-core/v5/features/outbound" 13 "github.com/imannamdari/v2ray-core/v5/features/routing" 14 routing_dns "github.com/imannamdari/v2ray-core/v5/features/routing/dns" 15 "github.com/imannamdari/v2ray-core/v5/infra/conf/cfgcommon" 16 "github.com/imannamdari/v2ray-core/v5/infra/conf/geodata" 17 ) 18 19 // Router is an implementation of routing.Router. 20 type Router struct { 21 domainStrategy 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, dispatcher routing.Dispatcher) 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, dispatcher) 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 == DomainStrategy_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 != DomainStrategy_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 (r *Router) Start() error { 120 return nil 121 } 122 123 // Close implements common.Closable. 124 func (r *Router) Close() error { 125 return nil 126 } 127 128 // Type implements 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, dispatcher routing.Dispatcher) error { 147 return r.Init(ctx, config.(*Config), d, ohm, dispatcher) 148 }); err != nil { 149 return nil, err 150 } 151 return r, nil 152 })) 153 154 common.Must(common.RegisterConfig((*SimplifiedConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 155 ctx = cfgcommon.NewConfigureLoadingContext(ctx) 156 157 geoloadername := platform.NewEnvFlag("v2ray.conf.geoloader").GetValue(func() string { 158 return "standard" 159 }) 160 161 if loader, err := geodata.GetGeoDataLoader(geoloadername); err == nil { 162 cfgcommon.SetGeoDataLoader(ctx, loader) 163 } else { 164 return nil, newError("unable to create geo data loader ").Base(err) 165 } 166 167 cfgEnv := cfgcommon.GetConfigureLoadingEnvironment(ctx) 168 geoLoader := cfgEnv.GetGeoLoader() 169 170 simplifiedConfig := config.(*SimplifiedConfig) 171 172 var routingRules []*RoutingRule 173 174 for _, v := range simplifiedConfig.Rule { 175 rule := new(RoutingRule) 176 177 for _, geo := range v.Geoip { 178 if geo.Code != "" { 179 filepath := "geoip.dat" 180 if geo.FilePath != "" { 181 filepath = geo.FilePath 182 } else { 183 geo.CountryCode = geo.Code 184 } 185 var err error 186 geo.Cidr, err = geoLoader.LoadIP(filepath, geo.Code) 187 if err != nil { 188 return nil, newError("unable to load geoip").Base(err) 189 } 190 } 191 } 192 rule.Geoip = v.Geoip 193 194 for _, geo := range v.SourceGeoip { 195 if geo.Code != "" { 196 filepath := "geoip.dat" 197 if geo.FilePath != "" { 198 filepath = geo.FilePath 199 } else { 200 geo.CountryCode = geo.Code 201 } 202 var err error 203 geo.Cidr, err = geoLoader.LoadIP(filepath, geo.Code) 204 if err != nil { 205 return nil, newError("unable to load geoip").Base(err) 206 } 207 } 208 } 209 rule.SourceGeoip = v.SourceGeoip 210 211 for _, geo := range v.GeoDomain { 212 if geo.Code != "" { 213 filepath := "geosite.dat" 214 if geo.FilePath != "" { 215 filepath = geo.FilePath 216 } 217 var err error 218 geo.Domain, err = geoLoader.LoadGeoSiteWithAttr(filepath, geo.Code) 219 if err != nil { 220 return nil, newError("unable to load geodomain").Base(err) 221 } 222 } 223 } 224 if v.PortList != "" { 225 portList := &cfgcommon.PortList{} 226 err := portList.UnmarshalText(v.PortList) 227 if err != nil { 228 return nil, err 229 } 230 rule.PortList = portList.Build() 231 } 232 if v.SourcePortList != "" { 233 portList := &cfgcommon.PortList{} 234 err := portList.UnmarshalText(v.SourcePortList) 235 if err != nil { 236 return nil, err 237 } 238 rule.SourcePortList = portList.Build() 239 } 240 rule.Domain = v.Domain 241 rule.GeoDomain = v.GeoDomain 242 rule.Networks = v.Networks.GetNetwork() 243 rule.Protocol = v.Protocol 244 rule.Attributes = v.Attributes 245 rule.UserEmail = v.UserEmail 246 rule.InboundTag = v.InboundTag 247 rule.DomainMatcher = v.DomainMatcher 248 switch s := v.TargetTag.(type) { 249 case *SimplifiedRoutingRule_Tag: 250 rule.TargetTag = &RoutingRule_Tag{s.Tag} 251 case *SimplifiedRoutingRule_BalancingTag: 252 rule.TargetTag = &RoutingRule_BalancingTag{s.BalancingTag} 253 } 254 routingRules = append(routingRules, rule) 255 } 256 257 fullConfig := &Config{ 258 DomainStrategy: simplifiedConfig.DomainStrategy, 259 Rule: routingRules, 260 BalancingRule: simplifiedConfig.BalancingRule, 261 } 262 return common.CreateObject(ctx, fullConfig) 263 })) 264 }