From d6931ec491dfad55d2043caddcef242939f536dc Mon Sep 17 00:00:00 2001 From: sleshep <9625413+sleshep@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:57:55 +0800 Subject: [PATCH] feat: support system dns --- config/config.go | 4 +++- dns/system.go | 39 +++++++++++++++++++++++++++++++++++++++ dns/system_windows.go | 7 +++++++ dns/util.go | 8 ++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 dns/system.go create mode 100644 dns/system_windows.go diff --git a/config/config.go b/config/config.go index 71f4087e..35929849 100644 --- a/config/config.go +++ b/config/config.go @@ -841,7 +841,7 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { } else { ips := make([]netip.Addr, 0) for _, addr := range addrs { - if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback()&&!ipnet.IP.IsLinkLocalUnicast() { + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsLinkLocalUnicast() { if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil { ips = append(ips, ip) } @@ -938,6 +938,8 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) case "quic": addr, err = hostWithDefaultPort(u.Host, "853") dnsNetType = "quic" // DNS over QUIC + case "system": + dnsNetType = "system" // System DNS default: return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme) } diff --git a/dns/system.go b/dns/system.go new file mode 100644 index 00000000..2e52f90f --- /dev/null +++ b/dns/system.go @@ -0,0 +1,39 @@ +//go:build !windows + +package dns + +import ( + "fmt" + "os" + "regexp" +) + +var ( + // nameserver xxx.xxx.xxx.xxx + nameserverPattern = regexp.MustCompile(`nameserver\s+(?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`) +) + +func loadSystemResolver() (clients []dnsClient, err error) { + content, err := os.ReadFile("/etc/resolv.conf") + if err != nil { + err = fmt.Errorf("failed to read /etc/resolv.conf: %w", err) + return + } + nameservers := make([]string, 0) + for _, line := range nameserverPattern.FindAllStringSubmatch(string(content), -1) { + addr := line[1] + nameservers = append(nameservers, addr) + } + if len(nameservers) == 0 { + err = fmt.Errorf("no nameserver found in /etc/resolv.conf") + return + } + servers := make([]NameServer, 0, len(nameservers)) + for _, addr := range nameservers { + servers = append(servers, NameServer{ + Addr: fmt.Sprintf("%s:%d", addr, 53), + Net: "udp", + }) + } + return transform(servers, nil), nil +} diff --git a/dns/system_windows.go b/dns/system_windows.go new file mode 100644 index 00000000..3334af96 --- /dev/null +++ b/dns/system_windows.go @@ -0,0 +1,7 @@ +//go:build windows + +package dns + +func loadSystemResolver() (clients []dnsClient, err error) { + return nil, errors.New("system resolver is not yet supported on Windows") +} diff --git a/dns/util.go b/dns/util.go index bfd2e9ed..948687ac 100644 --- a/dns/util.go +++ b/dns/util.go @@ -79,6 +79,14 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { case "dhcp": ret = append(ret, newDHCPClient(s.Addr)) continue + case "system": + clients, err := loadSystemResolver() + if err != nil { + log.Warnln("[DNS:system] load system resolver failed: %s", err.Error()) + continue + } + ret = append(ret, clients...) + continue case "quic": if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil { ret = append(ret, doq)