Source file
src/net/lookup_windows_test.go
Documentation: net
1
2
3
4
5 package net
6
7 import (
8 "context"
9 "encoding/json"
10 "errors"
11 "fmt"
12 "internal/testenv"
13 "os/exec"
14 "reflect"
15 "regexp"
16 "sort"
17 "strings"
18 "syscall"
19 "testing"
20 )
21
22 var nslookupTestServers = []string{"mail.golang.com", "gmail.com"}
23 var lookupTestIPs = []string{"8.8.8.8", "1.1.1.1"}
24
25 func toJson(v any) string {
26 data, _ := json.Marshal(v)
27 return string(data)
28 }
29
30 func testLookup(t *testing.T, fn func(*testing.T, *Resolver, string)) {
31 for _, def := range []bool{true, false} {
32 def := def
33 for _, server := range nslookupTestServers {
34 server := server
35 var name string
36 if def {
37 name = "default/"
38 } else {
39 name = "go/"
40 }
41 t.Run(name+server, func(t *testing.T) {
42 t.Parallel()
43 r := DefaultResolver
44 if !def {
45 r = &Resolver{PreferGo: true}
46 }
47 fn(t, r, server)
48 })
49 }
50 }
51 }
52
53 func TestNSLookupMX(t *testing.T) {
54 testenv.MustHaveExternalNetwork(t)
55
56 testLookup(t, func(t *testing.T, r *Resolver, server string) {
57 mx, err := r.LookupMX(context.Background(), server)
58 if err != nil {
59 t.Fatal(err)
60 }
61 if len(mx) == 0 {
62 t.Fatal("no results")
63 }
64 expected, err := nslookupMX(server)
65 if err != nil {
66 t.Skipf("skipping failed nslookup %s test: %s", server, err)
67 }
68 sort.Sort(byPrefAndHost(expected))
69 sort.Sort(byPrefAndHost(mx))
70 if !reflect.DeepEqual(expected, mx) {
71 t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(mx))
72 }
73 })
74 }
75
76 func TestNSLookupCNAME(t *testing.T) {
77 testenv.MustHaveExternalNetwork(t)
78
79 testLookup(t, func(t *testing.T, r *Resolver, server string) {
80 cname, err := r.LookupCNAME(context.Background(), server)
81 if err != nil {
82 t.Fatalf("failed %s: %s", server, err)
83 }
84 if cname == "" {
85 t.Fatalf("no result %s", server)
86 }
87 expected, err := nslookupCNAME(server)
88 if err != nil {
89 t.Skipf("skipping failed nslookup %s test: %s", server, err)
90 }
91 if expected != cname {
92 t.Errorf("different results %s:\texp:%v\tgot:%v", server, expected, cname)
93 }
94 })
95 }
96
97 func TestNSLookupNS(t *testing.T) {
98 testenv.MustHaveExternalNetwork(t)
99
100 testLookup(t, func(t *testing.T, r *Resolver, server string) {
101 ns, err := r.LookupNS(context.Background(), server)
102 if err != nil {
103 t.Fatalf("failed %s: %s", server, err)
104 }
105 if len(ns) == 0 {
106 t.Fatal("no results")
107 }
108 expected, err := nslookupNS(server)
109 if err != nil {
110 t.Skipf("skipping failed nslookup %s test: %s", server, err)
111 }
112 sort.Sort(byHost(expected))
113 sort.Sort(byHost(ns))
114 if !reflect.DeepEqual(expected, ns) {
115 t.Errorf("different results %s:\texp:%v\tgot:%v", toJson(server), toJson(expected), ns)
116 }
117 })
118 }
119
120 func TestNSLookupTXT(t *testing.T) {
121 testenv.MustHaveExternalNetwork(t)
122
123 testLookup(t, func(t *testing.T, r *Resolver, server string) {
124 txt, err := r.LookupTXT(context.Background(), server)
125 if err != nil {
126 t.Fatalf("failed %s: %s", server, err)
127 }
128 if len(txt) == 0 {
129 t.Fatalf("no results")
130 }
131 expected, err := nslookupTXT(server)
132 if err != nil {
133 t.Skipf("skipping failed nslookup %s test: %s", server, err)
134 }
135 sort.Strings(expected)
136 sort.Strings(txt)
137 if !reflect.DeepEqual(expected, txt) {
138 t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(txt))
139 }
140 })
141 }
142
143 func TestLookupLocalPTR(t *testing.T) {
144 testenv.MustHaveExternalNetwork(t)
145
146 addr, err := localIP()
147 if err != nil {
148 t.Errorf("failed to get local ip: %s", err)
149 }
150 names, err := LookupAddr(addr.String())
151 if err != nil {
152 t.Errorf("failed %s: %s", addr, err)
153 }
154 if len(names) == 0 {
155 t.Errorf("no results")
156 }
157 expected, err := lookupPTR(addr.String())
158 if err != nil {
159 t.Skipf("skipping failed lookup %s test: %s", addr.String(), err)
160 }
161 sort.Strings(expected)
162 sort.Strings(names)
163 if !reflect.DeepEqual(expected, names) {
164 t.Errorf("different results %s:\texp:%v\tgot:%v", addr, toJson(expected), toJson(names))
165 }
166 }
167
168 func TestLookupPTR(t *testing.T) {
169 testenv.MustHaveExternalNetwork(t)
170
171 for _, addr := range lookupTestIPs {
172 names, err := LookupAddr(addr)
173 if err != nil {
174
175
176
177
178 var DNS_ERROR_RCODE_SERVER_FAILURE syscall.Errno = 9002
179 if strings.HasSuffix(err.Error(), DNS_ERROR_RCODE_SERVER_FAILURE.Error()) {
180 testenv.SkipFlaky(t, 38111)
181 }
182 t.Errorf("failed %s: %s", addr, err)
183 }
184 if len(names) == 0 {
185 t.Errorf("no results")
186 }
187 expected, err := lookupPTR(addr)
188 if err != nil {
189 t.Logf("skipping failed lookup %s test: %s", addr, err)
190 continue
191 }
192 sort.Strings(expected)
193 sort.Strings(names)
194 if !reflect.DeepEqual(expected, names) {
195 t.Errorf("different results %s:\texp:%v\tgot:%v", addr, toJson(expected), toJson(names))
196 }
197 }
198 }
199
200 type byPrefAndHost []*MX
201
202 func (s byPrefAndHost) Len() int { return len(s) }
203 func (s byPrefAndHost) Less(i, j int) bool {
204 if s[i].Pref != s[j].Pref {
205 return s[i].Pref < s[j].Pref
206 }
207 return s[i].Host < s[j].Host
208 }
209 func (s byPrefAndHost) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
210
211 type byHost []*NS
212
213 func (s byHost) Len() int { return len(s) }
214 func (s byHost) Less(i, j int) bool { return s[i].Host < s[j].Host }
215 func (s byHost) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
216
217 func nslookup(qtype, name string) (string, error) {
218 var out strings.Builder
219 var err strings.Builder
220 cmd := exec.Command("nslookup", "-querytype="+qtype, name)
221 cmd.Stdout = &out
222 cmd.Stderr = &err
223 if err := cmd.Run(); err != nil {
224 return "", err
225 }
226 r := strings.ReplaceAll(out.String(), "\r\n", "\n")
227
228
229 if strings.Contains(err.String(), "can't find") {
230 return r, errors.New(err.String())
231 }
232 return r, nil
233 }
234
235 func nslookupMX(name string) (mx []*MX, err error) {
236 var r string
237 if r, err = nslookup("mx", name); err != nil {
238 return
239 }
240 mx = make([]*MX, 0, 10)
241
242
243 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+mail exchanger\s*=\s*([0-9]+)\s*([a-z0-9.\-]+)$`)
244 for _, ans := range rx.FindAllStringSubmatch(r, -1) {
245 pref, _, _ := dtoi(ans[2])
246 mx = append(mx, &MX{absDomainName(ans[3]), uint16(pref)})
247 }
248
249
250 rx = regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+MX preference\s*=\s*([0-9]+)\s*,\s*mail exchanger\s*=\s*([a-z0-9.\-]+)$`)
251 for _, ans := range rx.FindAllStringSubmatch(r, -1) {
252 pref, _, _ := dtoi(ans[2])
253 mx = append(mx, &MX{absDomainName(ans[3]), uint16(pref)})
254 }
255 return
256 }
257
258 func nslookupNS(name string) (ns []*NS, err error) {
259 var r string
260 if r, err = nslookup("ns", name); err != nil {
261 return
262 }
263 ns = make([]*NS, 0, 10)
264
265 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+nameserver\s*=\s*([a-z0-9.\-]+)$`)
266 for _, ans := range rx.FindAllStringSubmatch(r, -1) {
267 ns = append(ns, &NS{absDomainName(ans[2])})
268 }
269 return
270 }
271
272 func nslookupCNAME(name string) (cname string, err error) {
273 var r string
274 if r, err = nslookup("cname", name); err != nil {
275 return
276 }
277
278 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+canonical name\s*=\s*([a-z0-9.\-]+)$`)
279
280 last := name
281 for _, ans := range rx.FindAllStringSubmatch(r, -1) {
282 last = ans[2]
283 }
284 return absDomainName(last), nil
285 }
286
287 func nslookupTXT(name string) (txt []string, err error) {
288 var r string
289 if r, err = nslookup("txt", name); err != nil {
290 return
291 }
292 txt = make([]string, 0, 10)
293
294
295
296
297
298
299
300 rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+text\s*=\s*"(.*)"$`)
301 for _, ans := range rx.FindAllStringSubmatch(r, -1) {
302 txt = append(txt, ans[2])
303 }
304 return
305 }
306
307 func ping(name string) (string, error) {
308 cmd := exec.Command("ping", "-n", "1", "-a", name)
309 stdoutStderr, err := cmd.CombinedOutput()
310 if err != nil {
311 return "", fmt.Errorf("%v: %v", err, string(stdoutStderr))
312 }
313 r := strings.ReplaceAll(string(stdoutStderr), "\r\n", "\n")
314 return r, nil
315 }
316
317 func lookupPTR(name string) (ptr []string, err error) {
318 var r string
319 if r, err = ping(name); err != nil {
320 return
321 }
322 ptr = make([]string, 0, 10)
323 rx := regexp.MustCompile(`(?m)^Pinging\s+([a-zA-Z0-9.\-]+)\s+\[.*$`)
324 for _, ans := range rx.FindAllStringSubmatch(r, -1) {
325 ptr = append(ptr, absDomainName(ans[1]))
326 }
327 return
328 }
329
330 func localIP() (ip IP, err error) {
331 conn, err := Dial("udp", "golang.org:80")
332 if err != nil {
333 return nil, err
334 }
335 defer conn.Close()
336
337 localAddr := conn.LocalAddr().(*UDPAddr)
338
339 return localAddr.IP, nil
340 }
341
View as plain text