Source file
src/net/lookup.go
1
2
3
4
5 package net
6
7 import (
8 "context"
9 "errors"
10 "internal/nettrace"
11 "internal/singleflight"
12 "net/netip"
13 "sync"
14
15 "golang.org/x/net/dns/dnsmessage"
16 )
17
18
19
20
21
22
23
24
25 var protocols = map[string]int{
26 "icmp": 1,
27 "igmp": 2,
28 "tcp": 6,
29 "udp": 17,
30 "ipv6-icmp": 58,
31 }
32
33
34
35
36
37
38
39 var services = map[string]map[string]int{
40 "udp": {
41 "domain": 53,
42 },
43 "tcp": {
44 "ftp": 21,
45 "ftps": 990,
46 "gopher": 70,
47 "http": 80,
48 "https": 443,
49 "imap2": 143,
50 "imap3": 220,
51 "imaps": 993,
52 "pop3": 110,
53 "pop3s": 995,
54 "smtp": 25,
55 "submissions": 465,
56 "ssh": 22,
57 "telnet": 23,
58 },
59 }
60
61
62
63 var dnsWaitGroup sync.WaitGroup
64
65 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10
66
67 func lookupProtocolMap(name string) (int, error) {
68 var lowerProtocol [maxProtoLength]byte
69 n := copy(lowerProtocol[:], name)
70 lowerASCIIBytes(lowerProtocol[:n])
71 proto, found := protocols[string(lowerProtocol[:n])]
72 if !found || n != len(name) {
73 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
74 }
75 return proto, nil
76 }
77
78
79
80
81
82
83 const maxPortBufSize = len("mobility-header") + 10
84
85 func lookupPortMap(network, service string) (port int, error error) {
86 switch network {
87 case "ip":
88 if p, err := lookupPortMapWithNetwork("tcp", "ip", service); err == nil {
89 return p, nil
90 }
91 return lookupPortMapWithNetwork("udp", "ip", service)
92 case "tcp", "tcp4", "tcp6":
93 return lookupPortMapWithNetwork("tcp", "tcp", service)
94 case "udp", "udp4", "udp6":
95 return lookupPortMapWithNetwork("udp", "udp", service)
96 }
97 return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
98 }
99
100 func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, error error) {
101 if m, ok := services[network]; ok {
102 var lowerService [maxPortBufSize]byte
103 n := copy(lowerService[:], service)
104 lowerASCIIBytes(lowerService[:n])
105 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
106 return port, nil
107 }
108 return 0, newDNSError(errUnknownPort, errNetwork+"/"+service, "")
109 }
110 return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service}
111 }
112
113
114
115 func ipVersion(network string) byte {
116 if network == "" {
117 return 0
118 }
119 n := network[len(network)-1]
120 if n != '4' && n != '6' {
121 n = 0
122 }
123 return n
124 }
125
126
127
128 var DefaultResolver = &Resolver{}
129
130
131
132
133 type Resolver struct {
134
135
136
137 PreferGo bool
138
139
140
141
142
143
144
145
146
147 StrictErrors bool
148
149
150
151
152
153
154
155
156
157
158
159
160 Dial func(ctx context.Context, network, address string) (Conn, error)
161
162
163
164
165 lookupGroup singleflight.Group
166
167
168
169 }
170
171 func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo }
172 func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
173
174 func (r *Resolver) getLookupGroup() *singleflight.Group {
175 if r == nil {
176 return &DefaultResolver.lookupGroup
177 }
178 return &r.lookupGroup
179 }
180
181
182
183
184
185
186 func LookupHost(host string) (addrs []string, err error) {
187 return DefaultResolver.LookupHost(context.Background(), host)
188 }
189
190
191
192 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
193
194 if host == "" {
195 return nil, newDNSError(errNoSuchHost, host, "")
196 }
197 if _, err := netip.ParseAddr(host); err == nil {
198 return []string{host}, nil
199 }
200 return r.lookupHost(ctx, host)
201 }
202
203
204
205 func LookupIP(host string) ([]IP, error) {
206 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
207 if err != nil {
208 return nil, err
209 }
210 ips := make([]IP, len(addrs))
211 for i, ia := range addrs {
212 ips[i] = ia.IP
213 }
214 return ips, nil
215 }
216
217
218
219 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
220 return r.lookupIPAddr(ctx, "ip", host)
221 }
222
223
224
225
226
227 func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) {
228 afnet, _, err := parseNetwork(ctx, network, false)
229 if err != nil {
230 return nil, err
231 }
232 switch afnet {
233 case "ip", "ip4", "ip6":
234 default:
235 return nil, UnknownNetworkError(network)
236 }
237
238 if host == "" {
239 return nil, newDNSError(errNoSuchHost, host, "")
240 }
241 addrs, err := r.internetAddrList(ctx, afnet, host)
242 if err != nil {
243 return nil, err
244 }
245
246 ips := make([]IP, 0, len(addrs))
247 for _, addr := range addrs {
248 ips = append(ips, addr.(*IPAddr).IP)
249 }
250 return ips, nil
251 }
252
253
254
255
256
257 func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
258
259
260
261
262 ips, err := r.LookupIP(ctx, network, host)
263 if err != nil {
264 return nil, err
265 }
266 ret := make([]netip.Addr, 0, len(ips))
267 for _, ip := range ips {
268 if a, ok := netip.AddrFromSlice(ip); ok {
269 ret = append(ret, a)
270 }
271 }
272 return ret, nil
273 }
274
275
276
277 type onlyValuesCtx struct {
278 context.Context
279 lookupValues context.Context
280 }
281
282 var _ context.Context = (*onlyValuesCtx)(nil)
283
284
285 func (ovc *onlyValuesCtx) Value(key any) any {
286 select {
287 case <-ovc.lookupValues.Done():
288 return nil
289 default:
290 return ovc.lookupValues.Value(key)
291 }
292 }
293
294
295
296
297
298 func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
299 return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
300 }
301
302
303
304 func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
305
306 if host == "" {
307 return nil, newDNSError(errNoSuchHost, host, "")
308 }
309 if ip, err := netip.ParseAddr(host); err == nil {
310 return []IPAddr{{IP: IP(ip.AsSlice()).To16(), Zone: ip.Zone()}}, nil
311 }
312 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
313 if trace != nil && trace.DNSStart != nil {
314 trace.DNSStart(host)
315 }
316
317
318
319 resolverFunc := r.lookupIP
320 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
321 resolverFunc = alt
322 }
323
324
325
326
327
328
329 lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
330
331 lookupKey := network + "\000" + host
332 dnsWaitGroup.Add(1)
333 ch := r.getLookupGroup().DoChan(lookupKey, func() (any, error) {
334 return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
335 })
336
337 dnsWaitGroupDone := func(ch <-chan singleflight.Result, cancelFn context.CancelFunc) {
338 <-ch
339 dnsWaitGroup.Done()
340 cancelFn()
341 }
342 select {
343 case <-ctx.Done():
344
345
346
347
348
349
350
351 if r.getLookupGroup().ForgetUnshared(lookupKey) {
352 lookupGroupCancel()
353 go dnsWaitGroupDone(ch, func() {})
354 } else {
355 go dnsWaitGroupDone(ch, lookupGroupCancel)
356 }
357 err := newDNSError(mapErr(ctx.Err()), host, "")
358 if trace != nil && trace.DNSDone != nil {
359 trace.DNSDone(nil, false, err)
360 }
361 return nil, err
362 case r := <-ch:
363 dnsWaitGroup.Done()
364 lookupGroupCancel()
365 err := r.Err
366 if err != nil {
367 if _, ok := err.(*DNSError); !ok {
368 err = newDNSError(mapErr(err), host, "")
369 }
370 }
371 if trace != nil && trace.DNSDone != nil {
372 addrs, _ := r.Val.([]IPAddr)
373 trace.DNSDone(ipAddrsEface(addrs), r.Shared, err)
374 }
375 return lookupIPReturn(r.Val, err, r.Shared)
376 }
377 }
378
379
380
381 func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) {
382 if err != nil {
383 return nil, err
384 }
385 addrs := addrsi.([]IPAddr)
386 if shared {
387 clone := make([]IPAddr, len(addrs))
388 copy(clone, addrs)
389 addrs = clone
390 }
391 return addrs, nil
392 }
393
394
395 func ipAddrsEface(addrs []IPAddr) []any {
396 s := make([]any, len(addrs))
397 for i, v := range addrs {
398 s[i] = v
399 }
400 return s
401 }
402
403
404
405
406
407 func LookupPort(network, service string) (port int, err error) {
408 return DefaultResolver.LookupPort(context.Background(), network, service)
409 }
410
411
412
413
414 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
415 port, needsLookup := parsePort(service)
416 if needsLookup {
417 switch network {
418 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip":
419 case "":
420 network = "ip"
421 default:
422 return 0, &AddrError{Err: "unknown network", Addr: network}
423 }
424 port, err = r.lookupPort(ctx, network, service)
425 if err != nil {
426 return 0, err
427 }
428 }
429 if 0 > port || port > 65535 {
430 return 0, &AddrError{Err: "invalid port", Addr: service}
431 }
432 return port, nil
433 }
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451 func LookupCNAME(host string) (cname string, err error) {
452 return DefaultResolver.LookupCNAME(context.Background(), host)
453 }
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) {
469 cname, err := r.lookupCNAME(ctx, host)
470 if err != nil {
471 return "", err
472 }
473 if !isDomainName(cname) {
474 return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
475 }
476 return cname, nil
477 }
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
494 return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
495 }
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
512 cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
513 if err != nil {
514 return "", nil, err
515 }
516 if cname != "" && !isDomainName(cname) {
517 return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
518 }
519 filteredAddrs := make([]*SRV, 0, len(addrs))
520 for _, addr := range addrs {
521 if addr == nil {
522 continue
523 }
524 if !isDomainName(addr.Target) {
525 continue
526 }
527 filteredAddrs = append(filteredAddrs, addr)
528 }
529 if len(addrs) != len(filteredAddrs) {
530 return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
531 }
532 return cname, filteredAddrs, nil
533 }
534
535
536
537
538
539
540
541
542
543
544 func LookupMX(name string) ([]*MX, error) {
545 return DefaultResolver.LookupMX(context.Background(), name)
546 }
547
548
549
550
551
552
553
554 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
555 records, err := r.lookupMX(ctx, name)
556 if err != nil {
557 return nil, err
558 }
559 filteredMX := make([]*MX, 0, len(records))
560 for _, mx := range records {
561 if mx == nil {
562 continue
563 }
564 if !isDomainName(mx.Host) {
565 continue
566 }
567 filteredMX = append(filteredMX, mx)
568 }
569 if len(records) != len(filteredMX) {
570 return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
571 }
572 return filteredMX, nil
573 }
574
575
576
577
578
579
580
581
582
583
584 func LookupNS(name string) ([]*NS, error) {
585 return DefaultResolver.LookupNS(context.Background(), name)
586 }
587
588
589
590
591
592
593
594 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
595 records, err := r.lookupNS(ctx, name)
596 if err != nil {
597 return nil, err
598 }
599 filteredNS := make([]*NS, 0, len(records))
600 for _, ns := range records {
601 if ns == nil {
602 continue
603 }
604 if !isDomainName(ns.Host) {
605 continue
606 }
607 filteredNS = append(filteredNS, ns)
608 }
609 if len(records) != len(filteredNS) {
610 return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
611 }
612 return filteredNS, nil
613 }
614
615
616
617
618
619 func LookupTXT(name string) ([]string, error) {
620 return DefaultResolver.lookupTXT(context.Background(), name)
621 }
622
623
624 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
625 return r.lookupTXT(ctx, name)
626 }
627
628
629
630
631
632
633
634
635
636
637
638
639
640 func LookupAddr(addr string) (names []string, err error) {
641 return DefaultResolver.LookupAddr(context.Background(), addr)
642 }
643
644
645
646
647
648
649
650 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
651 names, err := r.lookupAddr(ctx, addr)
652 if err != nil {
653 return nil, err
654 }
655 filteredNames := make([]string, 0, len(names))
656 for _, name := range names {
657 if isDomainName(name) {
658 filteredNames = append(filteredNames, name)
659 }
660 }
661 if len(names) != len(filteredNames) {
662 return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
663 }
664 return filteredNames, nil
665 }
666
667
668
669
670 var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
671
672
673
674
675 func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
676
677
678
679
680
681 var c Conn
682 var err error
683 if r != nil && r.Dial != nil {
684 c, err = r.Dial(ctx, network, server)
685 } else {
686 var d Dialer
687 c, err = d.DialContext(ctx, network, server)
688 }
689 if err != nil {
690 return nil, mapErr(err)
691 }
692 return c, nil
693 }
694
695
696
697
698
699
700
701
702
703
704 func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) {
705 if service == "" && proto == "" {
706 target = name
707 } else {
708 target = "_" + service + "._" + proto + "." + name
709 }
710 p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV, nil)
711 if err != nil {
712 return "", nil, err
713 }
714 var cname dnsmessage.Name
715 for {
716 h, err := p.AnswerHeader()
717 if err == dnsmessage.ErrSectionDone {
718 break
719 }
720 if err != nil {
721 return "", nil, &DNSError{
722 Err: "cannot unmarshal DNS message",
723 Name: name,
724 Server: server,
725 }
726 }
727 if h.Type != dnsmessage.TypeSRV {
728 if err := p.SkipAnswer(); err != nil {
729 return "", nil, &DNSError{
730 Err: "cannot unmarshal DNS message",
731 Name: name,
732 Server: server,
733 }
734 }
735 continue
736 }
737 if cname.Length == 0 && h.Name.Length != 0 {
738 cname = h.Name
739 }
740 srv, err := p.SRVResource()
741 if err != nil {
742 return "", nil, &DNSError{
743 Err: "cannot unmarshal DNS message",
744 Name: name,
745 Server: server,
746 }
747 }
748 srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
749 }
750 byPriorityWeight(srvs).sort()
751 return cname.String(), srvs, nil
752 }
753
754
755 func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) {
756 p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX, nil)
757 if err != nil {
758 return nil, err
759 }
760 var mxs []*MX
761 for {
762 h, err := p.AnswerHeader()
763 if err == dnsmessage.ErrSectionDone {
764 break
765 }
766 if err != nil {
767 return nil, &DNSError{
768 Err: "cannot unmarshal DNS message",
769 Name: name,
770 Server: server,
771 }
772 }
773 if h.Type != dnsmessage.TypeMX {
774 if err := p.SkipAnswer(); err != nil {
775 return nil, &DNSError{
776 Err: "cannot unmarshal DNS message",
777 Name: name,
778 Server: server,
779 }
780 }
781 continue
782 }
783 mx, err := p.MXResource()
784 if err != nil {
785 return nil, &DNSError{
786 Err: "cannot unmarshal DNS message",
787 Name: name,
788 Server: server,
789 }
790 }
791 mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
792
793 }
794 byPref(mxs).sort()
795 return mxs, nil
796 }
797
798
799 func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) {
800 p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS, nil)
801 if err != nil {
802 return nil, err
803 }
804 var nss []*NS
805 for {
806 h, err := p.AnswerHeader()
807 if err == dnsmessage.ErrSectionDone {
808 break
809 }
810 if err != nil {
811 return nil, &DNSError{
812 Err: "cannot unmarshal DNS message",
813 Name: name,
814 Server: server,
815 }
816 }
817 if h.Type != dnsmessage.TypeNS {
818 if err := p.SkipAnswer(); err != nil {
819 return nil, &DNSError{
820 Err: "cannot unmarshal DNS message",
821 Name: name,
822 Server: server,
823 }
824 }
825 continue
826 }
827 ns, err := p.NSResource()
828 if err != nil {
829 return nil, &DNSError{
830 Err: "cannot unmarshal DNS message",
831 Name: name,
832 Server: server,
833 }
834 }
835 nss = append(nss, &NS{Host: ns.NS.String()})
836 }
837 return nss, nil
838 }
839
840
841 func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([]string, error) {
842 p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT, nil)
843 if err != nil {
844 return nil, err
845 }
846 var txts []string
847 for {
848 h, err := p.AnswerHeader()
849 if err == dnsmessage.ErrSectionDone {
850 break
851 }
852 if err != nil {
853 return nil, &DNSError{
854 Err: "cannot unmarshal DNS message",
855 Name: name,
856 Server: server,
857 }
858 }
859 if h.Type != dnsmessage.TypeTXT {
860 if err := p.SkipAnswer(); err != nil {
861 return nil, &DNSError{
862 Err: "cannot unmarshal DNS message",
863 Name: name,
864 Server: server,
865 }
866 }
867 continue
868 }
869 txt, err := p.TXTResource()
870 if err != nil {
871 return nil, &DNSError{
872 Err: "cannot unmarshal DNS message",
873 Name: name,
874 Server: server,
875 }
876 }
877
878
879
880 n := 0
881 for _, s := range txt.TXT {
882 n += len(s)
883 }
884 txtJoin := make([]byte, 0, n)
885 for _, s := range txt.TXT {
886 txtJoin = append(txtJoin, s...)
887 }
888 if len(txts) == 0 {
889 txts = make([]string, 0, 1)
890 }
891 txts = append(txts, string(txtJoin))
892 }
893 return txts, nil
894 }
895
896 func parseCNAMEFromResources(resources []dnsmessage.Resource) (string, error) {
897 if len(resources) == 0 {
898 return "", errors.New("no CNAME record received")
899 }
900 c, ok := resources[0].Body.(*dnsmessage.CNAMEResource)
901 if !ok {
902 return "", errors.New("could not parse CNAME record")
903 }
904 return c.CNAME.String(), nil
905 }
906
View as plain text