github.com/igoogolx/clash@v1.19.8/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"net/url"
     8  	"os"
     9  	"strings"
    10  
    11  	"github.com/igoogolx/clash/adapter"
    12  	"github.com/igoogolx/clash/adapter/outbound"
    13  	"github.com/igoogolx/clash/adapter/outboundgroup"
    14  	"github.com/igoogolx/clash/adapter/provider"
    15  	"github.com/igoogolx/clash/component/auth"
    16  	"github.com/igoogolx/clash/component/fakeip"
    17  	"github.com/igoogolx/clash/component/trie"
    18  	C "github.com/igoogolx/clash/constant"
    19  	providerTypes "github.com/igoogolx/clash/constant/provider"
    20  	"github.com/igoogolx/clash/dns"
    21  	"github.com/igoogolx/clash/log"
    22  	R "github.com/igoogolx/clash/rule"
    23  	T "github.com/igoogolx/clash/tunnel"
    24  
    25  	"github.com/samber/lo"
    26  	"gopkg.in/yaml.v3"
    27  )
    28  
    29  // General config
    30  type General struct {
    31  	LegacyInbound
    32  	Controller
    33  	Authentication []string     `json:"authentication"`
    34  	Mode           T.TunnelMode `json:"mode"`
    35  	LogLevel       log.LogLevel `json:"log-level"`
    36  	IPv6           bool         `json:"ipv6"`
    37  	Interface      string       `json:"-"`
    38  	RoutingMark    int          `json:"-"`
    39  }
    40  
    41  // Controller
    42  type Controller struct {
    43  	ExternalController string `json:"-"`
    44  	ExternalUI         string `json:"-"`
    45  	Secret             string `json:"-"`
    46  }
    47  
    48  type LegacyInbound struct {
    49  	Port        int    `json:"port"`
    50  	SocksPort   int    `json:"socks-port"`
    51  	RedirPort   int    `json:"redir-port"`
    52  	TProxyPort  int    `json:"tproxy-port"`
    53  	MixedPort   int    `json:"mixed-port"`
    54  	AllowLan    bool   `json:"allow-lan"`
    55  	BindAddress string `json:"bind-address"`
    56  }
    57  
    58  // DNS config
    59  type DNS struct {
    60  	Enable            bool             `yaml:"enable"`
    61  	IPv6              bool             `yaml:"ipv6"`
    62  	NameServer        []dns.NameServer `yaml:"nameserver"`
    63  	Fallback          []dns.NameServer `yaml:"fallback"`
    64  	FallbackFilter    FallbackFilter   `yaml:"fallback-filter"`
    65  	Listen            string           `yaml:"listen"`
    66  	EnhancedMode      C.DNSMode        `yaml:"enhanced-mode"`
    67  	DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
    68  	FakeIPRange       *fakeip.Pool
    69  	Hosts             *trie.DomainTrie
    70  	NameServerPolicy  map[string]dns.NameServer
    71  	SearchDomains     []string
    72  }
    73  
    74  // FallbackFilter config
    75  type FallbackFilter struct {
    76  	GeoIP     bool         `yaml:"geoip"`
    77  	GeoIPCode string       `yaml:"geoip-code"`
    78  	IPCIDR    []*net.IPNet `yaml:"ipcidr"`
    79  	Domain    []string     `yaml:"domain"`
    80  }
    81  
    82  // Profile config
    83  type Profile struct {
    84  	StoreSelected bool `yaml:"store-selected"`
    85  	StoreFakeIP   bool `yaml:"store-fake-ip"`
    86  }
    87  
    88  // Experimental config
    89  type Experimental struct {
    90  	UDPFallbackMatch bool `yaml:"udp-fallback-match"`
    91  }
    92  
    93  // Config is clash config manager
    94  type Config struct {
    95  	General      *General
    96  	DNS          *DNS
    97  	Experimental *Experimental
    98  	Hosts        *trie.DomainTrie
    99  	Profile      *Profile
   100  	Inbounds     []C.Inbound
   101  	Rules        []C.Rule
   102  	Users        []auth.AuthUser
   103  	Proxies      map[string]C.Proxy
   104  	Providers    map[string]providerTypes.ProxyProvider
   105  	Tunnels      []Tunnel
   106  }
   107  
   108  type RawDNS struct {
   109  	Enable            bool              `yaml:"enable"`
   110  	IPv6              *bool             `yaml:"ipv6"`
   111  	UseHosts          bool              `yaml:"use-hosts"`
   112  	NameServer        []string          `yaml:"nameserver"`
   113  	Fallback          []string          `yaml:"fallback"`
   114  	FallbackFilter    RawFallbackFilter `yaml:"fallback-filter"`
   115  	Listen            string            `yaml:"listen"`
   116  	EnhancedMode      C.DNSMode         `yaml:"enhanced-mode"`
   117  	FakeIPRange       string            `yaml:"fake-ip-range"`
   118  	FakeIPFilter      []string          `yaml:"fake-ip-filter"`
   119  	DefaultNameserver []string          `yaml:"default-nameserver"`
   120  	NameServerPolicy  map[string]string `yaml:"nameserver-policy"`
   121  	SearchDomains     []string          `yaml:"search-domains"`
   122  }
   123  
   124  type RawFallbackFilter struct {
   125  	GeoIP     bool     `yaml:"geoip"`
   126  	GeoIPCode string   `yaml:"geoip-code"`
   127  	IPCIDR    []string `yaml:"ipcidr"`
   128  	Domain    []string `yaml:"domain"`
   129  }
   130  
   131  type tunnel struct {
   132  	Network []string `yaml:"network"`
   133  	Address string   `yaml:"address"`
   134  	Target  string   `yaml:"target"`
   135  	Proxy   string   `yaml:"proxy"`
   136  }
   137  
   138  type Tunnel tunnel
   139  
   140  // UnmarshalYAML implements yaml.Unmarshaler
   141  func (t *Tunnel) UnmarshalYAML(unmarshal func(any) error) error {
   142  	var tp string
   143  	if err := unmarshal(&tp); err != nil {
   144  		var inner tunnel
   145  		if err := unmarshal(&inner); err != nil {
   146  			return err
   147  		}
   148  
   149  		*t = Tunnel(inner)
   150  		return nil
   151  	}
   152  
   153  	// parse udp/tcp,address,target,proxy
   154  	parts := lo.Map(strings.Split(tp, ","), func(s string, _ int) string {
   155  		return strings.TrimSpace(s)
   156  	})
   157  	if len(parts) != 4 {
   158  		return fmt.Errorf("invalid tunnel config %s", tp)
   159  	}
   160  	network := strings.Split(parts[0], "/")
   161  
   162  	// validate network
   163  	for _, n := range network {
   164  		switch n {
   165  		case "tcp", "udp":
   166  		default:
   167  			return fmt.Errorf("invalid tunnel network %s", n)
   168  		}
   169  	}
   170  
   171  	// validate address and target
   172  	address := parts[1]
   173  	target := parts[2]
   174  	for _, addr := range []string{address, target} {
   175  		if _, _, err := net.SplitHostPort(addr); err != nil {
   176  			return fmt.Errorf("invalid tunnel target or address %s", addr)
   177  		}
   178  	}
   179  
   180  	*t = Tunnel(tunnel{
   181  		Network: network,
   182  		Address: address,
   183  		Target:  target,
   184  		Proxy:   parts[3],
   185  	})
   186  	return nil
   187  }
   188  
   189  type RawConfig struct {
   190  	Port               int          `yaml:"port"`
   191  	SocksPort          int          `yaml:"socks-port"`
   192  	RedirPort          int          `yaml:"redir-port"`
   193  	TProxyPort         int          `yaml:"tproxy-port"`
   194  	MixedPort          int          `yaml:"mixed-port"`
   195  	Authentication     []string     `yaml:"authentication"`
   196  	AllowLan           bool         `yaml:"allow-lan"`
   197  	BindAddress        string       `yaml:"bind-address"`
   198  	Mode               T.TunnelMode `yaml:"mode"`
   199  	LogLevel           log.LogLevel `yaml:"log-level"`
   200  	IPv6               bool         `yaml:"ipv6"`
   201  	ExternalController string       `yaml:"external-controller"`
   202  	ExternalUI         string       `yaml:"external-ui"`
   203  	Secret             string       `yaml:"secret"`
   204  	Interface          string       `yaml:"interface-name"`
   205  	RoutingMark        int          `yaml:"routing-mark"`
   206  	Tunnels            []Tunnel     `yaml:"tunnels"`
   207  
   208  	ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
   209  	Hosts         map[string]string         `yaml:"hosts"`
   210  	Inbounds      []C.Inbound               `yaml:"inbounds"`
   211  	DNS           RawDNS                    `yaml:"dns"`
   212  	Experimental  Experimental              `yaml:"experimental"`
   213  	Profile       Profile                   `yaml:"profile"`
   214  	Proxy         []map[string]any          `yaml:"proxies"`
   215  	ProxyGroup    []map[string]any          `yaml:"proxy-groups"`
   216  	Rule          []string                  `yaml:"rules"`
   217  }
   218  
   219  // Parse config
   220  func Parse(buf []byte) (*Config, error) {
   221  	rawCfg, err := UnmarshalRawConfig(buf)
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	return ParseRawConfig(rawCfg)
   227  }
   228  
   229  func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
   230  	// config with default value
   231  	rawCfg := &RawConfig{
   232  		AllowLan:       false,
   233  		BindAddress:    "*",
   234  		Mode:           T.Rule,
   235  		Authentication: []string{},
   236  		LogLevel:       log.INFO,
   237  		Hosts:          map[string]string{},
   238  		Rule:           []string{},
   239  		Proxy:          []map[string]any{},
   240  		ProxyGroup:     []map[string]any{},
   241  		DNS: RawDNS{
   242  			Enable:      false,
   243  			UseHosts:    true,
   244  			FakeIPRange: "198.18.0.1/16",
   245  			FallbackFilter: RawFallbackFilter{
   246  				GeoIP:     true,
   247  				GeoIPCode: "CN",
   248  				IPCIDR:    []string{},
   249  			},
   250  			DefaultNameserver: []string{
   251  				"114.114.114.114",
   252  				"8.8.8.8",
   253  			},
   254  		},
   255  		Profile: Profile{
   256  			StoreSelected: true,
   257  		},
   258  	}
   259  
   260  	if err := yaml.Unmarshal(buf, rawCfg); err != nil {
   261  		return nil, err
   262  	}
   263  
   264  	return rawCfg, nil
   265  }
   266  
   267  func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
   268  	config := &Config{}
   269  
   270  	config.Experimental = &rawCfg.Experimental
   271  	config.Profile = &rawCfg.Profile
   272  
   273  	general, err := parseGeneral(rawCfg)
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  	config.General = general
   278  
   279  	config.Inbounds = rawCfg.Inbounds
   280  
   281  	proxies, providers, err := parseProxies(rawCfg)
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  	config.Proxies = proxies
   286  	config.Providers = providers
   287  
   288  	rules, err := parseRules(rawCfg, proxies)
   289  	if err != nil {
   290  		return nil, err
   291  	}
   292  	config.Rules = rules
   293  
   294  	hosts, err := parseHosts(rawCfg)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	config.Hosts = hosts
   299  
   300  	dnsCfg, err := parseDNS(rawCfg, hosts)
   301  	if err != nil {
   302  		return nil, err
   303  	}
   304  	config.DNS = dnsCfg
   305  
   306  	config.Users = parseAuthentication(rawCfg.Authentication)
   307  
   308  	config.Tunnels = rawCfg.Tunnels
   309  	// verify tunnels
   310  	for _, t := range config.Tunnels {
   311  		if _, ok := config.Proxies[t.Proxy]; !ok {
   312  			return nil, fmt.Errorf("tunnel proxy %s not found", t.Proxy)
   313  		}
   314  	}
   315  
   316  	return config, nil
   317  }
   318  
   319  func parseGeneral(cfg *RawConfig) (*General, error) {
   320  	externalUI := cfg.ExternalUI
   321  
   322  	// checkout externalUI exist
   323  	if externalUI != "" {
   324  		externalUI = C.Path.Resolve(externalUI)
   325  
   326  		if _, err := os.Stat(externalUI); os.IsNotExist(err) {
   327  			return nil, fmt.Errorf("external-ui: %s not exist", externalUI)
   328  		}
   329  	}
   330  
   331  	return &General{
   332  		LegacyInbound: LegacyInbound{
   333  			Port:        cfg.Port,
   334  			SocksPort:   cfg.SocksPort,
   335  			RedirPort:   cfg.RedirPort,
   336  			TProxyPort:  cfg.TProxyPort,
   337  			MixedPort:   cfg.MixedPort,
   338  			AllowLan:    cfg.AllowLan,
   339  			BindAddress: cfg.BindAddress,
   340  		},
   341  		Controller: Controller{
   342  			ExternalController: cfg.ExternalController,
   343  			ExternalUI:         cfg.ExternalUI,
   344  			Secret:             cfg.Secret,
   345  		},
   346  		Mode:        cfg.Mode,
   347  		LogLevel:    cfg.LogLevel,
   348  		IPv6:        cfg.IPv6,
   349  		Interface:   cfg.Interface,
   350  		RoutingMark: cfg.RoutingMark,
   351  	}, nil
   352  }
   353  
   354  func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
   355  	proxies = make(map[string]C.Proxy)
   356  	providersMap = make(map[string]providerTypes.ProxyProvider)
   357  	proxyList := []string{}
   358  	proxiesConfig := cfg.Proxy
   359  	groupsConfig := cfg.ProxyGroup
   360  	providersConfig := cfg.ProxyProvider
   361  
   362  	proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
   363  	proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
   364  	proxyList = append(proxyList, "DIRECT", "REJECT")
   365  
   366  	// parse proxy
   367  	for idx, mapping := range proxiesConfig {
   368  		proxy, err := adapter.ParseProxy(mapping)
   369  		if err != nil {
   370  			return nil, nil, fmt.Errorf("proxy %d: %w", idx, err)
   371  		}
   372  
   373  		if _, exist := proxies[proxy.Name()]; exist {
   374  			return nil, nil, fmt.Errorf("proxy %s is the duplicate name", proxy.Name())
   375  		}
   376  		proxies[proxy.Name()] = proxy
   377  		proxyList = append(proxyList, proxy.Name())
   378  	}
   379  
   380  	// keep the original order of ProxyGroups in config file
   381  	for idx, mapping := range groupsConfig {
   382  		groupName, existName := mapping["name"].(string)
   383  		if !existName {
   384  			return nil, nil, fmt.Errorf("proxy group %d: missing name", idx)
   385  		}
   386  		proxyList = append(proxyList, groupName)
   387  	}
   388  
   389  	// check if any loop exists and sort the ProxyGroups
   390  	if err := proxyGroupsDagSort(groupsConfig); err != nil {
   391  		return nil, nil, err
   392  	}
   393  
   394  	// parse and initial providers
   395  	for name, mapping := range providersConfig {
   396  		if name == provider.ReservedName {
   397  			return nil, nil, fmt.Errorf("can not defined a provider called `%s`", provider.ReservedName)
   398  		}
   399  
   400  		pd, err := provider.ParseProxyProvider(name, mapping)
   401  		if err != nil {
   402  			return nil, nil, fmt.Errorf("parse proxy provider %s error: %w", name, err)
   403  		}
   404  
   405  		providersMap[name] = pd
   406  	}
   407  
   408  	for _, provider := range providersMap {
   409  		log.Infoln("Start initial provider %s", provider.Name())
   410  		if err := provider.Initial(); err != nil {
   411  			return nil, nil, fmt.Errorf("initial proxy provider %s error: %w", provider.Name(), err)
   412  		}
   413  	}
   414  
   415  	// parse proxy group
   416  	for idx, mapping := range groupsConfig {
   417  		group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap)
   418  		if err != nil {
   419  			return nil, nil, fmt.Errorf("proxy group[%d]: %w", idx, err)
   420  		}
   421  
   422  		groupName := group.Name()
   423  		if _, exist := proxies[groupName]; exist {
   424  			return nil, nil, fmt.Errorf("proxy group %s: the duplicate name", groupName)
   425  		}
   426  
   427  		proxies[groupName] = adapter.NewProxy(group)
   428  	}
   429  
   430  	// initial compatible provider
   431  	for _, pd := range providersMap {
   432  		if pd.VehicleType() != providerTypes.Compatible {
   433  			continue
   434  		}
   435  
   436  		log.Infoln("Start initial compatible provider %s", pd.Name())
   437  		if err := pd.Initial(); err != nil {
   438  			return nil, nil, err
   439  		}
   440  	}
   441  
   442  	ps := []C.Proxy{}
   443  	for _, v := range proxyList {
   444  		ps = append(ps, proxies[v])
   445  	}
   446  	hc := provider.NewHealthCheck(ps, "", 0, true)
   447  	pd, _ := provider.NewCompatibleProvider(provider.ReservedName, ps, hc)
   448  	providersMap[provider.ReservedName] = pd
   449  
   450  	global := outboundgroup.NewSelector(
   451  		&outboundgroup.GroupCommonOption{
   452  			Name: "GLOBAL",
   453  		},
   454  		[]providerTypes.ProxyProvider{pd},
   455  	)
   456  	proxies["GLOBAL"] = adapter.NewProxy(global)
   457  	return proxies, providersMap, nil
   458  }
   459  
   460  func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, error) {
   461  	rules := []C.Rule{}
   462  	rulesConfig := cfg.Rule
   463  
   464  	// parse rules
   465  	for idx, line := range rulesConfig {
   466  		rule := trimArr(strings.Split(line, ","))
   467  		var (
   468  			payload string
   469  			target  string
   470  			params  = []string{}
   471  		)
   472  
   473  		switch l := len(rule); {
   474  		case l == 2:
   475  			target = rule[1]
   476  		case l == 3:
   477  			payload = rule[1]
   478  			target = rule[2]
   479  		case l >= 4:
   480  			payload = rule[1]
   481  			target = rule[2]
   482  			params = rule[3:]
   483  		default:
   484  			return nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
   485  		}
   486  
   487  		if _, ok := proxies[target]; !ok {
   488  			return nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
   489  		}
   490  
   491  		rule = trimArr(rule)
   492  		params = trimArr(params)
   493  
   494  		parsed, parseErr := R.ParseRule(rule[0], payload, target, params)
   495  		if parseErr != nil {
   496  			return nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
   497  		}
   498  
   499  		rules = append(rules, parsed)
   500  	}
   501  
   502  	return rules, nil
   503  }
   504  
   505  func parseHosts(cfg *RawConfig) (*trie.DomainTrie, error) {
   506  	tree := trie.New()
   507  
   508  	// add default hosts
   509  	if err := tree.Insert("localhost", net.IP{127, 0, 0, 1}); err != nil {
   510  		log.Errorln("insert localhost to host error: %s", err.Error())
   511  	}
   512  
   513  	if len(cfg.Hosts) != 0 {
   514  		for domain, ipStr := range cfg.Hosts {
   515  			ip := net.ParseIP(ipStr)
   516  			if ip == nil {
   517  				return nil, fmt.Errorf("%s is not a valid IP", ipStr)
   518  			}
   519  			tree.Insert(domain, ip)
   520  		}
   521  	}
   522  
   523  	return tree, nil
   524  }
   525  
   526  func hostWithDefaultPort(host string, defPort string) (string, error) {
   527  	if !strings.Contains(host, ":") {
   528  		host += ":"
   529  	}
   530  
   531  	hostname, port, err := net.SplitHostPort(host)
   532  	if err != nil {
   533  		return "", err
   534  	}
   535  
   536  	if port == "" {
   537  		port = defPort
   538  	}
   539  
   540  	return net.JoinHostPort(hostname, port), nil
   541  }
   542  
   543  func parseNameServer(servers []string) ([]dns.NameServer, error) {
   544  	nameservers := []dns.NameServer{}
   545  
   546  	for idx, server := range servers {
   547  		// parse without scheme .e.g 8.8.8.8:53
   548  		if !strings.Contains(server, "://") {
   549  			server = "udp://" + server
   550  		}
   551  		u, err := url.Parse(server)
   552  		if err != nil {
   553  			return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error())
   554  		}
   555  
   556  		// parse with specific interface
   557  		// .e.g 10.0.0.1#en0
   558  		interfaceName := u.Fragment
   559  
   560  		var addr, dnsNetType string
   561  		switch u.Scheme {
   562  		case "udp":
   563  			addr, err = hostWithDefaultPort(u.Host, "53")
   564  			dnsNetType = "" // UDP
   565  		case "tcp":
   566  			addr, err = hostWithDefaultPort(u.Host, "53")
   567  			dnsNetType = "tcp" // TCP
   568  		case "tls":
   569  			addr, err = hostWithDefaultPort(u.Host, "853")
   570  			dnsNetType = "tcp-tls" // DNS over TLS
   571  		case "https":
   572  			clearURL := url.URL{Scheme: "https", Host: u.Host, Path: u.Path, User: u.User}
   573  			addr = clearURL.String()
   574  			dnsNetType = "https" // DNS over HTTPS
   575  		case "dhcp":
   576  			addr = u.Host
   577  			dnsNetType = "dhcp" // UDP from DHCP
   578  		default:
   579  			return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme)
   580  		}
   581  
   582  		if err != nil {
   583  			return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error())
   584  		}
   585  
   586  		nameservers = append(
   587  			nameservers,
   588  			dns.NameServer{
   589  				Net:       dnsNetType,
   590  				Addr:      addr,
   591  				Interface: interfaceName,
   592  			},
   593  		)
   594  	}
   595  	return nameservers, nil
   596  }
   597  
   598  func parseNameServerPolicy(nsPolicy map[string]string) (map[string]dns.NameServer, error) {
   599  	policy := map[string]dns.NameServer{}
   600  
   601  	for domain, server := range nsPolicy {
   602  		nameservers, err := parseNameServer([]string{server})
   603  		if err != nil {
   604  			return nil, err
   605  		}
   606  		if _, valid := trie.ValidAndSplitDomain(domain); !valid {
   607  			return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
   608  		}
   609  		policy[domain] = nameservers[0]
   610  	}
   611  
   612  	return policy, nil
   613  }
   614  
   615  func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
   616  	ipNets := []*net.IPNet{}
   617  
   618  	for idx, ip := range ips {
   619  		_, ipnet, err := net.ParseCIDR(ip)
   620  		if err != nil {
   621  			return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error())
   622  		}
   623  		ipNets = append(ipNets, ipnet)
   624  	}
   625  
   626  	return ipNets, nil
   627  }
   628  
   629  func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie) (*DNS, error) {
   630  	cfg := rawCfg.DNS
   631  	if cfg.Enable && len(cfg.NameServer) == 0 {
   632  		return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
   633  	}
   634  
   635  	dnsCfg := &DNS{
   636  		Enable:       cfg.Enable,
   637  		Listen:       cfg.Listen,
   638  		IPv6:         lo.FromPtrOr(cfg.IPv6, rawCfg.IPv6),
   639  		EnhancedMode: cfg.EnhancedMode,
   640  		FallbackFilter: FallbackFilter{
   641  			IPCIDR: []*net.IPNet{},
   642  		},
   643  	}
   644  	var err error
   645  	if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer); err != nil {
   646  		return nil, err
   647  	}
   648  
   649  	if dnsCfg.Fallback, err = parseNameServer(cfg.Fallback); err != nil {
   650  		return nil, err
   651  	}
   652  
   653  	if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy); err != nil {
   654  		return nil, err
   655  	}
   656  
   657  	if len(cfg.DefaultNameserver) == 0 {
   658  		return nil, errors.New("default nameserver should have at least one nameserver")
   659  	}
   660  	if dnsCfg.DefaultNameserver, err = parseNameServer(cfg.DefaultNameserver); err != nil {
   661  		return nil, err
   662  	}
   663  	// check default nameserver is pure ip addr
   664  	for _, ns := range dnsCfg.DefaultNameserver {
   665  		host, _, err := net.SplitHostPort(ns.Addr)
   666  		if err != nil || net.ParseIP(host) == nil {
   667  			return nil, errors.New("default nameserver should be pure IP")
   668  		}
   669  	}
   670  
   671  	if cfg.EnhancedMode == C.DNSFakeIP {
   672  		_, ipnet, err := net.ParseCIDR(cfg.FakeIPRange)
   673  		if err != nil {
   674  			return nil, err
   675  		}
   676  
   677  		var host *trie.DomainTrie
   678  		// fake ip skip host filter
   679  		if len(cfg.FakeIPFilter) != 0 {
   680  			host = trie.New()
   681  			for _, domain := range cfg.FakeIPFilter {
   682  				host.Insert(domain, true)
   683  			}
   684  		}
   685  
   686  		pool, err := fakeip.New(fakeip.Options{
   687  			IPNet:       ipnet,
   688  			Size:        1000,
   689  			Host:        host,
   690  			Persistence: rawCfg.Profile.StoreFakeIP,
   691  		})
   692  		if err != nil {
   693  			return nil, err
   694  		}
   695  
   696  		dnsCfg.FakeIPRange = pool
   697  	}
   698  
   699  	dnsCfg.FallbackFilter.GeoIP = cfg.FallbackFilter.GeoIP
   700  	dnsCfg.FallbackFilter.GeoIPCode = cfg.FallbackFilter.GeoIPCode
   701  	if fallbackip, err := parseFallbackIPCIDR(cfg.FallbackFilter.IPCIDR); err == nil {
   702  		dnsCfg.FallbackFilter.IPCIDR = fallbackip
   703  	}
   704  	dnsCfg.FallbackFilter.Domain = cfg.FallbackFilter.Domain
   705  
   706  	if cfg.UseHosts {
   707  		dnsCfg.Hosts = hosts
   708  	}
   709  
   710  	if len(cfg.SearchDomains) != 0 {
   711  		for _, domain := range cfg.SearchDomains {
   712  			if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") {
   713  				return nil, errors.New("search domains should not start or end with '.'")
   714  			}
   715  			if strings.Contains(domain, ":") {
   716  				return nil, errors.New("search domains are for ipv4 only and should not contain ports")
   717  			}
   718  		}
   719  		dnsCfg.SearchDomains = cfg.SearchDomains
   720  	}
   721  
   722  	return dnsCfg, nil
   723  }
   724  
   725  func parseAuthentication(rawRecords []string) []auth.AuthUser {
   726  	users := []auth.AuthUser{}
   727  	for _, line := range rawRecords {
   728  		if user, pass, found := strings.Cut(line, ":"); found {
   729  			users = append(users, auth.AuthUser{User: user, Pass: pass})
   730  		}
   731  	}
   732  	return users
   733  }