Source file src/pkg/net/lookup.go
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
36 var services = map[string]map[string]int{
37 "udp": {
38 "domain": 53,
39 },
40 "tcp": {
41 "ftp": 21,
42 "ftps": 990,
43 "gopher": 70,
44 "http": 80,
45 "https": 443,
46 "imap2": 143,
47 "imap3": 220,
48 "imaps": 993,
49 "pop3": 110,
50 "pop3s": 995,
51 "smtp": 25,
52 "ssh": 22,
53 "telnet": 23,
54 },
55 }
56
57
58
59 var dnsWaitGroup sync.WaitGroup
60
61 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10
62
63 func lookupProtocolMap(name string) (int, error) {
64 var lowerProtocol [maxProtoLength]byte
65 n := copy(lowerProtocol[:], name)
66 lowerASCIIBytes(lowerProtocol[:n])
67 proto, found := protocols[string(lowerProtocol[:n])]
68 if !found || n != len(name) {
69 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
70 }
71 return proto, nil
72 }
73
74
75
76
77
78
79 const maxPortBufSize = len("mobility-header") + 10
80
81 func lookupPortMap(network, service string) (port int, error error) {
82 switch network {
83 case "tcp4", "tcp6":
84 network = "tcp"
85 case "udp4", "udp6":
86 network = "udp"
87 }
88
89 if m, ok := services[network]; ok {
90 var lowerService [maxPortBufSize]byte
91 n := copy(lowerService[:], service)
92 lowerASCIIBytes(lowerService[:n])
93 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
94 return port, nil
95 }
96 }
97 return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
98 }
99
100
101
102 func ipVersion(network string) byte {
103 if network == "" {
104 return 0
105 }
106 n := network[len(network)-1]
107 if n != '4' && n != '6' {
108 n = 0
109 }
110 return n
111 }
112
113
114
115 var DefaultResolver = &Resolver{}
116
117
118
119
120 type Resolver struct {
121
122
123
124 PreferGo bool
125
126
127
128
129
130
131
132
133
134 StrictErrors bool
135
136
137
138
139
140
141
142
143
144
145
146
147 Dial func(ctx context.Context, network, address string) (Conn, error)
148
149
150
151
152 lookupGroup singleflight.Group
153
154
155
156 }
157
158 func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo }
159 func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
160
161 func (r *Resolver) getLookupGroup() *singleflight.Group {
162 if r == nil {
163 return &DefaultResolver.lookupGroup
164 }
165 return &r.lookupGroup
166 }
167
168
169
170 func LookupHost(host string) (addrs []string, err error) {
171 return DefaultResolver.LookupHost(context.Background(), host)
172 }
173
174
175
176 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
177
178
179 if host == "" {
180 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
181 }
182 if ip, _ := parseIPZone(host); ip != nil {
183 return []string{host}, nil
184 }
185 return r.lookupHost(ctx, host)
186 }
187
188
189
190 func LookupIP(host string) ([]IP, error) {
191 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
192 if err != nil {
193 return nil, err
194 }
195 ips := make([]IP, len(addrs))
196 for i, ia := range addrs {
197 ips[i] = ia.IP
198 }
199 return ips, nil
200 }
201
202
203
204 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
205 return r.lookupIPAddr(ctx, "ip", host)
206 }
207
208
209
210 type onlyValuesCtx struct {
211 context.Context
212 lookupValues context.Context
213 }
214
215 var _ context.Context = (*onlyValuesCtx)(nil)
216
217
218 func (ovc *onlyValuesCtx) Value(key interface{}) interface{} {
219 select {
220 case <-ovc.lookupValues.Done():
221 return nil
222 default:
223 return ovc.lookupValues.Value(key)
224 }
225 }
226
227
228
229
230
231 func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
232 return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
233 }
234
235
236
237 func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
238
239
240 if host == "" {
241 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
242 }
243 if ip, zone := parseIPZone(host); ip != nil {
244 return []IPAddr{{IP: ip, Zone: zone}}, nil
245 }
246 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
247 if trace != nil && trace.DNSStart != nil {
248 trace.DNSStart(host)
249 }
250
251
252
253 resolverFunc := r.lookupIP
254 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
255 resolverFunc = alt
256 }
257
258
259
260
261
262
263 lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
264
265 lookupKey := network + "\000" + host
266 dnsWaitGroup.Add(1)
267 ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) {
268 defer dnsWaitGroup.Done()
269 return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
270 })
271 if !called {
272 dnsWaitGroup.Done()
273 }
274
275 select {
276 case <-ctx.Done():
277
278
279
280
281
282
283
284 if r.getLookupGroup().ForgetUnshared(lookupKey) {
285 lookupGroupCancel()
286 } else {
287 go func() {
288 <-ch
289 lookupGroupCancel()
290 }()
291 }
292 err := mapErr(ctx.Err())
293 if trace != nil && trace.DNSDone != nil {
294 trace.DNSDone(nil, false, err)
295 }
296 return nil, err
297 case r := <-ch:
298 lookupGroupCancel()
299 if trace != nil && trace.DNSDone != nil {
300 addrs, _ := r.Val.([]IPAddr)
301 trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
302 }
303 return lookupIPReturn(r.Val, r.Err, r.Shared)
304 }
305 }
306
307
308
309 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
310 if err != nil {
311 return nil, err
312 }
313 addrs := addrsi.([]IPAddr)
314 if shared {
315 clone := make([]IPAddr, len(addrs))
316 copy(clone, addrs)
317 addrs = clone
318 }
319 return addrs, nil
320 }
321
322
323 func ipAddrsEface(addrs []IPAddr) []interface{} {
324 s := make([]interface{}, len(addrs))
325 for i, v := range addrs {
326 s[i] = v
327 }
328 return s
329 }
330
331
332 func LookupPort(network, service string) (port int, err error) {
333 return DefaultResolver.LookupPort(context.Background(), network, service)
334 }
335
336
337 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
338 port, needsLookup := parsePort(service)
339 if needsLookup {
340 switch network {
341 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
342 case "":
343 network = "ip"
344 default:
345 return 0, &AddrError{Err: "unknown network", Addr: network}
346 }
347 port, err = r.lookupPort(ctx, network, service)
348 if err != nil {
349 return 0, err
350 }
351 }
352 if 0 > port || port > 65535 {
353 return 0, &AddrError{Err: "invalid port", Addr: service}
354 }
355 return port, nil
356 }
357
358
359
360
361
362
363
364
365
366
367
368 func LookupCNAME(host string) (cname string, err error) {
369 return DefaultResolver.lookupCNAME(context.Background(), host)
370 }
371
372
373
374
375
376
377
378
379
380
381
382 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
383 return r.lookupCNAME(ctx, host)
384 }
385
386
387
388
389
390
391
392
393
394
395 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
396 return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
397 }
398
399
400
401
402
403
404
405
406
407
408 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
409 return r.lookupSRV(ctx, service, proto, name)
410 }
411
412
413 func LookupMX(name string) ([]*MX, error) {
414 return DefaultResolver.lookupMX(context.Background(), name)
415 }
416
417
418 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
419 return r.lookupMX(ctx, name)
420 }
421
422
423 func LookupNS(name string) ([]*NS, error) {
424 return DefaultResolver.lookupNS(context.Background(), name)
425 }
426
427
428 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
429 return r.lookupNS(ctx, name)
430 }
431
432
433 func LookupTXT(name string) ([]string, error) {
434 return DefaultResolver.lookupTXT(context.Background(), name)
435 }
436
437
438 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
439 return r.lookupTXT(ctx, name)
440 }
441
442
443
444
445
446
447 func LookupAddr(addr string) (names []string, err error) {
448 return DefaultResolver.lookupAddr(context.Background(), addr)
449 }
450
451
452
453 func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
454 return r.lookupAddr(ctx, addr)
455 }
456
View as plain text