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
620
621
622 func LookupTXT(name string) ([]string, error) {
623 return DefaultResolver.lookupTXT(context.Background(), name)
624 }
625
626
627
628
629
630 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
631 return r.lookupTXT(ctx, name)
632 }
633
634
635
636
637
638
639
640
641
642
643
644
645
646 func LookupAddr(addr string) (names []string, err error) {
647 return DefaultResolver.LookupAddr(context.Background(), addr)
648 }
649
650
651
652
653
654
655
656 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
657 names, err := r.lookupAddr(ctx, addr)
658 if err != nil {
659 return nil, err
660 }
661 filteredNames := make([]string, 0, len(names))
662 for _, name := range names {
663 if isDomainName(name) {
664 filteredNames = append(filteredNames, name)
665 }
666 }
667 if len(names) != len(filteredNames) {
668 return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
669 }
670 return filteredNames, nil
671 }
672
673
674
675
676 var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
677
678
679
680
681 func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
682
683
684
685
686
687 var c Conn
688 var err error
689 if r != nil && r.Dial != nil {
690 c, err = r.Dial(ctx, network, server)
691 } else {
692 var d Dialer
693 c, err = d.DialContext(ctx, network, server)
694 }
695 if err != nil {
696 return nil, mapErr(err)
697 }
698 return c, nil
699 }
700
701
702
703
704
705
706
707
708
709
710 func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) {
711 if service == "" && proto == "" {
712 target = name
713 } else {
714 target = "_" + service + "._" + proto + "." + name
715 }
716 p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV, nil)
717 if err != nil {
718 return "", nil, err
719 }
720 var cname dnsmessage.Name
721 for {
722 h, err := p.AnswerHeader()
723 if err == dnsmessage.ErrSectionDone {
724 break
725 }
726 if err != nil {
727 return "", nil, &DNSError{
728 Err: "cannot unmarshal DNS message",
729 Name: name,
730 Server: server,
731 }
732 }
733 if h.Type != dnsmessage.TypeSRV {
734 if err := p.SkipAnswer(); err != nil {
735 return "", nil, &DNSError{
736 Err: "cannot unmarshal DNS message",
737 Name: name,
738 Server: server,
739 }
740 }
741 continue
742 }
743 if cname.Length == 0 && h.Name.Length != 0 {
744 cname = h.Name
745 }
746 srv, err := p.SRVResource()
747 if err != nil {
748 return "", nil, &DNSError{
749 Err: "cannot unmarshal DNS message",
750 Name: name,
751 Server: server,
752 }
753 }
754 srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
755 }
756 byPriorityWeight(srvs).sort()
757 return cname.String(), srvs, nil
758 }
759
760
761 func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) {
762 p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX, nil)
763 if err != nil {
764 return nil, err
765 }
766 var mxs []*MX
767 for {
768 h, err := p.AnswerHeader()
769 if err == dnsmessage.ErrSectionDone {
770 break
771 }
772 if err != nil {
773 return nil, &DNSError{
774 Err: "cannot unmarshal DNS message",
775 Name: name,
776 Server: server,
777 }
778 }
779 if h.Type != dnsmessage.TypeMX {
780 if err := p.SkipAnswer(); err != nil {
781 return nil, &DNSError{
782 Err: "cannot unmarshal DNS message",
783 Name: name,
784 Server: server,
785 }
786 }
787 continue
788 }
789 mx, err := p.MXResource()
790 if err != nil {
791 return nil, &DNSError{
792 Err: "cannot unmarshal DNS message",
793 Name: name,
794 Server: server,
795 }
796 }
797 mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
798
799 }
800 byPref(mxs).sort()
801 return mxs, nil
802 }
803
804
805 func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) {
806 p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS, nil)
807 if err != nil {
808 return nil, err
809 }
810 var nss []*NS
811 for {
812 h, err := p.AnswerHeader()
813 if err == dnsmessage.ErrSectionDone {
814 break
815 }
816 if err != nil {
817 return nil, &DNSError{
818 Err: "cannot unmarshal DNS message",
819 Name: name,
820 Server: server,
821 }
822 }
823 if h.Type != dnsmessage.TypeNS {
824 if err := p.SkipAnswer(); err != nil {
825 return nil, &DNSError{
826 Err: "cannot unmarshal DNS message",
827 Name: name,
828 Server: server,
829 }
830 }
831 continue
832 }
833 ns, err := p.NSResource()
834 if err != nil {
835 return nil, &DNSError{
836 Err: "cannot unmarshal DNS message",
837 Name: name,
838 Server: server,
839 }
840 }
841 nss = append(nss, &NS{Host: ns.NS.String()})
842 }
843 return nss, nil
844 }
845
846
847 func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([]string, error) {
848 p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT, nil)
849 if err != nil {
850 return nil, err
851 }
852 var txts []string
853 for {
854 h, err := p.AnswerHeader()
855 if err == dnsmessage.ErrSectionDone {
856 break
857 }
858 if err != nil {
859 return nil, &DNSError{
860 Err: "cannot unmarshal DNS message",
861 Name: name,
862 Server: server,
863 }
864 }
865 if h.Type != dnsmessage.TypeTXT {
866 if err := p.SkipAnswer(); err != nil {
867 return nil, &DNSError{
868 Err: "cannot unmarshal DNS message",
869 Name: name,
870 Server: server,
871 }
872 }
873 continue
874 }
875 txt, err := p.TXTResource()
876 if err != nil {
877 return nil, &DNSError{
878 Err: "cannot unmarshal DNS message",
879 Name: name,
880 Server: server,
881 }
882 }
883
884
885
886 n := 0
887 for _, s := range txt.TXT {
888 n += len(s)
889 }
890 txtJoin := make([]byte, 0, n)
891 for _, s := range txt.TXT {
892 txtJoin = append(txtJoin, s...)
893 }
894 if len(txts) == 0 {
895 txts = make([]string, 0, 1)
896 }
897 txts = append(txts, string(txtJoin))
898 }
899 return txts, nil
900 }
901
902 func parseCNAMEFromResources(resources []dnsmessage.Resource) (string, error) {
903 if len(resources) == 0 {
904 return "", errors.New("no CNAME record received")
905 }
906 c, ok := resources[0].Body.(*dnsmessage.CNAMEResource)
907 if !ok {
908 return "", errors.New("could not parse CNAME record")
909 }
910 return c.CNAME.String(), nil
911 }
912
View as plain text