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
495
496
497
498
499 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
500 return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
501 }
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
523 cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
524 if err != nil {
525 return "", nil, err
526 }
527 if cname != "" && !isDomainName(cname) {
528 return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
529 }
530 filteredAddrs := make([]*SRV, 0, len(addrs))
531 for _, addr := range addrs {
532 if addr == nil {
533 continue
534 }
535 if !isDomainName(addr.Target) {
536 continue
537 }
538 filteredAddrs = append(filteredAddrs, addr)
539 }
540 if len(addrs) != len(filteredAddrs) {
541 return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
542 }
543 return cname, filteredAddrs, nil
544 }
545
546
547
548
549
550
551
552
553
554
555 func LookupMX(name string) ([]*MX, error) {
556 return DefaultResolver.LookupMX(context.Background(), name)
557 }
558
559
560
561
562
563
564
565 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
566 records, err := r.lookupMX(ctx, name)
567 if err != nil {
568 return nil, err
569 }
570 filteredMX := make([]*MX, 0, len(records))
571 for _, mx := range records {
572 if mx == nil {
573 continue
574 }
575 if !isDomainName(mx.Host) {
576
577
578 ip, err := netip.ParseAddr(stringslite.TrimSuffix(mx.Host, "."))
579 if err != nil || ip.Zone() != "" {
580 continue
581 }
582 }
583 filteredMX = append(filteredMX, mx)
584 }
585 if len(records) != len(filteredMX) {
586 return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
587 }
588 return filteredMX, nil
589 }
590
591
592
593
594
595
596
597
598
599
600 func LookupNS(name string) ([]*NS, error) {
601 return DefaultResolver.LookupNS(context.Background(), name)
602 }
603
604
605
606
607
608
609
610 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
611 records, err := r.lookupNS(ctx, name)
612 if err != nil {
613 return nil, err
614 }
615 filteredNS := make([]*NS, 0, len(records))
616 for _, ns := range records {
617 if ns == nil {
618 continue
619 }
620 if !isDomainName(ns.Host) {
621 continue
622 }
623 filteredNS = append(filteredNS, ns)
624 }
625 if len(records) != len(filteredNS) {
626 return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
627 }
628 return filteredNS, nil
629 }
630
631
632
633
634
635
636
637
638 func LookupTXT(name string) ([]string, error) {
639 return DefaultResolver.lookupTXT(context.Background(), name)
640 }
641
642
643
644
645
646 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
647 return r.lookupTXT(ctx, name)
648 }
649
650
651
652
653
654
655
656
657
658
659
660
661
662 func LookupAddr(addr string) (names []string, err error) {
663 return DefaultResolver.LookupAddr(context.Background(), addr)
664 }
665
666
667
668
669
670
671
672 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
673 names, err := r.lookupAddr(ctx, addr)
674 if err != nil {
675 return nil, err
676 }
677 filteredNames := make([]string, 0, len(names))
678 for _, name := range names {
679 if isDomainName(name) {
680 filteredNames = append(filteredNames, name)
681 }
682 }
683 if len(names) != len(filteredNames) {
684 return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
685 }
686 return filteredNames, nil
687 }
688
689
690
691
692 var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
693
694
695
696
697 func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
698
699
700
701
702
703 var c Conn
704 var err error
705 if r != nil && r.Dial != nil {
706 c, err = r.Dial(ctx, network, server)
707 } else {
708 var d Dialer
709 c, err = d.DialContext(ctx, network, server)
710 }
711 if err != nil {
712 return nil, mapErr(err)
713 }
714 return c, nil
715 }
716
717
718
719
720
721
722
723
724
725
726 func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) {
727 if service == "" && proto == "" {
728 target = name
729 } else {
730 target = "_" + service + "._" + proto + "." + name
731 }
732 p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV, nil)
733 if err != nil {
734 return "", nil, err
735 }
736 var cname dnsmessage.Name
737 for {
738 h, err := p.AnswerHeader()
739 if err == dnsmessage.ErrSectionDone {
740 break
741 }
742 if err != nil {
743 return "", nil, &DNSError{
744 Err: "cannot unmarshal DNS message",
745 Name: name,
746 Server: server,
747 }
748 }
749 if h.Type != dnsmessage.TypeSRV {
750 if err := p.SkipAnswer(); err != nil {
751 return "", nil, &DNSError{
752 Err: "cannot unmarshal DNS message",
753 Name: name,
754 Server: server,
755 }
756 }
757 continue
758 }
759 if cname.Length == 0 && h.Name.Length != 0 {
760 cname = h.Name
761 }
762 srv, err := p.SRVResource()
763 if err != nil {
764 return "", nil, &DNSError{
765 Err: "cannot unmarshal DNS message",
766 Name: name,
767 Server: server,
768 }
769 }
770 srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
771 }
772 byPriorityWeight(srvs).sort()
773 return cname.String(), srvs, nil
774 }
775
776
777 func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) {
778 p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX, nil)
779 if err != nil {
780 return nil, err
781 }
782 var mxs []*MX
783 for {
784 h, err := p.AnswerHeader()
785 if err == dnsmessage.ErrSectionDone {
786 break
787 }
788 if err != nil {
789 return nil, &DNSError{
790 Err: "cannot unmarshal DNS message",
791 Name: name,
792 Server: server,
793 }
794 }
795 if h.Type != dnsmessage.TypeMX {
796 if err := p.SkipAnswer(); err != nil {
797 return nil, &DNSError{
798 Err: "cannot unmarshal DNS message",
799 Name: name,
800 Server: server,
801 }
802 }
803 continue
804 }
805 mx, err := p.MXResource()
806 if err != nil {
807 return nil, &DNSError{
808 Err: "cannot unmarshal DNS message",
809 Name: name,
810 Server: server,
811 }
812 }
813 mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
814
815 }
816 byPref(mxs).sort()
817 return mxs, nil
818 }
819
820
821 func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) {
822 p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS, nil)
823 if err != nil {
824 return nil, err
825 }
826 var nss []*NS
827 for {
828 h, err := p.AnswerHeader()
829 if err == dnsmessage.ErrSectionDone {
830 break
831 }
832 if err != nil {
833 return nil, &DNSError{
834 Err: "cannot unmarshal DNS message",
835 Name: name,
836 Server: server,
837 }
838 }
839 if h.Type != dnsmessage.TypeNS {
840 if err := p.SkipAnswer(); err != nil {
841 return nil, &DNSError{
842 Err: "cannot unmarshal DNS message",
843 Name: name,
844 Server: server,
845 }
846 }
847 continue
848 }
849 ns, err := p.NSResource()
850 if err != nil {
851 return nil, &DNSError{
852 Err: "cannot unmarshal DNS message",
853 Name: name,
854 Server: server,
855 }
856 }
857 nss = append(nss, &NS{Host: ns.NS.String()})
858 }
859 return nss, nil
860 }
861
862
863 func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([]string, error) {
864 p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT, nil)
865 if err != nil {
866 return nil, err
867 }
868 var txts []string
869 for {
870 h, err := p.AnswerHeader()
871 if err == dnsmessage.ErrSectionDone {
872 break
873 }
874 if err != nil {
875 return nil, &DNSError{
876 Err: "cannot unmarshal DNS message",
877 Name: name,
878 Server: server,
879 }
880 }
881 if h.Type != dnsmessage.TypeTXT {
882 if err := p.SkipAnswer(); err != nil {
883 return nil, &DNSError{
884 Err: "cannot unmarshal DNS message",
885 Name: name,
886 Server: server,
887 }
888 }
889 continue
890 }
891 txt, err := p.TXTResource()
892 if err != nil {
893 return nil, &DNSError{
894 Err: "cannot unmarshal DNS message",
895 Name: name,
896 Server: server,
897 }
898 }
899
900
901
902 n := 0
903 for _, s := range txt.TXT {
904 n += len(s)
905 }
906 txtJoin := make([]byte, 0, n)
907 for _, s := range txt.TXT {
908 txtJoin = append(txtJoin, s...)
909 }
910 if len(txts) == 0 {
911 txts = make([]string, 0, 1)
912 }
913 txts = append(txts, string(txtJoin))
914 }
915 return txts, nil
916 }
917
918 func parseCNAMEFromResources(resources []dnsmessage.Resource) (string, error) {
919 if len(resources) == 0 {
920 return "", errors.New("no CNAME record received")
921 }
922 c, ok := resources[0].Body.(*dnsmessage.CNAMEResource)
923 if !ok {
924 return "", errors.New("could not parse CNAME record")
925 }
926 return c.CNAME.String(), nil
927 }
928
View as plain text