151 lines
3.7 KiB
Go
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
|
|
}
|