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