github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/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 "fmt" 12 "internal/testenv" 13 "os/exec" 14 "reflect" 15 "regexp" 16 "sort" 17 "strings" 18 "testing" 19 ) 20 21 var nslookupTestServers = []string{"mail.golang.com", "gmail.com"} 22 var lookupTestIPs = []string{"8.8.8.8", "1.1.1.1"} 23 24 func toJson(v interface{}) string { 25 data, _ := json.Marshal(v) 26 return string(data) 27 } 28 29 func TestNSLookupMX(t *testing.T) { 30 testenv.MustHaveExternalNetwork(t) 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 TestNSLookupCNAME(t *testing.T) { 55 testenv.MustHaveExternalNetwork(t) 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 TestNSLookupNS(t *testing.T) { 78 testenv.MustHaveExternalNetwork(t) 79 80 for _, server := range nslookupTestServers { 81 ns, err := LookupNS(server) 82 if err != nil { 83 t.Errorf("failed %s: %s", server, err) 84 continue 85 } 86 if len(ns) == 0 { 87 t.Errorf("no results") 88 continue 89 } 90 expected, err := nslookupNS(server) 91 if err != nil { 92 t.Logf("skipping failed nslookup %s test: %s", server, err) 93 continue 94 } 95 sort.Sort(byHost(expected)) 96 sort.Sort(byHost(ns)) 97 if !reflect.DeepEqual(expected, ns) { 98 t.Errorf("different results %s:\texp:%v\tgot:%v", toJson(server), toJson(expected), ns) 99 } 100 } 101 } 102 103 func TestNSLookupTXT(t *testing.T) { 104 testenv.MustHaveExternalNetwork(t) 105 106 for _, server := range nslookupTestServers { 107 txt, err := LookupTXT(server) 108 if err != nil { 109 t.Errorf("failed %s: %s", server, err) 110 continue 111 } 112 if len(txt) == 0 { 113 t.Errorf("no results") 114 continue 115 } 116 expected, err := nslookupTXT(server) 117 if err != nil { 118 t.Logf("skipping failed nslookup %s test: %s", server, err) 119 continue 120 } 121 sort.Strings(expected) 122 sort.Strings(txt) 123 if !reflect.DeepEqual(expected, txt) { 124 t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(txt)) 125 } 126 } 127 } 128 129 func TestLookupLocalPTR(t *testing.T) { 130 testenv.MustHaveExternalNetwork(t) 131 132 addr, err := localIP() 133 if err != nil { 134 t.Errorf("failed to get local ip: %s", err) 135 } 136 names, err := LookupAddr(addr.String()) 137 if err != nil { 138 t.Errorf("failed %s: %s", addr, err) 139 } 140 if len(names) == 0 { 141 t.Errorf("no results") 142 } 143 expected, err := lookupPTR(addr.String()) 144 if err != nil { 145 t.Logf("skipping failed lookup %s test: %s", addr.String(), err) 146 } 147 sort.Strings(expected) 148 sort.Strings(names) 149 if !reflect.DeepEqual(expected, names) { 150 t.Errorf("different results %s:\texp:%v\tgot:%v", addr, toJson(expected), toJson(names)) 151 } 152 } 153 154 func TestLookupPTR(t *testing.T) { 155 testenv.MustHaveExternalNetwork(t) 156 157 for _, addr := range lookupTestIPs { 158 names, err := LookupAddr(addr) 159 if err != nil { 160 t.Errorf("failed %s: %s", addr, err) 161 } 162 if len(names) == 0 { 163 t.Errorf("no results") 164 } 165 expected, err := lookupPTR(addr) 166 if err != nil { 167 t.Logf("skipping failed lookup %s test: %s", addr, err) 168 } 169 sort.Strings(expected) 170 sort.Strings(names) 171 if !reflect.DeepEqual(expected, names) { 172 t.Errorf("different results %s:\texp:%v\tgot:%v", addr, toJson(expected), toJson(names)) 173 } 174 } 175 } 176 177 type byPrefAndHost []*MX 178 179 func (s byPrefAndHost) Len() int { return len(s) } 180 func (s byPrefAndHost) Less(i, j int) bool { 181 if s[i].Pref != s[j].Pref { 182 return s[i].Pref < s[j].Pref 183 } 184 return s[i].Host < s[j].Host 185 } 186 func (s byPrefAndHost) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 187 188 type byHost []*NS 189 190 func (s byHost) Len() int { return len(s) } 191 func (s byHost) Less(i, j int) bool { return s[i].Host < s[j].Host } 192 func (s byHost) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 193 194 func nslookup(qtype, name string) (string, error) { 195 var out bytes.Buffer 196 var err bytes.Buffer 197 cmd := exec.Command("nslookup", "-querytype="+qtype, name) 198 cmd.Stdout = &out 199 cmd.Stderr = &err 200 if err := cmd.Run(); err != nil { 201 return "", err 202 } 203 r := strings.ReplaceAll(out.String(), "\r\n", "\n") 204 // nslookup stderr output contains also debug information such as 205 // "Non-authoritative answer" and it doesn't return the correct errcode 206 if strings.Contains(err.String(), "can't find") { 207 return r, errors.New(err.String()) 208 } 209 return r, nil 210 } 211 212 func nslookupMX(name string) (mx []*MX, err error) { 213 var r string 214 if r, err = nslookup("mx", name); err != nil { 215 return 216 } 217 mx = make([]*MX, 0, 10) 218 // linux nslookup syntax 219 // golang.org mail exchanger = 2 alt1.aspmx.l.google.com. 220 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+mail exchanger\s*=\s*([0-9]+)\s*([a-z0-9.\-]+)$`) 221 for _, ans := range rx.FindAllStringSubmatch(r, -1) { 222 pref, _, _ := dtoi(ans[2]) 223 mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)}) 224 } 225 // windows nslookup syntax 226 // gmail.com MX preference = 30, mail exchanger = alt3.gmail-smtp-in.l.google.com 227 rx = regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+MX preference\s*=\s*([0-9]+)\s*,\s*mail exchanger\s*=\s*([a-z0-9.\-]+)$`) 228 for _, ans := range rx.FindAllStringSubmatch(r, -1) { 229 pref, _, _ := dtoi(ans[2]) 230 mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)}) 231 } 232 return 233 } 234 235 func nslookupNS(name string) (ns []*NS, err error) { 236 var r string 237 if r, err = nslookup("ns", name); err != nil { 238 return 239 } 240 ns = make([]*NS, 0, 10) 241 // golang.org nameserver = ns1.google.com. 242 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+nameserver\s*=\s*([a-z0-9.\-]+)$`) 243 for _, ans := range rx.FindAllStringSubmatch(r, -1) { 244 ns = append(ns, &NS{absDomainName([]byte(ans[2]))}) 245 } 246 return 247 } 248 249 func nslookupCNAME(name string) (cname string, err error) { 250 var r string 251 if r, err = nslookup("cname", name); err != nil { 252 return 253 } 254 // mail.golang.com canonical name = golang.org. 255 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+canonical name\s*=\s*([a-z0-9.\-]+)$`) 256 // assumes the last CNAME is the correct one 257 last := name 258 for _, ans := range rx.FindAllStringSubmatch(r, -1) { 259 last = ans[2] 260 } 261 return absDomainName([]byte(last)), nil 262 } 263 264 func nslookupTXT(name string) (txt []string, err error) { 265 var r string 266 if r, err = nslookup("txt", name); err != nil { 267 return 268 } 269 txt = make([]string, 0, 10) 270 // linux 271 // golang.org text = "v=spf1 redirect=_spf.google.com" 272 273 // windows 274 // golang.org text = 275 // 276 // "v=spf1 redirect=_spf.google.com" 277 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+text\s*=\s*"(.*)"$`) 278 for _, ans := range rx.FindAllStringSubmatch(r, -1) { 279 txt = append(txt, ans[2]) 280 } 281 return 282 } 283 284 func ping(name string) (string, error) { 285 cmd := exec.Command("ping", "-n", "1", "-a", name) 286 stdoutStderr, err := cmd.CombinedOutput() 287 if err != nil { 288 return "", fmt.Errorf("%v: %v", err, string(stdoutStderr)) 289 } 290 r := strings.ReplaceAll(string(stdoutStderr), "\r\n", "\n") 291 return r, nil 292 } 293 294 func lookupPTR(name string) (ptr []string, err error) { 295 var r string 296 if r, err = ping(name); err != nil { 297 return 298 } 299 ptr = make([]string, 0, 10) 300 rx := regexp.MustCompile(`(?m)^Pinging\s+([a-zA-Z0-9.\-]+)\s+\[.*$`) 301 for _, ans := range rx.FindAllStringSubmatch(r, -1) { 302 ptr = append(ptr, absDomainName([]byte(ans[1]))) 303 } 304 return 305 } 306 307 func localIP() (ip IP, err error) { 308 conn, err := Dial("udp", "golang.org:80") 309 if err != nil { 310 return nil, err 311 } 312 defer conn.Close() 313 314 localAddr := conn.LocalAddr().(*UDPAddr) 315 316 return localAddr.IP, nil 317 }