github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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 }