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