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
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 var DefaultResolver = &Resolver{}
103
104
105
106
107 type Resolver struct {
108
109
110
111 PreferGo bool
112
113
114
115
116
117
118
119
120
121 StrictErrors bool
122
123
124
125
126
127
128
129
130
131
132
133
134 Dial func(ctx context.Context, network, address string) (Conn, error)
135
136
137
138
139 lookupGroup singleflight.Group
140
141
142
143 }
144
145 func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo }
146 func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
147
148 func (r *Resolver) getLookupGroup() *singleflight.Group {
149 if r == nil {
150 return &DefaultResolver.lookupGroup
151 }
152 return &r.lookupGroup
153 }
154
155
156
157 func LookupHost(host string) (addrs []string, err error) {
158 return DefaultResolver.LookupHost(context.Background(), host)
159 }
160
161
162
163 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
164
165
166 if host == "" {
167 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
168 }
169 if ip, _ := parseIPZone(host); ip != nil {
170 return []string{host}, nil
171 }
172 return r.lookupHost(ctx, host)
173 }
174
175
176
177 func LookupIP(host string) ([]IP, error) {
178 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
179 if err != nil {
180 return nil, err
181 }
182 ips := make([]IP, len(addrs))
183 for i, ia := range addrs {
184 ips[i] = ia.IP
185 }
186 return ips, nil
187 }
188
189
190
191 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
192
193
194 if host == "" {
195 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
196 }
197 if ip, zone := parseIPZone(host); ip != nil {
198 return []IPAddr{{IP: ip, Zone: zone}}, nil
199 }
200 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
201 if trace != nil && trace.DNSStart != nil {
202 trace.DNSStart(host)
203 }
204
205
206
207 resolverFunc := r.lookupIP
208 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil {
209 resolverFunc = alt
210 }
211
212
213
214
215
216 lookupGroupCtx, lookupGroupCancel := context.WithCancel(context.Background())
217
218 dnsWaitGroup.Add(1)
219 ch, called := r.getLookupGroup().DoChan(host, func() (interface{}, error) {
220 defer dnsWaitGroup.Done()
221 return testHookLookupIP(lookupGroupCtx, resolverFunc, host)
222 })
223 if !called {
224 dnsWaitGroup.Done()
225 }
226
227 select {
228 case <-ctx.Done():
229
230
231
232
233
234
235
236 if r.getLookupGroup().ForgetUnshared(host) {
237 lookupGroupCancel()
238 } else {
239 go func() {
240 <-ch
241 lookupGroupCancel()
242 }()
243 }
244 err := mapErr(ctx.Err())
245 if trace != nil && trace.DNSDone != nil {
246 trace.DNSDone(nil, false, err)
247 }
248 return nil, err
249 case r := <-ch:
250 lookupGroupCancel()
251 if trace != nil && trace.DNSDone != nil {
252 addrs, _ := r.Val.([]IPAddr)
253 trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
254 }
255 return lookupIPReturn(r.Val, r.Err, r.Shared)
256 }
257 }
258
259
260
261 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
262 if err != nil {
263 return nil, err
264 }
265 addrs := addrsi.([]IPAddr)
266 if shared {
267 clone := make([]IPAddr, len(addrs))
268 copy(clone, addrs)
269 addrs = clone
270 }
271 return addrs, nil
272 }
273
274
275 func ipAddrsEface(addrs []IPAddr) []interface{} {
276 s := make([]interface{}, len(addrs))
277 for i, v := range addrs {
278 s[i] = v
279 }
280 return s
281 }
282
283
284 func LookupPort(network, service string) (port int, err error) {
285 return DefaultResolver.LookupPort(context.Background(), network, service)
286 }
287
288
289 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
290 port, needsLookup := parsePort(service)
291 if needsLookup {
292 port, err = r.lookupPort(ctx, network, service)
293 if err != nil {
294 return 0, err
295 }
296 }
297 if 0 > port || port > 65535 {
298 return 0, &AddrError{Err: "invalid port", Addr: service}
299 }
300 return port, nil
301 }
302
303
304
305
306
307
308
309
310
311
312
313 func LookupCNAME(host string) (cname string, err error) {
314 return DefaultResolver.lookupCNAME(context.Background(), host)
315 }
316
317
318
319
320
321
322
323
324
325
326
327 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
328 return r.lookupCNAME(ctx, host)
329 }
330
331
332
333
334
335
336
337
338
339
340 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
341 return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
342 }
343
344
345
346
347
348
349
350
351
352
353 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
354 return r.lookupSRV(ctx, service, proto, name)
355 }
356
357
358 func LookupMX(name string) ([]*MX, error) {
359 return DefaultResolver.lookupMX(context.Background(), name)
360 }
361
362
363 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
364 return r.lookupMX(ctx, name)
365 }
366
367
368 func LookupNS(name string) ([]*NS, error) {
369 return DefaultResolver.lookupNS(context.Background(), name)
370 }
371
372
373 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
374 return r.lookupNS(ctx, name)
375 }
376
377
378 func LookupTXT(name string) ([]string, error) {
379 return DefaultResolver.lookupTXT(context.Background(), name)
380 }
381
382
383 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
384 return r.lookupTXT(ctx, name)
385 }
386
387
388
389
390
391
392 func LookupAddr(addr string) (names []string, err error) {
393 return DefaultResolver.lookupAddr(context.Background(), addr)
394 }
395
396
397
398 func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
399 return r.lookupAddr(ctx, addr)
400 }
401
View as plain text