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