...

Source file src/github.com/miekg/dns/clientconfig.go

Documentation: github.com/miekg/dns

     1  package dns
     2  
     3  import (
     4  	"bufio"
     5  	"io"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  )
    10  
    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
    19  }
    20  
    21  // ClientConfigFromFile parses a resolv.conf(5) like file and returns
    22  // a *ClientConfig.
    23  func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
    24  	file, err := os.Open(resolvconf)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	defer file.Close()
    29  	return ClientConfigFromReader(file)
    30  }
    31  
    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)
    38  	c.Port = "53"
    39  	c.Ndots = 1
    40  	c.Timeout = 5
    41  	c.Attempts = 2
    42  
    43  	for scanner.Scan() {
    44  		if err := scanner.Err(); err != nil {
    45  			return nil, err
    46  		}
    47  		line := scanner.Text()
    48  		f := strings.Fields(line)
    49  		if len(f) < 1 {
    50  			continue
    51  		}
    52  		switch f[0] {
    53  		case "nameserver": // add one name server
    54  			if len(f) > 1 {
    55  				// One more check: make sure server name is
    56  				// just an IP address.  Otherwise we need DNS
    57  				// to look it up.
    58  				name := f[1]
    59  				c.Servers = append(c.Servers, name)
    60  			}
    61  
    62  		case "domain": // set search path to just this domain
    63  			if len(f) > 1 {
    64  				c.Search = make([]string, 1)
    65  				c.Search[0] = f[1]
    66  			} else {
    67  				c.Search = make([]string, 0)
    68  			}
    69  
    70  		case "search": // set search path to given servers
    71  			c.Search = cloneSlice(f[1:])
    72  
    73  		case "options": // magic options
    74  			for _, s := range f[1:] {
    75  				switch {
    76  				case len(s) >= 6 && s[:6] == "ndots:":
    77  					n, _ := strconv.Atoi(s[6:])
    78  					if n < 0 {
    79  						n = 0
    80  					} else if n > 15 {
    81  						n = 15
    82  					}
    83  					c.Ndots = n
    84  				case len(s) >= 8 && s[:8] == "timeout:":
    85  					n, _ := strconv.Atoi(s[8:])
    86  					if n < 1 {
    87  						n = 1
    88  					}
    89  					c.Timeout = n
    90  				case len(s) >= 9 && s[:9] == "attempts:":
    91  					n, _ := strconv.Atoi(s[9:])
    92  					if n < 1 {
    93  						n = 1
    94  					}
    95  					c.Attempts = n
    96  				case s == "rotate":
    97  					/* not imp */
    98  				}
    99  			}
   100  		}
   101  	}
   102  	return c, nil
   103  }
   104  
   105  // NameList returns all of the names that should be queried based on the
   106  // config. It is based off of go's net/dns name building, but it does not
   107  // check the length of the resulting names.
   108  func (c *ClientConfig) NameList(name string) []string {
   109  	// if this domain is already fully qualified, no append needed.
   110  	if IsFqdn(name) {
   111  		return []string{name}
   112  	}
   113  
   114  	// Check to see if the name has more labels than Ndots. Do this before making
   115  	// the domain fully qualified.
   116  	hasNdots := CountLabel(name) > c.Ndots
   117  	// Make the domain fully qualified.
   118  	name = Fqdn(name)
   119  
   120  	// Make a list of names based off search.
   121  	names := []string{}
   122  
   123  	// If name has enough dots, try that first.
   124  	if hasNdots {
   125  		names = append(names, name)
   126  	}
   127  	for _, s := range c.Search {
   128  		names = append(names, Fqdn(name+s))
   129  	}
   130  	// If we didn't have enough dots, try after suffixes.
   131  	if !hasNdots {
   132  		names = append(names, name)
   133  	}
   134  	return names
   135  }
   136  

View as plain text