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 dnsWaitGroup.Add(1)
198 ch, called := lookupGroup.DoChan(host, func() (interface{}, error) {
199 defer dnsWaitGroup.Done()
200 return testHookLookupIP(ctx, resolverFunc, host)
201 })
202 if !called {
203 dnsWaitGroup.Done()
204 }
205
206 select {
207 case <-ctx.Done():
208
209
210
211
212 ctxErr := ctx.Err()
213 if ctxErr == context.DeadlineExceeded {
214 lookupGroup.Forget(host)
215 }
216 err := mapErr(ctxErr)
217 if trace != nil && trace.DNSDone != nil {
218 trace.DNSDone(nil, false, err)
219 }
220 return nil, err
221 case r := <-ch:
222 if trace != nil && trace.DNSDone != nil {
223 addrs, _ := r.Val.([]IPAddr)
224 trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
225 }
226 return lookupIPReturn(r.Val, r.Err, r.Shared)
227 }
228 }
229
230
231
232
233
234 var lookupGroup singleflight.Group
235
236
237
238 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
239 if err != nil {
240 return nil, err
241 }
242 addrs := addrsi.([]IPAddr)
243 if shared {
244 clone := make([]IPAddr, len(addrs))
245 copy(clone, addrs)
246 addrs = clone
247 }
248 return addrs, nil
249 }
250
251
252 func ipAddrsEface(addrs []IPAddr) []interface{} {
253 s := make([]interface{}, len(addrs))
254 for i, v := range addrs {
255 s[i] = v
256 }
257 return s
258 }
259
260
261 func LookupPort(network, service string) (port int, err error) {
262 return DefaultResolver.LookupPort(context.Background(), network, service)
263 }
264
265
266 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
267 port, needsLookup := parsePort(service)
268 if needsLookup {
269 port, err = r.lookupPort(ctx, network, service)
270 if err != nil {
271 return 0, err
272 }
273 }
274 if 0 > port || port > 65535 {
275 return 0, &AddrError{Err: "invalid port", Addr: service}
276 }
277 return port, nil
278 }
279
280
281
282
283
284
285
286
287
288
289
290 func LookupCNAME(host string) (cname string, err error) {
291 return DefaultResolver.lookupCNAME(context.Background(), host)
292 }
293
294
295
296
297
298
299
300
301
302
303
304 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
305 return r.lookupCNAME(ctx, host)
306 }
307
308
309
310
311
312
313
314
315
316
317 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
318 return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
319 }
320
321
322
323
324
325
326
327
328
329
330 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
331 return r.lookupSRV(ctx, service, proto, name)
332 }
333
334
335 func LookupMX(name string) ([]*MX, error) {
336 return DefaultResolver.lookupMX(context.Background(), name)
337 }
338
339
340 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
341 return r.lookupMX(ctx, name)
342 }
343
344
345 func LookupNS(name string) ([]*NS, error) {
346 return DefaultResolver.lookupNS(context.Background(), name)
347 }
348
349
350 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
351 return r.lookupNS(ctx, name)
352 }
353
354
355 func LookupTXT(name string) ([]string, error) {
356 return DefaultResolver.lookupTXT(context.Background(), name)
357 }
358
359
360 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
361 return r.lookupTXT(ctx, name)
362 }
363
364
365
366
367
368
369 func LookupAddr(addr string) (names []string, err error) {
370 return DefaultResolver.lookupAddr(context.Background(), addr)
371 }
372
373
374
375 func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
376 return r.lookupAddr(ctx, addr)
377 }
378
View as plain text