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