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