2021-08-21 01:20:40 -04:00
|
|
|
//go:build !confonly
|
2020-12-18 04:24:33 -05:00
|
|
|
// +build !confonly
|
|
|
|
|
2018-04-19 15:33:18 -04:00
|
|
|
// Package dns is an implementation of core.DNS feature.
|
2015-12-06 05:00:10 -05:00
|
|
|
package dns
|
|
|
|
|
2022-01-02 10:16:23 -05:00
|
|
|
//go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
|
2020-12-18 04:24:33 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2021-02-22 21:17:20 -05:00
|
|
|
"strings"
|
2020-12-18 04:24:33 -05:00
|
|
|
"sync"
|
|
|
|
|
2022-01-02 10:16:23 -05:00
|
|
|
"github.com/v2fly/v2ray-core/v5/app/router"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/errors"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/platform"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/session"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/strmatcher"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/features"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/features/dns"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/infra/conf/geodata"
|
2020-12-18 04:24:33 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// DNS is a DNS rely server.
|
|
|
|
type DNS struct {
|
|
|
|
sync.Mutex
|
2022-11-29 19:43:39 -05:00
|
|
|
ipOption dns.IPOption
|
|
|
|
hosts *StaticHosts
|
|
|
|
clients []*Client
|
|
|
|
ctx context.Context
|
|
|
|
clientTags map[string]bool
|
|
|
|
domainMatcher strmatcher.IndexMatcher
|
|
|
|
matcherInfos []DomainMatcherInfo
|
2020-12-18 04:24:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
|
|
|
type DomainMatcherInfo struct {
|
|
|
|
clientIdx uint16
|
|
|
|
domainRuleIdx uint16
|
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a new DNS server with given configuration.
|
|
|
|
func New(ctx context.Context, config *Config) (*DNS, error) {
|
2022-11-29 19:43:39 -05:00
|
|
|
// Create static hosts
|
2020-12-18 04:24:33 -05:00
|
|
|
hosts, err := NewStaticHosts(config.StaticHosts, config.Hosts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, newError("failed to create hosts").Base(err)
|
|
|
|
}
|
|
|
|
|
2022-11-29 19:43:39 -05:00
|
|
|
// Create name servers from legacy configs
|
2020-12-18 04:24:33 -05:00
|
|
|
clients := []*Client{}
|
|
|
|
for _, endpoint := range config.NameServers {
|
|
|
|
features.PrintDeprecatedFeatureWarning("simple DNS server")
|
2022-11-29 19:43:39 -05:00
|
|
|
client, err := NewClient(ctx, &NameServer{Address: endpoint}, config)
|
2020-12-18 04:24:33 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, newError("failed to create client").Base(err)
|
|
|
|
}
|
|
|
|
clients = append(clients, client)
|
|
|
|
}
|
|
|
|
|
2022-11-29 19:43:39 -05:00
|
|
|
// Create name servers
|
|
|
|
nsClientMap := map[int]int{}
|
|
|
|
for nsIdx, ns := range config.NameServer {
|
|
|
|
client, err := NewClient(ctx, ns, config)
|
2020-12-18 04:24:33 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, newError("failed to create client").Base(err)
|
|
|
|
}
|
2022-11-29 19:43:39 -05:00
|
|
|
nsClientMap[nsIdx] = len(clients)
|
2020-12-18 04:24:33 -05:00
|
|
|
clients = append(clients, client)
|
|
|
|
}
|
|
|
|
|
2021-02-22 21:17:20 -05:00
|
|
|
// If there is no DNS client in config, add a `localhost` DNS client
|
2020-12-18 04:24:33 -05:00
|
|
|
if len(clients) == 0 {
|
|
|
|
clients = append(clients, NewLocalDNSClient())
|
|
|
|
}
|
|
|
|
|
2022-11-29 19:43:39 -05:00
|
|
|
// Establish members related to global DNS state
|
|
|
|
domainMatcher, matcherInfos, err := establishDomainRules(config, clients, nsClientMap)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err := establishExpectedIPs(config, clients, nsClientMap); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
clientTags := make(map[string]bool)
|
|
|
|
for _, client := range clients {
|
|
|
|
clientTags[client.tag] = true
|
|
|
|
}
|
|
|
|
|
2020-12-18 04:24:33 -05:00
|
|
|
return &DNS{
|
2022-11-29 19:43:39 -05:00
|
|
|
ipOption: toIPOption(config.QueryStrategy),
|
|
|
|
hosts: hosts,
|
|
|
|
clients: clients,
|
|
|
|
ctx: ctx,
|
|
|
|
clientTags: clientTags,
|
|
|
|
domainMatcher: domainMatcher,
|
|
|
|
matcherInfos: matcherInfos,
|
2020-12-18 04:24:33 -05:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2022-11-29 19:43:39 -05:00
|
|
|
func establishDomainRules(config *Config, clients []*Client, nsClientMap map[int]int) (strmatcher.IndexMatcher, []DomainMatcherInfo, error) {
|
|
|
|
domainRuleCount := 0
|
|
|
|
for _, ns := range config.NameServer {
|
|
|
|
domainRuleCount += len(ns.PrioritizedDomain)
|
|
|
|
}
|
|
|
|
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
|
|
|
|
matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1)
|
2022-11-30 01:34:24 -05:00
|
|
|
var domainMatcher strmatcher.IndexMatcher
|
|
|
|
switch config.DomainMatcher {
|
|
|
|
case "mph", "hybrid":
|
|
|
|
newError("using mph domain matcher").AtDebug().WriteToLog()
|
|
|
|
domainMatcher = strmatcher.NewMphIndexMatcher()
|
|
|
|
case "linear":
|
|
|
|
fallthrough
|
|
|
|
default:
|
|
|
|
newError("using default domain matcher").AtDebug().WriteToLog()
|
|
|
|
domainMatcher = strmatcher.NewLinearIndexMatcher()
|
|
|
|
}
|
2022-11-29 19:43:39 -05:00
|
|
|
for nsIdx, ns := range config.NameServer {
|
|
|
|
clientIdx := nsClientMap[nsIdx]
|
|
|
|
var rules []string
|
|
|
|
ruleCurr := 0
|
|
|
|
ruleIter := 0
|
|
|
|
for _, domain := range ns.PrioritizedDomain {
|
|
|
|
domainRule, err := toStrMatcher(domain.Type, domain.Domain)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, newError("failed to create prioritized domain").Base(err).AtWarning()
|
|
|
|
}
|
|
|
|
originalRuleIdx := ruleCurr
|
|
|
|
if ruleCurr < len(ns.OriginalRules) {
|
|
|
|
rule := ns.OriginalRules[ruleCurr]
|
|
|
|
if ruleCurr >= len(rules) {
|
|
|
|
rules = append(rules, rule.Rule)
|
|
|
|
}
|
|
|
|
ruleIter++
|
|
|
|
if ruleIter >= int(rule.Size) {
|
|
|
|
ruleIter = 0
|
|
|
|
ruleCurr++
|
|
|
|
}
|
|
|
|
} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
|
|
|
|
rules = append(rules, domainRule.String())
|
|
|
|
ruleCurr++
|
|
|
|
}
|
|
|
|
midx := domainMatcher.Add(domainRule)
|
|
|
|
matcherInfos[midx] = DomainMatcherInfo{
|
|
|
|
clientIdx: uint16(clientIdx),
|
|
|
|
domainRuleIdx: uint16(originalRuleIdx),
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, newError("failed to create prioritized domain").Base(err).AtWarning()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clients[clientIdx].domains = rules
|
|
|
|
}
|
2022-11-30 01:34:24 -05:00
|
|
|
if err := domainMatcher.Build(); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2022-11-29 19:43:39 -05:00
|
|
|
return domainMatcher, matcherInfos, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func establishExpectedIPs(config *Config, clients []*Client, nsClientMap map[int]int) error {
|
|
|
|
geoipContainer := router.GeoIPMatcherContainer{}
|
|
|
|
for nsIdx, ns := range config.NameServer {
|
|
|
|
clientIdx := nsClientMap[nsIdx]
|
|
|
|
var matchers []*router.GeoIPMatcher
|
|
|
|
for _, geoip := range ns.Geoip {
|
|
|
|
matcher, err := geoipContainer.Add(geoip)
|
|
|
|
if err != nil {
|
|
|
|
return newError("failed to create ip matcher").Base(err).AtWarning()
|
|
|
|
}
|
|
|
|
matchers = append(matchers, matcher)
|
|
|
|
}
|
|
|
|
clients[clientIdx].expectIPs = matchers
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-18 04:24:33 -05:00
|
|
|
// Type implements common.HasType.
|
|
|
|
func (*DNS) Type() interface{} {
|
|
|
|
return dns.ClientType()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start implements common.Runnable.
|
|
|
|
func (s *DNS) Start() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close implements common.Closable.
|
|
|
|
func (s *DNS) Close() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsOwnLink implements proxy.dns.ownLinkVerifier
|
|
|
|
func (s *DNS) IsOwnLink(ctx context.Context) bool {
|
|
|
|
inbound := session.InboundFromContext(ctx)
|
2022-11-29 19:43:39 -05:00
|
|
|
return inbound != nil && s.clientTags[inbound.Tag]
|
2020-12-18 04:24:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// LookupIP implements dns.Client.
|
2021-03-19 03:55:18 -04:00
|
|
|
func (s *DNS) LookupIP(domain string) ([]net.IP, error) {
|
2022-11-29 19:43:39 -05:00
|
|
|
return s.lookupIPInternal(domain, s.ipOption)
|
2021-03-19 03:55:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// LookupIPv4 implements dns.IPv4Lookup.
|
|
|
|
func (s *DNS) LookupIPv4(domain string) ([]net.IP, error) {
|
2022-11-29 19:43:39 -05:00
|
|
|
if option := s.ipOption.With(dns.IPOption{IPv4Enable: true}); option.IsValid() {
|
|
|
|
return s.lookupIPInternal(domain, option)
|
2021-09-24 01:46:34 -04:00
|
|
|
}
|
2022-11-29 19:43:39 -05:00
|
|
|
return nil, dns.ErrEmptyResponse
|
2021-03-19 03:55:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// LookupIPv6 implements dns.IPv6Lookup.
|
|
|
|
func (s *DNS) LookupIPv6(domain string) ([]net.IP, error) {
|
2022-11-29 19:43:39 -05:00
|
|
|
if option := s.ipOption.With(dns.IPOption{IPv6Enable: true}); option.IsValid() {
|
|
|
|
return s.lookupIPInternal(domain, option)
|
2021-09-24 01:46:34 -04:00
|
|
|
}
|
2022-11-29 19:43:39 -05:00
|
|
|
return nil, dns.ErrEmptyResponse
|
2021-03-19 03:55:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *DNS) lookupIPInternal(domain string, option dns.IPOption) ([]net.IP, error) {
|
2020-12-18 04:24:33 -05:00
|
|
|
if domain == "" {
|
|
|
|
return nil, newError("empty domain name")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Normalize the FQDN form query
|
2021-06-22 07:56:35 -04:00
|
|
|
domain = strings.TrimSuffix(domain, ".")
|
2020-12-18 04:24:33 -05:00
|
|
|
|
|
|
|
// Static host lookup
|
|
|
|
switch addrs := s.hosts.Lookup(domain, option); {
|
|
|
|
case addrs == nil: // Domain not recorded in static host
|
|
|
|
break
|
|
|
|
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)
|
|
|
|
return nil, dns.ErrEmptyResponse
|
|
|
|
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement
|
|
|
|
newError("domain replaced: ", domain, " -> ", addrs[0].Domain()).WriteToLog()
|
|
|
|
domain = addrs[0].Domain()
|
|
|
|
default: // Successfully found ip records in static host
|
2021-04-10 23:52:12 -04:00
|
|
|
newError("returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs).WriteToLog()
|
2020-12-18 04:24:33 -05:00
|
|
|
return toNetIP(addrs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Name servers lookup
|
|
|
|
errs := []error{}
|
2022-11-29 19:43:39 -05:00
|
|
|
for _, client := range s.sortClients(domain, option) {
|
|
|
|
ips, err := client.QueryIP(s.ctx, domain, option)
|
2020-12-18 04:24:33 -05:00
|
|
|
if len(ips) > 0 {
|
|
|
|
return ips, nil
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
errs = append(errs, err)
|
|
|
|
}
|
2022-11-29 19:43:39 -05:00
|
|
|
if err != dns.ErrEmptyResponse { // ErrEmptyResponse is not seen as failure, so no failed log
|
|
|
|
newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
|
|
|
|
}
|
2020-12-18 04:24:33 -05:00
|
|
|
if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch {
|
2022-11-29 19:43:39 -05:00
|
|
|
return nil, err // Continues lookup for certain errors
|
2020-12-18 04:24:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, newError("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:55:18 -04:00
|
|
|
// GetIPOption implements ClientWithIPOption.
|
|
|
|
func (s *DNS) GetIPOption() *dns.IPOption {
|
2022-11-29 19:43:39 -05:00
|
|
|
return &s.ipOption
|
2021-03-19 03:55:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetQueryOption implements ClientWithIPOption.
|
|
|
|
func (s *DNS) SetQueryOption(isIPv4Enable, isIPv6Enable bool) {
|
|
|
|
s.ipOption.IPv4Enable = isIPv4Enable
|
|
|
|
s.ipOption.IPv6Enable = isIPv6Enable
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetFakeDNSOption implements ClientWithIPOption.
|
|
|
|
func (s *DNS) SetFakeDNSOption(isFakeEnable bool) {
|
|
|
|
s.ipOption.FakeEnable = isFakeEnable
|
|
|
|
}
|
|
|
|
|
2022-11-29 19:43:39 -05:00
|
|
|
func (s *DNS) sortClients(domain string, option dns.IPOption) []*Client {
|
2020-12-18 04:24:33 -05:00
|
|
|
clients := make([]*Client, 0, len(s.clients))
|
|
|
|
clientUsed := make([]bool, len(s.clients))
|
|
|
|
clientNames := make([]string, 0, len(s.clients))
|
|
|
|
domainRules := []string{}
|
|
|
|
|
|
|
|
// Priority domain matching
|
|
|
|
for _, match := range s.domainMatcher.Match(domain) {
|
|
|
|
info := s.matcherInfos[match]
|
|
|
|
client := s.clients[info.clientIdx]
|
|
|
|
domainRule := client.domains[info.domainRuleIdx]
|
|
|
|
domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", domainRule, info.clientIdx))
|
2022-11-29 19:43:39 -05:00
|
|
|
switch {
|
|
|
|
case clientUsed[info.clientIdx]:
|
|
|
|
continue
|
|
|
|
case !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS"):
|
2020-12-18 04:24:33 -05:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
clientUsed[info.clientIdx] = true
|
|
|
|
clients = append(clients, client)
|
|
|
|
clientNames = append(clientNames, client.Name())
|
|
|
|
}
|
|
|
|
|
2022-11-29 19:43:39 -05:00
|
|
|
// Default round-robin query
|
|
|
|
hasDomainMatch := len(clients) > 0
|
|
|
|
for idx, client := range s.clients {
|
|
|
|
switch {
|
|
|
|
case clientUsed[idx]:
|
|
|
|
continue
|
|
|
|
case !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS"):
|
|
|
|
continue
|
|
|
|
case client.fallbackStrategy == FallbackStrategy_Disabled:
|
|
|
|
continue
|
|
|
|
case client.fallbackStrategy == FallbackStrategy_DisabledIfAnyMatch && hasDomainMatch:
|
|
|
|
continue
|
2020-12-18 04:24:33 -05:00
|
|
|
}
|
2022-11-29 19:43:39 -05:00
|
|
|
clientUsed[idx] = true
|
|
|
|
clients = append(clients, client)
|
|
|
|
clientNames = append(clientNames, client.Name())
|
2020-12-18 04:24:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(domainRules) > 0 {
|
|
|
|
newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
|
|
|
|
}
|
|
|
|
if len(clientNames) > 0 {
|
2022-11-29 19:43:39 -05:00
|
|
|
newError("domain ", domain, " will use DNS in order: ", clientNames, " ", toReqTypes(option)).AtDebug().WriteToLog()
|
2021-04-08 22:35:26 -04:00
|
|
|
}
|
|
|
|
|
2020-12-18 04:24:33 -05:00
|
|
|
return clients
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
|
|
return New(ctx, config.(*Config))
|
|
|
|
}))
|
2021-09-07 03:00:17 -04:00
|
|
|
|
2022-03-08 21:59:18 -05:00
|
|
|
common.Must(common.RegisterConfig((*SimplifiedConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
|
|
ctx = cfgcommon.NewConfigureLoadingContext(ctx)
|
2021-09-07 03:00:17 -04:00
|
|
|
|
|
|
|
geoloadername := platform.NewEnvFlag("v2ray.conf.geoloader").GetValue(func() string {
|
|
|
|
return "standard"
|
|
|
|
})
|
|
|
|
|
|
|
|
if loader, err := geodata.GetGeoDataLoader(geoloadername); err == nil {
|
|
|
|
cfgcommon.SetGeoDataLoader(ctx, loader)
|
|
|
|
} else {
|
|
|
|
return nil, newError("unable to create geo data loader ").Base(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cfgEnv := cfgcommon.GetConfigureLoadingEnvironment(ctx)
|
|
|
|
geoLoader := cfgEnv.GetGeoLoader()
|
|
|
|
|
|
|
|
simplifiedConfig := config.(*SimplifiedConfig)
|
|
|
|
for _, v := range simplifiedConfig.NameServer {
|
|
|
|
for _, geo := range v.Geoip {
|
|
|
|
if geo.Code != "" {
|
|
|
|
filepath := "geoip.dat"
|
|
|
|
if geo.FilePath != "" {
|
|
|
|
filepath = geo.FilePath
|
2021-09-07 06:09:34 -04:00
|
|
|
} else {
|
|
|
|
geo.CountryCode = geo.Code
|
2021-09-07 03:00:17 -04:00
|
|
|
}
|
|
|
|
var err error
|
|
|
|
geo.Cidr, err = geoLoader.LoadIP(filepath, geo.Code)
|
|
|
|
if err != nil {
|
|
|
|
return nil, newError("unable to load geoip").Base(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-10 15:35:02 -04:00
|
|
|
var nameservers []*NameServer
|
|
|
|
|
|
|
|
for _, v := range simplifiedConfig.NameServer {
|
|
|
|
nameserver := &NameServer{
|
2022-11-29 19:43:39 -05:00
|
|
|
Address: v.Address,
|
|
|
|
ClientIp: net.ParseIP(v.ClientIp),
|
|
|
|
Tag: v.Tag,
|
|
|
|
QueryStrategy: v.QueryStrategy,
|
|
|
|
CacheStrategy: v.CacheStrategy,
|
|
|
|
FallbackStrategy: v.FallbackStrategy,
|
|
|
|
SkipFallback: v.SkipFallback,
|
|
|
|
Geoip: v.Geoip,
|
2021-09-10 15:35:02 -04:00
|
|
|
}
|
|
|
|
for _, prioritizedDomain := range v.PrioritizedDomain {
|
|
|
|
nameserver.PrioritizedDomain = append(nameserver.PrioritizedDomain, &NameServer_PriorityDomain{
|
|
|
|
Type: prioritizedDomain.Type,
|
|
|
|
Domain: prioritizedDomain.Domain,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
nameservers = append(nameservers, nameserver)
|
|
|
|
}
|
|
|
|
|
2021-09-07 03:00:17 -04:00
|
|
|
fullConfig := &Config{
|
2022-11-29 19:43:39 -05:00
|
|
|
StaticHosts: simplifiedConfig.StaticHosts,
|
|
|
|
NameServer: nameservers,
|
|
|
|
ClientIp: net.ParseIP(simplifiedConfig.ClientIp),
|
|
|
|
Tag: simplifiedConfig.Tag,
|
|
|
|
QueryStrategy: simplifiedConfig.QueryStrategy,
|
|
|
|
CacheStrategy: simplifiedConfig.CacheStrategy,
|
|
|
|
FallbackStrategy: simplifiedConfig.FallbackStrategy,
|
|
|
|
// Deprecated flags
|
|
|
|
DisableCache: simplifiedConfig.DisableCache,
|
|
|
|
DisableFallback: simplifiedConfig.DisableFallback,
|
|
|
|
DisableFallbackIfMatch: simplifiedConfig.DisableFallbackIfMatch,
|
2021-09-07 03:00:17 -04:00
|
|
|
}
|
|
|
|
return common.CreateObject(ctx, fullConfig)
|
|
|
|
}))
|
2020-12-18 04:24:33 -05:00
|
|
|
}
|