1package dns
2
3import (
4	"bufio"
5	"os"
6	"strconv"
7	"strings"
8)
9
10// ClientConfig wraps the contents of the /etc/resolv.conf file.
11type ClientConfig struct {
12	Servers  []string // servers to use
13	Search   []string // suffixes to append to local name
14	Port     string   // what port to use
15	Ndots    int      // number of dots in name to trigger absolute lookup
16	Timeout  int      // seconds before giving up on packet
17	Attempts int      // lost packets before giving up on server, not used in the package dns
18}
19
20// ClientConfigFromFile parses a resolv.conf(5) like file and returns
21// a *ClientConfig.
22func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
23	file, err := os.Open(resolvconf)
24	if err != nil {
25		return nil, err
26	}
27	defer file.Close()
28	c := new(ClientConfig)
29	scanner := bufio.NewScanner(file)
30	c.Servers = make([]string, 0)
31	c.Search = make([]string, 0)
32	c.Port = "53"
33	c.Ndots = 1
34	c.Timeout = 5
35	c.Attempts = 2
36
37	for scanner.Scan() {
38		if err := scanner.Err(); err != nil {
39			return nil, err
40		}
41		line := scanner.Text()
42		f := strings.Fields(line)
43		if len(f) < 1 {
44			continue
45		}
46		switch f[0] {
47		case "nameserver": // add one name server
48			if len(f) > 1 {
49				// One more check: make sure server name is
50				// just an IP address.  Otherwise we need DNS
51				// to look it up.
52				name := f[1]
53				c.Servers = append(c.Servers, name)
54			}
55
56		case "domain": // set search path to just this domain
57			if len(f) > 1 {
58				c.Search = make([]string, 1)
59				c.Search[0] = f[1]
60			} else {
61				c.Search = make([]string, 0)
62			}
63
64		case "search": // set search path to given servers
65			c.Search = make([]string, len(f)-1)
66			for i := 0; i < len(c.Search); i++ {
67				c.Search[i] = f[i+1]
68			}
69
70		case "options": // magic options
71			for i := 1; i < len(f); i++ {
72				s := f[i]
73				switch {
74				case len(s) >= 6 && s[:6] == "ndots:":
75					n, _ := strconv.Atoi(s[6:])
76					if n < 1 {
77						n = 1
78					}
79					c.Ndots = n
80				case len(s) >= 8 && s[:8] == "timeout:":
81					n, _ := strconv.Atoi(s[8:])
82					if n < 1 {
83						n = 1
84					}
85					c.Timeout = n
86				case len(s) >= 8 && s[:9] == "attempts:":
87					n, _ := strconv.Atoi(s[9:])
88					if n < 1 {
89						n = 1
90					}
91					c.Attempts = n
92				case s == "rotate":
93					/* not imp */
94				}
95			}
96		}
97	}
98	return c, nil
99}
100