11 // ClientConfig wraps the contents of the /etc/resolv.conf file.
12 type ClientConfig struct {
13 Servers []string // servers to use
14 Search []string // suffixes to append to local name
15 Port string // what port to use
16 Ndots int // number of dots in name to trigger absolute lookup
17 Timeout int // seconds before giving up on packet
18 Attempts int // lost packets before giving up on server, not used in the package dns
21 // ClientConfigFromFile parses a resolv.conf(5) like file and returns
23 func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
24 file, err := os.Open(resolvconf)
29 return ClientConfigFromReader(file)
32 // ClientConfigFromReader works like ClientConfigFromFile but takes an io.Reader as argument
33 func ClientConfigFromReader(resolvconf io.Reader) (*ClientConfig, error) {
34 c := new(ClientConfig)
35 scanner := bufio.NewScanner(resolvconf)
36 c.Servers = make([]string, 0)
37 c.Search = make([]string, 0)
44 if err := scanner.Err(); err != nil {
47 line := scanner.Text()
48 f := strings.Fields(line)
53 case "nameserver": // add one name server
55 // One more check: make sure server name is
56 // just an IP address. Otherwise we need DNS
59 c.Servers = append(c.Servers, name)
62 case "domain": // set search path to just this domain
64 c.Search = make([]string, 1)
67 c.Search = make([]string, 0)
70 case "search": // set search path to given servers
71 c.Search = make([]string, len(f)-1)
72 for i := 0; i < len(c.Search); i++ {
76 case "options": // magic options
77 for i := 1; i < len(f); i++ {
80 case len(s) >= 6 && s[:6] == "ndots:":
81 n, _ := strconv.Atoi(s[6:])
88 case len(s) >= 8 && s[:8] == "timeout:":
89 n, _ := strconv.Atoi(s[8:])
94 case len(s) >= 9 && s[:9] == "attempts:":
95 n, _ := strconv.Atoi(s[9:])
109 // NameList returns all of the names that should be queried based on the
110 // config. It is based off of go's net/dns name building, but it does not
111 // check the length of the resulting names.
112 func (c *ClientConfig) NameList(name string) []string {
113 // if this domain is already fully qualified, no append needed.
115 return []string{name}
118 // Check to see if the name has more labels than Ndots. Do this before making
119 // the domain fully qualified.
120 hasNdots := CountLabel(name) > c.Ndots
121 // Make the domain fully qualified.
124 // Make a list of names based off search.
127 // If name has enough dots, try that first.
129 names = append(names, name)
131 for _, s := range c.Search {
132 names = append(names, Fqdn(name+s))
134 // If we didn't have enough dots, try after suffixes.
136 names = append(names, name)