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