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