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