Source file
src/net/lookup.go
1
2
3
4
5 package net
6
7 import (
8 "context"
9 "internal/nettrace"
10 "internal/singleflight"
11 "net/netip"
12 "sync"
13 )
14
15
16
17
18
19
20
21
22 var protocols = map[string]int{
23 "icmp": 1,
24 "igmp": 2,
25 "tcp": 6,
26 "udp": 17,
27 "ipv6-icmp": 58,
28 }
29
30
31
32
33
34
35
36 var services = map[string]map[string]int{
37 "udp": {
38 "domain": 53,
39 },
40 "tcp": {
41 "ftp": 21,
42 "ftps": 990,
43 "gopher": 70,
44 "http": 80,
45 "https": 443,
46 "imap2": 143,
47 "imap3": 220,
48 "imaps": 993,
49 "pop3": 110,
50 "pop3s": 995,
51 "smtp": 25,
52 "ssh": 22,
53 "telnet": 23,
54 },
55 }
56
57
58
59 var dnsWaitGroup sync.WaitGroup
60
61 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10
62
63 func lookupProtocolMap(name string) (int, error) {
64 var lowerProtocol [maxProtoLength]byte
65 n := copy(lowerProtocol[:], name)
66 lowerASCIIBytes(lowerProtocol[:n])
67 proto, found := protocols[string(lowerProtocol[:n])]
68 if !found || n != len(name) {
69 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
70 }
71 return proto, nil
72 }
73
74
75
76
77
78
79 const maxPortBufSize = len("mobility-header") + 10
80
81 func lookupPortMap(network, service string) (port int, error error) {
82 switch network {
83 case "tcp4", "tcp6":
84 network = "tcp"
85 case "udp4", "udp6":
86 network = "udp"
87 }
88
89 if m, ok := services[network]; ok {
90 var lowerService [maxPortBufSize]byte
91 n := copy(lowerService[:], service)
92 lowerASCIIBytes(lowerService[:n])
93 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
94 return port, nil
95 }
96 }
97 return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
98 }
99
100
101
102 func ipVersion(network string) byte {
103 if network == "" {
104 return 0
105 }
106 n := network[len(network)-1]
107 if n != '4' && n != '6' {
108 n = 0
109 }
110 return n
111 }
112
113
114
115 var DefaultResolver = &Resolver{}
116
117
118
119
120 type Resolver struct {
121
122
123
124 PreferGo bool
125
126
127
128
129
130
131
132
133
134 StrictErrors bool
135
136
137
138
139
140
141
142
143
144
145
146
147 Dial func(ctx context.Context, network, address string) (Conn, error)
148
149
150
151
152 lookupGroup singleflight.Group
153
154
155
156 }
157
158 func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo }
159 func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
160
161 func (r *Resolver) getLookupGroup() *singleflight.Group {
162 if r == nil {
163 return &DefaultResolver.lookupGroup
164 }
165 return &r.lookupGroup
166 }
167
168
169
170
171
172
173 func LookupHost(host string) (addrs []string, err error) {
174 return DefaultResolver.LookupHost(context.Background(), host)
175 }
176
177
178
179 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
180
181
182 if host == "" {
183 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
184 }
185 if ip, _ := parseIPZone(host); ip != nil {
186 return []string{host}, nil
187 }
188 return r.lookupHost(ctx, host)
189 }
190
191
192
193 func LookupIP(host string) ([]IP, error) {
194 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
195 if err != nil {
196 return nil, err
197 }
198 ips := make([]IP, len(addrs))
199 for i, ia := range addrs {
200 ips[i] = ia.IP
201 }
202 return ips, nil
203 }
204
205
206
207 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
208 return r.lookupIPAddr(ctx, "ip", host)
209 }
210
211
212
213
214
215 func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) {
216 afnet, _, err := parseNetwork(ctx, network, false)
217 if err != nil {
218 return nil, err
219 }
220 switch afnet {
221 case "ip", "ip4", "ip6":
222 default:
223 return nil, UnknownNetworkError(network)
224 }
225 addrs, err := r.internetAddrList(ctx, afnet, host)
226 if err != nil {
227 return nil, err
228 }
229 ips := make([]IP, 0, len(addrs))
230 for _, addr := range addrs {
231 ips = append(ips, addr.(*IPAddr).IP)
232 }
233 return ips, nil
234 }
235
236
237
238
239
240 func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
241
242
243
244
245 ips, err := r.LookupIP(ctx, network, host)
246 if err != nil {
247 return nil, err
248 }
249 ret := make([]netip.Addr, 0, len(ips))
250 for _, ip := range ips {
251 if a, ok := netip.AddrFromSlice(ip); ok {
252 ret = append(ret, a)
253 }
254 }
255 return ret, nil
256 }
257
258
259
260 type onlyValuesCtx struct {
261 context.Context
262 lookupValues context.Context
263 }
264
265 var _ context.Context = (*onlyValuesCtx)(nil)
266
267
268 func (ovc *onlyValuesCtx) Value(key any) any {
269 select {
270 case <-ovc.lookupValues.Done():
271 return nil
272 default:
273 return ovc.lookupValues.Value(key)
274 }
275 }
276
277
278
279
280
281 func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
282 return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
283 }
284
285
286
287 func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
288
289
290 if host == "" {
291 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
292 }
293 if ip, zone := parseIPZone(host); ip != nil {
294 return []IPAddr{{IP: ip, Zone: zone}}, nil
295 }
296 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
297 if trace != nil && trace.DNSStart != nil {
298 trace.DNSStart(host)
299 }
300
301
302
303 resolverFunc := r.lookupIP
304 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
305 resolverFunc = alt
306 }
307
308
309
310
311
312
313 lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
314
315 lookupKey := network + "\000" + host
316 dnsWaitGroup.Add(1)
317 ch, called := r.getLookupGroup().DoChan(lookupKey, func() (any, error) {
318 defer dnsWaitGroup.Done()
319 return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
320 })
321 if !called {
322 dnsWaitGroup.Done()
323 }
324
325 select {
326 case <-ctx.Done():
327
328
329
330
331
332
333
334 if r.getLookupGroup().ForgetUnshared(lookupKey) {
335 lookupGroupCancel()
336 } else {
337 go func() {
338 <-ch
339 lookupGroupCancel()
340 }()
341 }
342 ctxErr := ctx.Err()
343 err := &DNSError{
344 Err: mapErr(ctxErr).Error(),
345 Name: host,
346 IsTimeout: ctxErr == context.DeadlineExceeded,
347 }
348 if trace != nil && trace.DNSDone != nil {
349 trace.DNSDone(nil, false, err)
350 }
351 return nil, err
352 case r := <-ch:
353 lookupGroupCancel()
354 err := r.Err
355 if err != nil {
356 if _, ok := err.(*DNSError); !ok {
357 isTimeout := false
358 if err == context.DeadlineExceeded {
359 isTimeout = true
360 } else if terr, ok := err.(timeout); ok {
361 isTimeout = terr.Timeout()
362 }
363 err = &DNSError{
364 Err: err.Error(),
365 Name: host,
366 IsTimeout: isTimeout,
367 }
368 }
369 }
370 if trace != nil && trace.DNSDone != nil {
371 addrs, _ := r.Val.([]IPAddr)
372 trace.DNSDone(ipAddrsEface(addrs), r.Shared, err)
373 }
374 return lookupIPReturn(r.Val, err, r.Shared)
375 }
376 }
377
378
379
380 func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) {
381 if err != nil {
382 return nil, err
383 }
384 addrs := addrsi.([]IPAddr)
385 if shared {
386 clone := make([]IPAddr, len(addrs))
387 copy(clone, addrs)
388 addrs = clone
389 }
390 return addrs, nil
391 }
392
393
394 func ipAddrsEface(addrs []IPAddr) []any {
395 s := make([]any, len(addrs))
396 for i, v := range addrs {
397 s[i] = v
398 }
399 return s
400 }
401
402
403
404
405
406 func LookupPort(network, service string) (port int, err error) {
407 return DefaultResolver.LookupPort(context.Background(), network, service)
408 }
409
410
411 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
412 port, needsLookup := parsePort(service)
413 if needsLookup {
414 switch network {
415 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
416 case "":
417 network = "ip"
418 default:
419 return 0, &AddrError{Err: "unknown network", Addr: network}
420 }
421 port, err = r.lookupPort(ctx, network, service)
422 if err != nil {
423 return 0, err
424 }
425 }
426 if 0 > port || port > 65535 {
427 return 0, &AddrError{Err: "invalid port", Addr: service}
428 }
429 return port, nil
430 }
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448 func LookupCNAME(host string) (cname string, err error) {
449 return DefaultResolver.LookupCNAME(context.Background(), host)
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) {
466 cname, err := r.lookupCNAME(ctx, host)
467 if err != nil {
468 return "", err
469 }
470 if !isDomainName(cname) {
471 return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
472 }
473 return cname, nil
474 }
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
491 return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
492 }
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
509 cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
510 if err != nil {
511 return "", nil, err
512 }
513 if cname != "" && !isDomainName(cname) {
514 return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
515 }
516 filteredAddrs := make([]*SRV, 0, len(addrs))
517 for _, addr := range addrs {
518 if addr == nil {
519 continue
520 }
521 if !isDomainName(addr.Target) {
522 continue
523 }
524 filteredAddrs = append(filteredAddrs, addr)
525 }
526 if len(addrs) != len(filteredAddrs) {
527 return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
528 }
529 return cname, filteredAddrs, nil
530 }
531
532
533
534
535
536
537
538
539
540
541 func LookupMX(name string) ([]*MX, error) {
542 return DefaultResolver.LookupMX(context.Background(), name)
543 }
544
545
546
547
548
549
550
551 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
552 records, err := r.lookupMX(ctx, name)
553 if err != nil {
554 return nil, err
555 }
556 filteredMX := make([]*MX, 0, len(records))
557 for _, mx := range records {
558 if mx == nil {
559 continue
560 }
561 if !isDomainName(mx.Host) {
562 continue
563 }
564 filteredMX = append(filteredMX, mx)
565 }
566 if len(records) != len(filteredMX) {
567 return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
568 }
569 return filteredMX, nil
570 }
571
572
573
574
575
576
577
578
579
580
581 func LookupNS(name string) ([]*NS, error) {
582 return DefaultResolver.LookupNS(context.Background(), name)
583 }
584
585
586
587
588
589
590
591 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
592 records, err := r.lookupNS(ctx, name)
593 if err != nil {
594 return nil, err
595 }
596 filteredNS := make([]*NS, 0, len(records))
597 for _, ns := range records {
598 if ns == nil {
599 continue
600 }
601 if !isDomainName(ns.Host) {
602 continue
603 }
604 filteredNS = append(filteredNS, ns)
605 }
606 if len(records) != len(filteredNS) {
607 return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
608 }
609 return filteredNS, nil
610 }
611
612
613
614
615
616 func LookupTXT(name string) ([]string, error) {
617 return DefaultResolver.lookupTXT(context.Background(), name)
618 }
619
620
621 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
622 return r.lookupTXT(ctx, name)
623 }
624
625
626
627
628
629
630
631
632
633
634
635
636
637 func LookupAddr(addr string) (names []string, err error) {
638 return DefaultResolver.LookupAddr(context.Background(), addr)
639 }
640
641
642
643
644
645
646
647 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
648 names, err := r.lookupAddr(ctx, addr)
649 if err != nil {
650 return nil, err
651 }
652 filteredNames := make([]string, 0, len(names))
653 for _, name := range names {
654 if isDomainName(name) {
655 filteredNames = append(filteredNames, name)
656 }
657 }
658 if len(names) != len(filteredNames) {
659 return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
660 }
661 return filteredNames, nil
662 }
663
664
665
666
667 var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
668
View as plain text