123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- //go:build !windows
- package local
- import (
- "bufio"
- "net"
- "net/netip"
- "os"
- "strings"
- "time"
- _ "unsafe"
- )
- func dnsReadConfig(name string) *dnsConfig {
- conf := &dnsConfig{
- ndots: 1,
- timeout: 5 * time.Second,
- attempts: 2,
- }
- file, err := os.Open(name)
- if err != nil {
- conf.servers = defaultNS
- conf.search = dnsDefaultSearch()
- conf.err = err
- return conf
- }
- defer file.Close()
- fi, err := file.Stat()
- if err == nil {
- conf.mtime = fi.ModTime()
- } else {
- conf.servers = defaultNS
- conf.search = dnsDefaultSearch()
- conf.err = err
- return conf
- }
- reader := bufio.NewReader(file)
- var (
- prefix []byte
- line []byte
- isPrefix bool
- )
- for {
- line, isPrefix, err = reader.ReadLine()
- if err != nil {
- break
- }
- if isPrefix {
- prefix = append(prefix, line...)
- continue
- } else if len(prefix) > 0 {
- line = append(prefix, line...)
- prefix = nil
- }
- if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
- continue
- }
- f := strings.Fields(string(line))
- if len(f) < 1 {
- continue
- }
- switch f[0] {
- case "nameserver":
- if len(f) > 1 && len(conf.servers) < 3 {
- if _, err := netip.ParseAddr(f[1]); err == nil {
- conf.servers = append(conf.servers, net.JoinHostPort(f[1], "53"))
- }
- }
- case "domain":
- if len(f) > 1 {
- conf.search = []string{ensureRooted(f[1])}
- }
- case "search":
- conf.search = make([]string, 0, len(f)-1)
- for i := 1; i < len(f); i++ {
- name := ensureRooted(f[i])
- if name == "." {
- continue
- }
- conf.search = append(conf.search, name)
- }
- case "options":
- for _, s := range f[1:] {
- switch {
- case strings.HasPrefix(s, "ndots:"):
- n, _, _ := dtoi(s[6:])
- if n < 0 {
- n = 0
- } else if n > 15 {
- n = 15
- }
- conf.ndots = n
- case strings.HasPrefix(s, "timeout:"):
- n, _, _ := dtoi(s[8:])
- if n < 1 {
- n = 1
- }
- conf.timeout = time.Duration(n) * time.Second
- case strings.HasPrefix(s, "attempts:"):
- n, _, _ := dtoi(s[9:])
- if n < 1 {
- n = 1
- }
- conf.attempts = n
- case s == "rotate":
- conf.rotate = true
- case s == "single-request" || s == "single-request-reopen":
- conf.singleRequest = true
- case s == "use-vc" || s == "usevc" || s == "tcp":
- conf.useTCP = true
- case s == "trust-ad":
- conf.trustAD = true
- case s == "edns0":
- case s == "no-reload":
- conf.noReload = true
- default:
- conf.unknownOpt = true
- }
- }
- case "lookup":
- conf.lookup = f[1:]
- default:
- conf.unknownOpt = true
- }
- }
- if len(conf.servers) == 0 {
- conf.servers = defaultNS
- }
- if len(conf.search) == 0 {
- conf.search = dnsDefaultSearch()
- }
- return conf
- }
- //go:linkname defaultNS net.defaultNS
- var defaultNS []string
- func dnsDefaultSearch() []string {
- hn, err := os.Hostname()
- if err != nil {
- return nil
- }
- if i := strings.IndexRune(hn, '.'); i >= 0 && i < len(hn)-1 {
- return []string{ensureRooted(hn[i+1:])}
- }
- return nil
- }
- func ensureRooted(s string) string {
- if len(s) > 0 && s[len(s)-1] == '.' {
- return s
- }
- return s + "."
- }
- const big = 0xFFFFFF
- func dtoi(s string) (n int, i int, ok bool) {
- n = 0
- for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
- n = n*10 + int(s[i]-'0')
- if n >= big {
- return big, i, false
- }
- }
- if i == 0 {
- return 0, 0, false
- }
- return n, i, true
- }
|