Source file
src/net/lookup_windows_test.go
1
2
3
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 any) 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
205
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
219
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(ans[3]), uint16(pref)})
224 }
225
226
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(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
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(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
255 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+canonical name\s*=\s*([a-z0-9.\-]+)$`)
256
257 last := name
258 for _, ans := range rx.FindAllStringSubmatch(r, -1) {
259 last = ans[2]
260 }
261 return absDomainName(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
271
272
273
274
275
276
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(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 }
318
View as plain text