github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/net/lookup_windows_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package net
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/json"
    10  	"errors"
    11  	"os/exec"
    12  	"reflect"
    13  	"regexp"
    14  	"sort"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  var nslookupTestServers = []string{"mail.golang.com", "gmail.com"}
    20  
    21  func toJson(v interface{}) string {
    22  	data, _ := json.Marshal(v)
    23  	return string(data)
    24  }
    25  
    26  func TestLookupMX(t *testing.T) {
    27  	if testing.Short() || !*testExternal {
    28  		t.Skip("avoid external network")
    29  	}
    30  
    31  	for _, server := range nslookupTestServers {
    32  		mx, err := LookupMX(server)
    33  		if err != nil {
    34  			t.Error(err)
    35  			continue
    36  		}
    37  		if len(mx) == 0 {
    38  			t.Errorf("no results")
    39  			continue
    40  		}
    41  		expected, err := nslookupMX(server)
    42  		if err != nil {
    43  			t.Logf("skipping failed nslookup %s test: %s", server, err)
    44  		}
    45  		sort.Sort(byPrefAndHost(expected))
    46  		sort.Sort(byPrefAndHost(mx))
    47  		if !reflect.DeepEqual(expected, mx) {
    48  			t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(mx))
    49  		}
    50  	}
    51  }
    52  
    53  func TestLookupCNAME(t *testing.T) {
    54  	if testing.Short() || !*testExternal {
    55  		t.Skip("avoid external network")
    56  	}
    57  
    58  	for _, server := range nslookupTestServers {
    59  		cname, err := LookupCNAME(server)
    60  		if err != nil {
    61  			t.Errorf("failed %s: %s", server, err)
    62  			continue
    63  		}
    64  		if cname == "" {
    65  			t.Errorf("no result %s", server)
    66  		}
    67  		expected, err := nslookupCNAME(server)
    68  		if err != nil {
    69  			t.Logf("skipping failed nslookup %s test: %s", server, err)
    70  			continue
    71  		}
    72  		if expected != cname {
    73  			t.Errorf("different results %s:\texp:%v\tgot:%v", server, expected, cname)
    74  		}
    75  	}
    76  }
    77  
    78  func TestLookupNS(t *testing.T) {
    79  	if testing.Short() || !*testExternal {
    80  		t.Skip("avoid external network")
    81  	}
    82  
    83  	for _, server := range nslookupTestServers {
    84  		ns, err := LookupNS(server)
    85  		if err != nil {
    86  			t.Errorf("failed %s: %s", server, err)
    87  			continue
    88  		}
    89  		if len(ns) == 0 {
    90  			t.Errorf("no results")
    91  			continue
    92  		}
    93  		expected, err := nslookupNS(server)
    94  		if err != nil {
    95  			t.Logf("skipping failed nslookup %s test: %s", server, err)
    96  			continue
    97  		}
    98  		sort.Sort(byHost(expected))
    99  		sort.Sort(byHost(ns))
   100  		if !reflect.DeepEqual(expected, ns) {
   101  			t.Errorf("different results %s:\texp:%v\tgot:%v", toJson(server), toJson(expected), ns)
   102  		}
   103  	}
   104  }
   105  
   106  func TestLookupTXT(t *testing.T) {
   107  	if testing.Short() || !*testExternal {
   108  		t.Skip("avoid external network")
   109  	}
   110  
   111  	for _, server := range nslookupTestServers {
   112  		txt, err := LookupTXT(server)
   113  		if err != nil {
   114  			t.Errorf("failed %s: %s", server, err)
   115  			continue
   116  		}
   117  		if len(txt) == 0 {
   118  			t.Errorf("no results")
   119  			continue
   120  		}
   121  		expected, err := nslookupTXT(server)
   122  		if err != nil {
   123  			t.Logf("skipping failed nslookup %s test: %s", server, err)
   124  			continue
   125  		}
   126  		sort.Strings(expected)
   127  		sort.Strings(txt)
   128  		if !reflect.DeepEqual(expected, txt) {
   129  			t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(txt))
   130  		}
   131  	}
   132  }
   133  
   134  type byPrefAndHost []*MX
   135  
   136  func (s byPrefAndHost) Len() int { return len(s) }
   137  func (s byPrefAndHost) Less(i, j int) bool {
   138  	if s[i].Pref != s[j].Pref {
   139  		return s[i].Pref < s[j].Pref
   140  	}
   141  	return s[i].Host < s[j].Host
   142  }
   143  func (s byPrefAndHost) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
   144  
   145  type byHost []*NS
   146  
   147  func (s byHost) Len() int           { return len(s) }
   148  func (s byHost) Less(i, j int) bool { return s[i].Host < s[j].Host }
   149  func (s byHost) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   150  
   151  func fqdn(s string) string {
   152  	if len(s) == 0 || s[len(s)-1] != '.' {
   153  		return s + "."
   154  	}
   155  	return s
   156  }
   157  
   158  func nslookup(qtype, name string) (string, error) {
   159  	var out bytes.Buffer
   160  	var err bytes.Buffer
   161  	cmd := exec.Command("nslookup", "-querytype="+qtype, name)
   162  	cmd.Stdout = &out
   163  	cmd.Stderr = &err
   164  	if err := cmd.Run(); err != nil {
   165  		return "", err
   166  	}
   167  	r := strings.Replace(out.String(), "\r\n", "\n", -1)
   168  	// nslookup stderr output contains also debug information such as
   169  	// "Non-authoritative answer" and it doesn't return the correct errcode
   170  	if strings.Contains(err.String(), "can't find") {
   171  		return r, errors.New(err.String())
   172  	}
   173  	return r, nil
   174  }
   175  
   176  func nslookupMX(name string) (mx []*MX, err error) {
   177  	var r string
   178  	if r, err = nslookup("mx", name); err != nil {
   179  		return
   180  	}
   181  	mx = make([]*MX, 0, 10)
   182  	// linux nslookup syntax
   183  	// golang.org      mail exchanger = 2 alt1.aspmx.l.google.com.
   184  	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+mail exchanger\s*=\s*([0-9]+)\s*([a-z0-9.\-]+)$`)
   185  	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
   186  		pref, _, _ := dtoi(ans[2], 0)
   187  		mx = append(mx, &MX{fqdn(ans[3]), uint16(pref)})
   188  	}
   189  	// windows nslookup syntax
   190  	// gmail.com       MX preference = 30, mail exchanger = alt3.gmail-smtp-in.l.google.com
   191  	rx = regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+MX preference\s*=\s*([0-9]+)\s*,\s*mail exchanger\s*=\s*([a-z0-9.\-]+)$`)
   192  	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
   193  		pref, _, _ := dtoi(ans[2], 0)
   194  		mx = append(mx, &MX{fqdn(ans[3]), uint16(pref)})
   195  	}
   196  	return
   197  }
   198  
   199  func nslookupNS(name string) (ns []*NS, err error) {
   200  	var r string
   201  	if r, err = nslookup("ns", name); err != nil {
   202  		return
   203  	}
   204  	ns = make([]*NS, 0, 10)
   205  	// golang.org      nameserver = ns1.google.com.
   206  	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+nameserver\s*=\s*([a-z0-9.\-]+)$`)
   207  	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
   208  		ns = append(ns, &NS{fqdn(ans[2])})
   209  	}
   210  	return
   211  }
   212  
   213  func nslookupCNAME(name string) (cname string, err error) {
   214  	var r string
   215  	if r, err = nslookup("cname", name); err != nil {
   216  		return
   217  	}
   218  	// mail.golang.com canonical name = golang.org.
   219  	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+canonical name\s*=\s*([a-z0-9.\-]+)$`)
   220  	// assumes the last CNAME is the correct one
   221  	last := name
   222  	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
   223  		last = ans[2]
   224  	}
   225  	return fqdn(last), nil
   226  }
   227  
   228  func nslookupTXT(name string) (txt []string, err error) {
   229  	var r string
   230  	if r, err = nslookup("txt", name); err != nil {
   231  		return
   232  	}
   233  	txt = make([]string, 0, 10)
   234  	// linux
   235  	// golang.org      text = "v=spf1 redirect=_spf.google.com"
   236  
   237  	// windows
   238  	// golang.org      text =
   239  	//
   240  	//    "v=spf1 redirect=_spf.google.com"
   241  	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+text\s*=\s*"(.*)"$`)
   242  	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
   243  		txt = append(txt, ans[2])
   244  	}
   245  	return
   246  }