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