Source file
src/net/lookup_windows.go
Documentation: net
1
2
3
4
5 package net
6
7 import (
8 "context"
9 "internal/syscall/windows"
10 "os"
11 "runtime"
12 "syscall"
13 "time"
14 "unsafe"
15 )
16
17
18
19
20 const cgoAvailable = true
21
22 const (
23 _DNS_ERROR_RCODE_NAME_ERROR = syscall.Errno(9003)
24 _DNS_INFO_NO_RECORDS = syscall.Errno(9501)
25
26 _WSAHOST_NOT_FOUND = syscall.Errno(11001)
27 _WSATRY_AGAIN = syscall.Errno(11002)
28 _WSATYPE_NOT_FOUND = syscall.Errno(10109)
29 )
30
31 func winError(call string, err error) error {
32 switch err {
33 case _WSAHOST_NOT_FOUND, _DNS_ERROR_RCODE_NAME_ERROR, _DNS_INFO_NO_RECORDS:
34 return errNoSuchHost
35 }
36 return os.NewSyscallError(call, err)
37 }
38
39 func getprotobyname(name string) (proto int, err error) {
40 p, err := syscall.GetProtoByName(name)
41 if err != nil {
42 return 0, winError("getprotobyname", err)
43 }
44 return int(p.Proto), nil
45 }
46
47
48 func lookupProtocol(ctx context.Context, name string) (int, error) {
49
50
51 type result struct {
52 proto int
53 err error
54 }
55 ch := make(chan result, 1)
56 go func() {
57 if err := acquireThread(ctx); err != nil {
58 ch <- result{err: mapErr(err)}
59 return
60 }
61 defer releaseThread()
62 runtime.LockOSThread()
63 defer runtime.UnlockOSThread()
64 proto, err := getprotobyname(name)
65 ch <- result{proto: proto, err: err}
66 }()
67 select {
68 case r := <-ch:
69 if r.err != nil {
70 if proto, err := lookupProtocolMap(name); err == nil {
71 return proto, nil
72 }
73 r.err = newDNSError(r.err, name, "")
74 }
75 return r.proto, r.err
76 case <-ctx.Done():
77 return 0, newDNSError(mapErr(ctx.Err()), name, "")
78 }
79 }
80
81 func (r *Resolver) lookupHost(ctx context.Context, name string) ([]string, error) {
82 ips, err := r.lookupIP(ctx, "ip", name)
83 if err != nil {
84 return nil, err
85 }
86 addrs := make([]string, 0, len(ips))
87 for _, ip := range ips {
88 addrs = append(addrs, ip.String())
89 }
90 return addrs, nil
91 }
92
93 func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr, error) {
94 if order, conf := systemConf().hostLookupOrder(r, name); order != hostLookupCgo {
95 return r.goLookupIP(ctx, network, name, order, conf)
96 }
97
98
99
100 var family int32 = syscall.AF_UNSPEC
101 switch ipVersion(network) {
102 case '4':
103 family = syscall.AF_INET
104 case '6':
105 family = syscall.AF_INET6
106 }
107
108 getaddr := func() ([]IPAddr, error) {
109 if err := acquireThread(ctx); err != nil {
110 return nil, newDNSError(mapErr(err), name, "")
111 }
112 defer releaseThread()
113 hints := syscall.AddrinfoW{
114 Family: family,
115 Socktype: syscall.SOCK_STREAM,
116 Protocol: syscall.IPPROTO_IP,
117 }
118 var result *syscall.AddrinfoW
119 name16p, err := syscall.UTF16PtrFromString(name)
120 if err != nil {
121 return nil, newDNSError(err, name, "")
122 }
123
124 dnsConf := getSystemDNSConfig()
125 start := time.Now()
126
127 var e error
128 for i := 0; i < dnsConf.attempts; i++ {
129 e = syscall.GetAddrInfoW(name16p, nil, &hints, &result)
130 if e == nil || e != _WSATRY_AGAIN || time.Since(start) > dnsConf.timeout {
131 break
132 }
133 }
134 if e != nil {
135 return nil, newDNSError(winError("getaddrinfow", e), name, "")
136 }
137 defer syscall.FreeAddrInfoW(result)
138 addrs := make([]IPAddr, 0, 5)
139 for ; result != nil; result = result.Next {
140 addr := unsafe.Pointer(result.Addr)
141 switch result.Family {
142 case syscall.AF_INET:
143 a := (*syscall.RawSockaddrInet4)(addr).Addr
144 addrs = append(addrs, IPAddr{IP: copyIP(a[:])})
145 case syscall.AF_INET6:
146 a := (*syscall.RawSockaddrInet6)(addr).Addr
147 zone := zoneCache.name(int((*syscall.RawSockaddrInet6)(addr).Scope_id))
148 addrs = append(addrs, IPAddr{IP: copyIP(a[:]), Zone: zone})
149 default:
150 return nil, newDNSError(syscall.EWINDOWS, name, "")
151 }
152 }
153 return addrs, nil
154 }
155
156 type ret struct {
157 addrs []IPAddr
158 err error
159 }
160
161 var ch chan ret
162 if ctx.Err() == nil {
163 ch = make(chan ret, 1)
164 go func() {
165 addr, err := getaddr()
166 ch <- ret{addrs: addr, err: err}
167 }()
168 }
169
170 select {
171 case r := <-ch:
172 return r.addrs, r.err
173 case <-ctx.Done():
174
175
176
177
178
179
180
181
182 return nil, newDNSError(mapErr(ctx.Err()), name, "")
183 }
184 }
185
186 func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
187 if systemConf().mustUseGoResolver(r) {
188 return lookupPortMap(network, service)
189 }
190
191
192 if err := acquireThread(ctx); err != nil {
193 return 0, newDNSError(mapErr(err), network+"/"+service, "")
194 }
195 defer releaseThread()
196
197 var hints syscall.AddrinfoW
198
199 switch network {
200 case "ip":
201 case "tcp", "tcp4", "tcp6":
202 hints.Socktype = syscall.SOCK_STREAM
203 hints.Protocol = syscall.IPPROTO_TCP
204 case "udp", "udp4", "udp6":
205 hints.Socktype = syscall.SOCK_DGRAM
206 hints.Protocol = syscall.IPPROTO_UDP
207 default:
208 return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
209 }
210
211 switch ipVersion(network) {
212 case '4':
213 hints.Family = syscall.AF_INET
214 case '6':
215 hints.Family = syscall.AF_INET6
216 }
217
218 servicep, err := syscall.UTF16PtrFromString(service)
219 if err != nil {
220 return 0, newDNSError(err, network+"/"+service, "")
221 }
222
223 var result *syscall.AddrinfoW
224 e := syscall.GetAddrInfoW(nil, servicep, &hints, &result)
225 if e != nil {
226 if port, err := lookupPortMap(network, service); err == nil {
227 return port, nil
228 }
229
230
231
232
233
234 if e == _WSATYPE_NOT_FOUND || e == _WSAHOST_NOT_FOUND {
235 return 0, newDNSError(errUnknownPort, network+"/"+service, "")
236 }
237 return 0, newDNSError(winError("getaddrinfow", e), network+"/"+service, "")
238 }
239 defer syscall.FreeAddrInfoW(result)
240 if result == nil {
241 return 0, newDNSError(syscall.EINVAL, network+"/"+service, "")
242 }
243 addr := unsafe.Pointer(result.Addr)
244 switch result.Family {
245 case syscall.AF_INET:
246 a := (*syscall.RawSockaddrInet4)(addr)
247 return int(syscall.Ntohs(a.Port)), nil
248 case syscall.AF_INET6:
249 a := (*syscall.RawSockaddrInet6)(addr)
250 return int(syscall.Ntohs(a.Port)), nil
251 }
252 return 0, newDNSError(syscall.EINVAL, network+"/"+service, "")
253 }
254
255 func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
256 if order, conf := systemConf().hostLookupOrder(r, name); order != hostLookupCgo {
257 return r.goLookupCNAME(ctx, name, order, conf)
258 }
259
260
261 if err := acquireThread(ctx); err != nil {
262 return "", newDNSError(mapErr(err), name, "")
263 }
264 defer releaseThread()
265 var rec *syscall.DNSRecord
266 e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &rec, nil)
267
268 if errno, ok := e.(syscall.Errno); ok && errno == syscall.DNS_INFO_NO_RECORDS {
269
270 return absDomainName(name), nil
271 }
272 if e != nil {
273 return "", newDNSError(winError("dnsquery", e), name, "")
274 }
275 defer syscall.DnsRecordListFree(rec, 1)
276
277 namep, err := syscall.UTF16PtrFromString(name)
278 if err != nil {
279 return "", newDNSError(err, name, "")
280 }
281
282 resolved := resolveCNAME(namep, rec)
283 cname := windows.UTF16PtrToString(resolved)
284 return absDomainName(cname), nil
285 }
286
287 func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
288 if systemConf().mustUseGoResolver(r) {
289 return r.goLookupSRV(ctx, service, proto, name)
290 }
291
292 if err := acquireThread(ctx); err != nil {
293 return "", nil, newDNSError(mapErr(err), name, "")
294 }
295 defer releaseThread()
296 var target string
297 if service == "" && proto == "" {
298 target = name
299 } else {
300 target = "_" + service + "._" + proto + "." + name
301 }
302 var rec *syscall.DNSRecord
303 e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &rec, nil)
304 if e != nil {
305 return "", nil, newDNSError(winError("dnsquery", e), name, "")
306 }
307 defer syscall.DnsRecordListFree(rec, 1)
308
309 srvs := make([]*SRV, 0, 10)
310 for _, p := range validRecs(rec, syscall.DNS_TYPE_SRV, target) {
311 v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
312 srvs = append(srvs, &SRV{absDomainName(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:])), v.Port, v.Priority, v.Weight})
313 }
314 byPriorityWeight(srvs).sort()
315 return absDomainName(target), srvs, nil
316 }
317
318 func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
319 if systemConf().mustUseGoResolver(r) {
320 return r.goLookupMX(ctx, name)
321 }
322
323 if err := acquireThread(ctx); err != nil {
324 return nil, newDNSError(mapErr(err), name, "")
325 }
326 defer releaseThread()
327 var rec *syscall.DNSRecord
328 e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &rec, nil)
329 if e != nil {
330 return nil, newDNSError(winError("dnsquery", e), name, "")
331 }
332 defer syscall.DnsRecordListFree(rec, 1)
333
334 mxs := make([]*MX, 0, 10)
335 for _, p := range validRecs(rec, syscall.DNS_TYPE_MX, name) {
336 v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
337 mxs = append(mxs, &MX{absDomainName(windows.UTF16PtrToString(v.NameExchange)), v.Preference})
338 }
339 byPref(mxs).sort()
340 return mxs, nil
341 }
342
343 func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
344 if systemConf().mustUseGoResolver(r) {
345 return r.goLookupNS(ctx, name)
346 }
347
348 if err := acquireThread(ctx); err != nil {
349 return nil, newDNSError(mapErr(err), name, "")
350 }
351 defer releaseThread()
352 var rec *syscall.DNSRecord
353 e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &rec, nil)
354 if e != nil {
355 return nil, newDNSError(winError("dnsquery", e), name, "")
356 }
357 defer syscall.DnsRecordListFree(rec, 1)
358
359 nss := make([]*NS, 0, 10)
360 for _, p := range validRecs(rec, syscall.DNS_TYPE_NS, name) {
361 v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
362 nss = append(nss, &NS{absDomainName(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))})
363 }
364 return nss, nil
365 }
366
367 func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
368 if systemConf().mustUseGoResolver(r) {
369 return r.goLookupTXT(ctx, name)
370 }
371
372 if err := acquireThread(ctx); err != nil {
373 return nil, newDNSError(mapErr(err), name, "")
374 }
375 defer releaseThread()
376 var rec *syscall.DNSRecord
377 e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &rec, nil)
378 if e != nil {
379 return nil, newDNSError(winError("dnsquery", e), name, "")
380 }
381 defer syscall.DnsRecordListFree(rec, 1)
382
383 txts := make([]string, 0, 10)
384 for _, p := range validRecs(rec, syscall.DNS_TYPE_TEXT, name) {
385 d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0]))
386 s := ""
387 for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount:d.StringCount] {
388 s += windows.UTF16PtrToString(v)
389 }
390 txts = append(txts, s)
391 }
392 return txts, nil
393 }
394
395 func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
396 if order, conf := systemConf().addrLookupOrder(r, addr); order != hostLookupCgo {
397 return r.goLookupPTR(ctx, addr, order, conf)
398 }
399
400
401 if err := acquireThread(ctx); err != nil {
402 return nil, newDNSError(mapErr(err), addr, "")
403 }
404 defer releaseThread()
405 arpa, err := reverseaddr(addr)
406 if err != nil {
407 return nil, err
408 }
409 var rec *syscall.DNSRecord
410 e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &rec, nil)
411 if e != nil {
412 return nil, newDNSError(winError("dnsquery", e), addr, "")
413 }
414 defer syscall.DnsRecordListFree(rec, 1)
415
416 ptrs := make([]string, 0, 10)
417 for _, p := range validRecs(rec, syscall.DNS_TYPE_PTR, arpa) {
418 v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
419 ptrs = append(ptrs, absDomainName(windows.UTF16PtrToString(v.Host)))
420 }
421 return ptrs, nil
422 }
423
424 const dnsSectionMask = 0x0003
425
426
427 func validRecs(r *syscall.DNSRecord, dnstype uint16, name string) []*syscall.DNSRecord {
428 cname, err := syscall.UTF16PtrFromString(name)
429 if err != nil {
430 return nil
431 }
432 if dnstype != syscall.DNS_TYPE_CNAME {
433 cname = resolveCNAME(cname, r)
434 }
435 rec := make([]*syscall.DNSRecord, 0, 10)
436 for p := r; p != nil; p = p.Next {
437
438 if p.Dw&dnsSectionMask != syscall.DnsSectionAnswer && p.Dw&dnsSectionMask != syscall.DnsSectionQuestion {
439 continue
440 }
441 if p.Type != dnstype {
442 continue
443 }
444 if !syscall.DnsNameCompare(cname, p.Name) {
445 continue
446 }
447 rec = append(rec, p)
448 }
449 return rec
450 }
451
452
453 func resolveCNAME(name *uint16, r *syscall.DNSRecord) *uint16 {
454
455 Cname:
456 for cnameloop := 0; cnameloop < 10; cnameloop++ {
457 for p := r; p != nil; p = p.Next {
458 if p.Dw&dnsSectionMask != syscall.DnsSectionAnswer {
459 continue
460 }
461 if p.Type != syscall.DNS_TYPE_CNAME {
462 continue
463 }
464 if !syscall.DnsNameCompare(name, p.Name) {
465 continue
466 }
467 name = (*syscall.DNSPTRData)(unsafe.Pointer(&r.Data[0])).Host
468 continue Cname
469 }
470 break
471 }
472 return name
473 }
474
475
476
477 func concurrentThreadsLimit() int {
478 return 500
479 }
480
View as plain text