]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/go/net/lookup_windows.go
libgo: update to Go1.14beta1
[thirdparty/gcc.git] / libgo / go / net / lookup_windows.go
CommitLineData
7a938933
ILT
1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package net
6
7import (
22b955cc 8 "context"
5a8ea165 9 "internal/syscall/windows"
7a938933 10 "os"
be47d6ec 11 "runtime"
9c63abc9
ILT
12 "syscall"
13 "unsafe"
7a938933
ILT
14)
15
c2047754
ILT
16const _WSAHOST_NOT_FOUND = syscall.Errno(11001)
17
18func winError(call string, err error) error {
19 switch err {
20 case _WSAHOST_NOT_FOUND:
21 return errNoSuchHost
22 }
23 return os.NewSyscallError(call, err)
24}
25
be47d6ec 26func getprotobyname(name string) (proto int, err error) {
94252f4b
ILT
27 p, err := syscall.GetProtoByName(name)
28 if err != nil {
c2047754 29 return 0, winError("getprotobyname", err)
d8f41257
ILT
30 }
31 return int(p.Proto), nil
32}
7a938933 33
be47d6ec 34// lookupProtocol looks up IP protocol name and returns correspondent protocol number.
22b955cc 35func lookupProtocol(ctx context.Context, name string) (int, error) {
be47d6ec
ILT
36 // GetProtoByName return value is stored in thread local storage.
37 // Start new os thread before the call to prevent races.
38 type result struct {
39 proto int
40 err error
41 }
22b955cc 42 ch := make(chan result) // unbuffered
be47d6ec 43 go func() {
f038dae6
ILT
44 acquireThread()
45 defer releaseThread()
be47d6ec
ILT
46 runtime.LockOSThread()
47 defer runtime.UnlockOSThread()
48 proto, err := getprotobyname(name)
22b955cc
ILT
49 select {
50 case ch <- result{proto: proto, err: err}:
51 case <-ctx.Done():
52 }
be47d6ec 53 }()
22b955cc
ILT
54 select {
55 case r := <-ch:
56 if r.err != nil {
c2047754 57 if proto, err := lookupProtocolMap(name); err == nil {
22b955cc
ILT
58 return proto, nil
59 }
aa8901e9
ILT
60
61 dnsError := &DNSError{Err: r.err.Error(), Name: name}
62 if r.err == errNoSuchHost {
63 dnsError.IsNotFound = true
64 }
65 r.err = dnsError
f038dae6 66 }
22b955cc
ILT
67 return r.proto, r.err
68 case <-ctx.Done():
69 return 0, mapErr(ctx.Err())
f038dae6 70 }
be47d6ec
ILT
71}
72
c2047754 73func (r *Resolver) lookupHost(ctx context.Context, name string) ([]string, error) {
4f4a855d 74 ips, err := r.lookupIP(ctx, "ip", name)
405ca104 75 if err != nil {
af146490 76 return nil, err
405ca104 77 }
af146490 78 addrs := make([]string, 0, len(ips))
405ca104
ILT
79 for _, ip := range ips {
80 addrs = append(addrs, ip.String())
81 }
af146490 82 return addrs, nil
405ca104
ILT
83}
84
4f4a855d 85func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr, error) {
c2047754 86 // TODO(bradfitz,brainman): use ctx more. See TODO below.
fabcaa8d 87
4f4a855d
ILT
88 var family int32 = syscall.AF_UNSPEC
89 switch ipVersion(network) {
90 case '4':
91 family = syscall.AF_INET
92 case '6':
93 family = syscall.AF_INET6
94 }
95
dd931d9b 96 getaddr := func() ([]IPAddr, error) {
f038dae6
ILT
97 acquireThread()
98 defer releaseThread()
22b955cc 99 hints := syscall.AddrinfoW{
4f4a855d 100 Family: family,
22b955cc
ILT
101 Socktype: syscall.SOCK_STREAM,
102 Protocol: syscall.IPPROTO_IP,
fabcaa8d 103 }
22b955cc 104 var result *syscall.AddrinfoW
aa8901e9
ILT
105 name16p, err := syscall.UTF16PtrFromString(name)
106 if err != nil {
107 return nil, &DNSError{Name: name, Err: err.Error()}
108 }
109 e := syscall.GetAddrInfoW(name16p, nil, &hints, &result)
22b955cc 110 if e != nil {
aa8901e9
ILT
111 err := winError("getaddrinfow", e)
112 dnsError := &DNSError{Err: err.Error(), Name: name}
113 if err == errNoSuchHost {
114 dnsError.IsNotFound = true
115 }
116 return nil, dnsError
22b955cc
ILT
117 }
118 defer syscall.FreeAddrInfoW(result)
119 addrs := make([]IPAddr, 0, 5)
120 for ; result != nil; result = result.Next {
121 addr := unsafe.Pointer(result.Addr)
122 switch result.Family {
123 case syscall.AF_INET:
124 a := (*syscall.RawSockaddrInet4)(addr).Addr
125 addrs = append(addrs, IPAddr{IP: IPv4(a[0], a[1], a[2], a[3])})
126 case syscall.AF_INET6:
127 a := (*syscall.RawSockaddrInet6)(addr).Addr
bc998d03 128 zone := zoneCache.name(int((*syscall.RawSockaddrInet6)(addr).Scope_id))
22b955cc
ILT
129 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})
130 default:
dd931d9b 131 return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}
22b955cc
ILT
132 }
133 }
dd931d9b
ILT
134 return addrs, nil
135 }
136
137 type ret struct {
138 addrs []IPAddr
139 err error
140 }
141
aa8901e9
ILT
142 var ch chan ret
143 if ctx.Err() == nil {
144 ch = make(chan ret, 1)
145 go func() {
146 addr, err := getaddr()
147 ch <- ret{addrs: addr, err: err}
148 }()
149 }
dd931d9b 150
22b955cc
ILT
151 select {
152 case r := <-ch:
153 return r.addrs, r.err
154 case <-ctx.Done():
155 // TODO(bradfitz,brainman): cancel the ongoing
156 // GetAddrInfoW? It would require conditionally using
157 // GetAddrInfoEx with lpOverlapped, which requires
158 // Windows 8 or newer. I guess we'll need oldLookupIP,
159 // newLookupIP, and newerLookUP.
160 //
161 // For now we just let it finish and write to the
162 // buffered channel.
163 return nil, &DNSError{
164 Name: name,
165 Err: ctx.Err().Error(),
166 IsTimeout: ctx.Err() == context.DeadlineExceeded,
167 }
af146490 168 }
be47d6ec
ILT
169}
170
c2047754 171func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
dd931d9b 172 if r.preferGo() {
c2047754
ILT
173 return lookupPortMap(network, service)
174 }
175
22b955cc 176 // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
f038dae6
ILT
177 acquireThread()
178 defer releaseThread()
be47d6ec
ILT
179 var stype int32
180 switch network {
181 case "tcp4", "tcp6":
182 stype = syscall.SOCK_STREAM
183 case "udp4", "udp6":
184 stype = syscall.SOCK_DGRAM
185 }
186 hints := syscall.AddrinfoW{
187 Family: syscall.AF_UNSPEC,
188 Socktype: stype,
189 Protocol: syscall.IPPROTO_IP,
190 }
191 var result *syscall.AddrinfoW
192 e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
193 if e != nil {
c2047754
ILT
194 if port, err := lookupPortMap(network, service); err == nil {
195 return port, nil
196 }
aa8901e9
ILT
197 err := winError("getaddrinfow", e)
198 dnsError := &DNSError{Err: err.Error(), Name: network + "/" + service}
199 if err == errNoSuchHost {
200 dnsError.IsNotFound = true
201 }
202 return 0, dnsError
be47d6ec
ILT
203 }
204 defer syscall.FreeAddrInfoW(result)
205 if result == nil {
af146490 206 return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
be47d6ec
ILT
207 }
208 addr := unsafe.Pointer(result.Addr)
209 switch result.Family {
210 case syscall.AF_INET:
211 a := (*syscall.RawSockaddrInet4)(addr)
212 return int(syscall.Ntohs(a.Port)), nil
213 case syscall.AF_INET6:
214 a := (*syscall.RawSockaddrInet6)(addr)
215 return int(syscall.Ntohs(a.Port)), nil
216 }
af146490 217 return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
be47d6ec
ILT
218}
219
c2047754 220func (*Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
22b955cc 221 // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
f038dae6
ILT
222 acquireThread()
223 defer releaseThread()
405ca104
ILT
224 var r *syscall.DNSRecord
225 e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
f8d9fa9e
ILT
226 // windows returns DNS_INFO_NO_RECORDS if there are no CNAME-s
227 if errno, ok := e.(syscall.Errno); ok && errno == syscall.DNS_INFO_NO_RECORDS {
228 // if there are no aliases, the canonical name is the input name
f98dd1a3 229 return absDomainName([]byte(name)), nil
f8d9fa9e 230 }
9a0e3259 231 if e != nil {
c2047754 232 return "", &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
405ca104
ILT
233 }
234 defer syscall.DnsRecordListFree(r, 1)
f8d9fa9e
ILT
235
236 resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r)
5a8ea165 237 cname := windows.UTF16PtrToString(resolved, 256)
f98dd1a3 238 return absDomainName([]byte(cname)), nil
7a938933
ILT
239}
240
c2047754 241func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
22b955cc 242 // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
f038dae6
ILT
243 acquireThread()
244 defer releaseThread()
d8f41257
ILT
245 var target string
246 if service == "" && proto == "" {
247 target = name
248 } else {
249 target = "_" + service + "._" + proto + "." + name
250 }
7a938933 251 var r *syscall.DNSRecord
7a938933 252 e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
9a0e3259 253 if e != nil {
c2047754 254 return "", nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: target}
7a938933
ILT
255 }
256 defer syscall.DnsRecordListFree(r, 1)
f8d9fa9e 257
af146490 258 srvs := make([]*SRV, 0, 10)
f8d9fa9e 259 for _, p := range validRecs(r, syscall.DNS_TYPE_SRV, target) {
7a938933 260 v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
f98dd1a3 261 srvs = append(srvs, &SRV{absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]))), v.Port, v.Priority, v.Weight})
7a938933 262 }
af146490 263 byPriorityWeight(srvs).sort()
f98dd1a3 264 return absDomainName([]byte(target)), srvs, nil
7a938933
ILT
265}
266
c2047754 267func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
22b955cc 268 // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
f038dae6
ILT
269 acquireThread()
270 defer releaseThread()
adb0401d
ILT
271 var r *syscall.DNSRecord
272 e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
9a0e3259 273 if e != nil {
c2047754 274 return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
7a938933 275 }
adb0401d 276 defer syscall.DnsRecordListFree(r, 1)
f8d9fa9e 277
af146490 278 mxs := make([]*MX, 0, 10)
f8d9fa9e 279 for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) {
adb0401d 280 v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
5a8ea165 281 mxs = append(mxs, &MX{absDomainName([]byte(windows.UTF16PtrToString(v.NameExchange, 256))), v.Preference})
7a938933 282 }
af146490
ILT
283 byPref(mxs).sort()
284 return mxs, nil
7a938933 285}
ff5f50c5 286
c2047754 287func (*Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
22b955cc 288 // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
f038dae6
ILT
289 acquireThread()
290 defer releaseThread()
fabcaa8d
ILT
291 var r *syscall.DNSRecord
292 e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
293 if e != nil {
c2047754 294 return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
fabcaa8d
ILT
295 }
296 defer syscall.DnsRecordListFree(r, 1)
f8d9fa9e 297
af146490 298 nss := make([]*NS, 0, 10)
f8d9fa9e 299 for _, p := range validRecs(r, syscall.DNS_TYPE_NS, name) {
fabcaa8d 300 v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
f98dd1a3 301 nss = append(nss, &NS{absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:])))})
fabcaa8d 302 }
af146490 303 return nss, nil
fabcaa8d
ILT
304}
305
c2047754 306func (*Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
22b955cc 307 // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
f038dae6
ILT
308 acquireThread()
309 defer releaseThread()
9c63abc9
ILT
310 var r *syscall.DNSRecord
311 e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
9a0e3259 312 if e != nil {
c2047754 313 return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
9c63abc9
ILT
314 }
315 defer syscall.DnsRecordListFree(r, 1)
f8d9fa9e 316
af146490 317 txts := make([]string, 0, 10)
f8d9fa9e
ILT
318 for _, p := range validRecs(r, syscall.DNS_TYPE_TEXT, name) {
319 d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0]))
1a2f01ef 320 s := ""
5a8ea165
ILT
321 for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount:d.StringCount] {
322 s += windows.UTF16PtrToString(v, 1<<20)
9c63abc9 323 }
1a2f01ef 324 txts = append(txts, s)
9c63abc9 325 }
af146490 326 return txts, nil
d8f41257
ILT
327}
328
c2047754 329func (*Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
22b955cc 330 // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
f038dae6
ILT
331 acquireThread()
332 defer releaseThread()
adb0401d
ILT
333 arpa, err := reverseaddr(addr)
334 if err != nil {
335 return nil, err
ff5f50c5 336 }
adb0401d
ILT
337 var r *syscall.DNSRecord
338 e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
9a0e3259 339 if e != nil {
c2047754 340 return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: addr}
ff5f50c5 341 }
adb0401d 342 defer syscall.DnsRecordListFree(r, 1)
f8d9fa9e 343
af146490 344 ptrs := make([]string, 0, 10)
f8d9fa9e 345 for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) {
adb0401d 346 v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
5a8ea165 347 ptrs = append(ptrs, absDomainName([]byte(windows.UTF16PtrToString(v.Host, 256))))
adb0401d 348 }
af146490 349 return ptrs, nil
ff5f50c5 350}
f8d9fa9e
ILT
351
352const dnsSectionMask = 0x0003
353
354// returns only results applicable to name and resolves CNAME entries
355func validRecs(r *syscall.DNSRecord, dnstype uint16, name string) []*syscall.DNSRecord {
356 cname := syscall.StringToUTF16Ptr(name)
357 if dnstype != syscall.DNS_TYPE_CNAME {
358 cname = resolveCNAME(cname, r)
359 }
360 rec := make([]*syscall.DNSRecord, 0, 10)
361 for p := r; p != nil; p = p.Next {
5a8ea165
ILT
362 // in case of a local machine, DNS records are returned with DNSREC_QUESTION flag instead of DNS_ANSWER
363 if p.Dw&dnsSectionMask != syscall.DnsSectionAnswer && p.Dw&dnsSectionMask != syscall.DnsSectionQuestion {
f8d9fa9e
ILT
364 continue
365 }
366 if p.Type != dnstype {
367 continue
368 }
369 if !syscall.DnsNameCompare(cname, p.Name) {
370 continue
371 }
372 rec = append(rec, p)
373 }
374 return rec
375}
376
377// returns the last CNAME in chain
378func resolveCNAME(name *uint16, r *syscall.DNSRecord) *uint16 {
5a8ea165 379 // limit cname resolving to 10 in case of an infinite CNAME loop
f8d9fa9e
ILT
380Cname:
381 for cnameloop := 0; cnameloop < 10; cnameloop++ {
382 for p := r; p != nil; p = p.Next {
383 if p.Dw&dnsSectionMask != syscall.DnsSectionAnswer {
384 continue
385 }
386 if p.Type != syscall.DNS_TYPE_CNAME {
387 continue
388 }
389 if !syscall.DnsNameCompare(name, p.Name) {
390 continue
391 }
392 name = (*syscall.DNSPTRData)(unsafe.Pointer(&r.Data[0])).Host
393 continue Cname
394 }
395 break
396 }
397 return name
398}
dd931d9b
ILT
399
400// concurrentThreadsLimit returns the number of threads we permit to
401// run concurrently doing DNS lookups.
402func concurrentThreadsLimit() int {
403 return 500
404}