Xray-core/app/router/router.go
世界 cd4631ce99
Merge dns (#722)
* DNS: add clientip for specific nameserver

* Refactoring: DNS App

* DNS: add DNS over QUIC support

* Feat: add disableCache option for DNS

* Feat: add queryStrategy option for DNS

* Feat: add disableFallback & skipFallback option for DNS

* Feat: DNS hosts support multiple addresses

* Feat: DNS transport over TCP

* DNS: fix typo & refine code

* DNS: refine code

* Add disableFallbackIfMatch dns option

* Feat: routing and freedom outbound ignore Fake DNS

Turn off fake DNS for request sent from Routing and Freedom outbound.
Fake DNS now only apply to DNS outbound.
This is important for Android, where VPN service take over all system DNS
traffic and pass it to core.  "UseIp" option can be used in Freedom outbound
to avoid getting fake IP and fail connection.

* Fix test

* Fix dns return

* Fix local dns return empty

* Apply timeout to dns outbound

* Update app/dns/config.go

Co-authored-by: Loyalsoldier <10487845+loyalsoldier@users.noreply.github.com>
Co-authored-by: Ye Zhihao <vigilans@foxmail.com>
Co-authored-by: maskedeken <52683904+maskedeken@users.noreply.github.com>
Co-authored-by: V2Fly Team <51714622+vcptr@users.noreply.github.com>
Co-authored-by: CalmLong <37164399+calmlong@users.noreply.github.com>
Co-authored-by: Shelikhoo <xiaokangwang@outlook.com>
Co-authored-by: 秋のかえで <autmaple@protonmail.com>
Co-authored-by: 朱聖黎 <digglife@gmail.com>
Co-authored-by: rurirei <72071920+rurirei@users.noreply.github.com>
Co-authored-by: yuhan6665 <1588741+yuhan6665@users.noreply.github.com>
Co-authored-by: Arthur Morgan <4637240+badO1a5A90@users.noreply.github.com>
2021-10-16 21:02:51 +08:00

151 lines
3.5 KiB
Go

package router
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
import (
"context"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/routing"
routing_dns "github.com/xtls/xray-core/features/routing/dns"
)
// Router is an implementation of routing.Router.
type Router struct {
domainStrategy Config_DomainStrategy
rules []*Rule
balancers map[string]*Balancer
dns dns.Client
}
// Route is an implementation of routing.Route.
type Route struct {
routing.Context
outboundGroupTags []string
outboundTag string
}
// Init initializes the Router.
func (r *Router) Init(config *Config, d dns.Client, ohm outbound.Manager) error {
r.domainStrategy = config.DomainStrategy
r.dns = d
r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
for _, rule := range config.BalancingRule {
balancer, err := rule.Build(ohm)
if err != nil {
return err
}
r.balancers[rule.Tag] = balancer
}
r.rules = make([]*Rule, 0, len(config.Rule))
for _, rule := range config.Rule {
cond, err := rule.BuildCondition()
if err != nil {
return err
}
rr := &Rule{
Condition: cond,
Tag: rule.GetTag(),
}
btag := rule.GetBalancingTag()
if len(btag) > 0 {
brule, found := r.balancers[btag]
if !found {
return newError("balancer ", btag, " not found")
}
rr.Balancer = brule
}
r.rules = append(r.rules, rr)
}
return nil
}
// PickRoute implements routing.Router.
func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
rule, ctx, err := r.pickRouteInternal(ctx)
if err != nil {
return nil, err
}
tag, err := rule.GetTag()
if err != nil {
return nil, err
}
return &Route{Context: ctx, outboundTag: tag}, nil
}
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
// SkipDNSResolve is set from DNS module.
// the DOH remote server maybe a domain name,
// this prevents cycle resolving dead loop
skipDNSResolve := ctx.GetSkipDNSResolve()
if r.domainStrategy == Config_IpOnDemand && !skipDNSResolve {
ctx = routing_dns.ContextWithDNSClient(ctx, r.dns)
}
for _, rule := range r.rules {
if rule.Apply(ctx) {
return rule, ctx, nil
}
}
if r.domainStrategy != Config_IpIfNonMatch || len(ctx.GetTargetDomain()) == 0 || skipDNSResolve {
return nil, ctx, common.ErrNoClue
}
ctx = routing_dns.ContextWithDNSClient(ctx, r.dns)
// Try applying rules again if we have IPs.
for _, rule := range r.rules {
if rule.Apply(ctx) {
return rule, ctx, nil
}
}
return nil, ctx, common.ErrNoClue
}
// Start implements common.Runnable.
func (*Router) Start() error {
return nil
}
// Close implements common.Closable.
func (*Router) Close() error {
return nil
}
// Type implement common.HasType.
func (*Router) Type() interface{} {
return routing.RouterType()
}
// GetOutboundGroupTags implements routing.Route.
func (r *Route) GetOutboundGroupTags() []string {
return r.outboundGroupTags
}
// GetOutboundTag implements routing.Route.
func (r *Route) GetOutboundTag() string {
return r.outboundTag
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
r := new(Router)
if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error {
return r.Init(config.(*Config), d, ohm)
}); err != nil {
return nil, err
}
return r, nil
}))
}