Files

151 lines
3.7 KiB
Go

package resolver
import (
"os"
"strings"
)
type DNSConfig struct {
Default []string
Meta []string
SmartDNS string
Mode string
}
type DNSConfigDeps struct {
ActivePool []string
IsSmartDNSForced bool
SmartDNSAddr string
SmartDNSForcedMode string
ResolveFallbackPool func() []string
MergeDNSUpstreamPools func(primary, fallback []string) []string
NormalizeDNSUpstream func(raw string, defaultPort string) string
NormalizeSmartDNSAddr func(raw string) string
NormalizeDNSResolverMode func(raw string) string
}
func LoadDNSConfig(path string, base DNSConfig, deps DNSConfigDeps, logf func(string, ...any)) DNSConfig {
cfg := DNSConfig{
Default: append([]string(nil), base.Default...),
Meta: append([]string(nil), base.Meta...),
SmartDNS: strings.TrimSpace(base.SmartDNS),
Mode: strings.TrimSpace(base.Mode),
}
if cfg.Mode == "" {
cfg.Mode = "direct"
}
if len(deps.ActivePool) > 0 {
cfg.Default = append([]string(nil), deps.ActivePool...)
cfg.Meta = append([]string(nil), deps.ActivePool...)
}
if deps.IsSmartDNSForced {
addr := strings.TrimSpace(deps.SmartDNSAddr)
if deps.NormalizeSmartDNSAddr != nil {
if n := deps.NormalizeSmartDNSAddr(addr); n != "" {
addr = n
}
}
if addr == "" {
addr = cfg.SmartDNS
}
cfg.Default = []string{addr}
cfg.Meta = []string{addr}
cfg.SmartDNS = addr
if strings.TrimSpace(deps.SmartDNSForcedMode) != "" {
cfg.Mode = deps.SmartDNSForcedMode
} else {
cfg.Mode = "smartdns"
}
if logf != nil {
logf("dns-config: SmartDNS forced (%s), ignore %s", addr, path)
}
return cfg
}
data, err := os.ReadFile(path)
if err != nil {
if logf != nil {
logf("dns-config: can't read %s: %v", path, err)
}
fallback := []string(nil)
if deps.ResolveFallbackPool != nil {
fallback = deps.ResolveFallbackPool()
}
if deps.MergeDNSUpstreamPools != nil {
cfg.Default = deps.MergeDNSUpstreamPools(cfg.Default, fallback)
cfg.Meta = deps.MergeDNSUpstreamPools(cfg.Meta, fallback)
}
return cfg
}
var def, meta []string
lines := strings.Split(string(data), "\n")
for _, ln := range lines {
s := strings.TrimSpace(ln)
if s == "" || strings.HasPrefix(s, "#") {
continue
}
parts := strings.Fields(s)
if len(parts) < 2 {
continue
}
key := strings.ToLower(parts[0])
vals := parts[1:]
switch key {
case "default":
for _, v := range vals {
if deps.NormalizeDNSUpstream != nil {
if n := deps.NormalizeDNSUpstream(v, "53"); n != "" {
def = append(def, n)
}
}
}
case "meta":
for _, v := range vals {
if deps.NormalizeDNSUpstream != nil {
if n := deps.NormalizeDNSUpstream(v, "53"); n != "" {
meta = append(meta, n)
}
}
}
case "smartdns":
if len(vals) > 0 && deps.NormalizeSmartDNSAddr != nil {
if n := deps.NormalizeSmartDNSAddr(vals[0]); n != "" {
cfg.SmartDNS = n
}
}
case "mode":
if len(vals) > 0 {
rawMode := vals[0]
if deps.NormalizeDNSResolverMode != nil {
cfg.Mode = deps.NormalizeDNSResolverMode(rawMode)
} else {
cfg.Mode = strings.ToLower(strings.TrimSpace(rawMode))
}
}
}
}
if len(deps.ActivePool) == 0 {
if len(def) > 0 {
cfg.Default = def
}
if len(meta) > 0 {
cfg.Meta = meta
}
}
fallback := []string(nil)
if deps.ResolveFallbackPool != nil {
fallback = deps.ResolveFallbackPool()
}
if deps.MergeDNSUpstreamPools != nil {
cfg.Default = deps.MergeDNSUpstreamPools(cfg.Default, fallback)
cfg.Meta = deps.MergeDNSUpstreamPools(cfg.Meta, fallback)
}
if logf != nil {
logf("dns-config: accept %s: mode=%s smartdns=%s default=%v; meta=%v", path, cfg.Mode, cfg.SmartDNS, cfg.Default, cfg.Meta)
}
return cfg
}