1 // Copyright 2011 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.
14 func query(ctx context
.Context
, filename
, query
string, bufSize
int) (res
[]string, err error
) {
15 file
, err
:= os
.OpenFile(filename
, os
.O_RDWR
, 0)
21 _
, err
= file
.Seek(0, io
.SeekStart
)
25 _
, err
= file
.WriteString(query
)
29 _
, err
= file
.Seek(0, io
.SeekStart
)
33 buf
:= make([]byte, bufSize
)
35 n
, _
:= file
.Read(buf
)
39 res
= append(res
, string(buf
[:n
]))
44 func queryCS(ctx context
.Context
, net
, host
, service
string) (res
[]string, err error
) {
54 return query(ctx
, netdir
+"/cs", net
+"!"+host
+"!"+service
, 128)
57 func queryCS1(ctx context
.Context
, net
string, ip IP
, port
int) (clone
, dest
string, err error
) {
59 if len(ip
) != 0 && !ip
.IsUnspecified() {
62 lines
, err
:= queryCS(ctx
, net
, ips
, itoa(port
))
66 f
:= getFields(lines
[0])
68 return "", "", errors
.New("bad response from ndb/cs")
70 clone
, dest
= f
[0], f
[1]
74 func queryDNS(ctx context
.Context
, addr
string, typ
string) (res
[]string, err error
) {
75 return query(ctx
, netdir
+"/dns", addr
+" "+typ
, 1024)
78 // toLower returns a lower-case version of in. Restricting us to
79 // ASCII is sufficient to handle the IP protocol names and allow
80 // us to not depend on the strings and unicode packages.
81 func toLower(in
string) string {
82 for _
, c
:= range in
{
83 if 'A' <= c
&& c
<= 'Z' {
84 // Has upper case; need to fix.
86 for i
:= 0; i
< len(in
); i
++ {
88 if 'A' <= c
&& c
<= 'Z' {
99 // lookupProtocol looks up IP protocol name and returns
100 // the corresponding protocol number.
101 func lookupProtocol(ctx context
.Context
, name
string) (proto
int, err error
) {
102 lines
, err
:= query(ctx
, netdir
+"/cs", "!protocol="+toLower(name
), 128)
107 return 0, UnknownNetworkError(name
)
109 f
:= getFields(lines
[0])
111 return 0, UnknownNetworkError(name
)
114 if n
, _
, ok
:= dtoi(s
[byteIndex(s
, '=')+1:]); ok
{
117 return 0, UnknownNetworkError(name
)
120 func (*Resolver
) lookupHost(ctx context
.Context
, host
string) (addrs
[]string, err error
) {
121 // Use netdir/cs instead of netdir/dns because cs knows about
122 // host names in local network (e.g. from /lib/ndb/local)
123 lines
, err
:= queryCS(ctx
, "net", host
, "1")
125 if stringsHasSuffix(err
.Error(), "dns failure") {
131 for _
, line
:= range lines
{
137 if i
:= byteIndex(addr
, '!'); i
>= 0 {
138 addr
= addr
[:i
] // remove port
140 if ParseIP(addr
) == nil {
143 // only return unique addresses
144 for _
, a
:= range addrs
{
149 addrs
= append(addrs
, addr
)
154 func (r
*Resolver
) lookupIP(ctx context
.Context
, host
string) (addrs
[]IPAddr
, err error
) {
155 lits
, err
:= r
.lookupHost(ctx
, host
)
159 for _
, lit
:= range lits
{
160 host
, zone
:= splitHostZone(lit
)
161 if ip
:= ParseIP(host
); ip
!= nil {
162 addr
:= IPAddr
{IP
: ip
, Zone
: zone
}
163 addrs
= append(addrs
, addr
)
169 func (*Resolver
) lookupPort(ctx context
.Context
, network
, service
string) (port
int, err error
) {
176 lines
, err
:= queryCS(ctx
, network
, "127.0.0.1", toLower(service
))
180 unknownPortError
:= &AddrError
{Err
: "unknown port", Addr
: network
+ "/" + service
}
182 return 0, unknownPortError
184 f
:= getFields(lines
[0])
186 return 0, unknownPortError
189 if i
:= byteIndex(s
, '!'); i
>= 0 {
190 s
= s
[i
+1:] // remove address
192 if n
, _
, ok
:= dtoi(s
); ok
{
195 return 0, unknownPortError
198 func (*Resolver
) lookupCNAME(ctx context
.Context
, name
string) (cname
string, err error
) {
199 lines
, err
:= queryDNS(ctx
, name
, "cname")
201 if stringsHasSuffix(err
.Error(), "dns failure") {
208 if f
:= getFields(lines
[0]); len(f
) >= 3 {
209 return f
[2] + ".", nil
212 return "", errors
.New("bad response from ndb/dns")
215 func (*Resolver
) lookupSRV(ctx context
.Context
, service
, proto
, name
string) (cname
string, addrs
[]*SRV
, err error
) {
217 if service
== "" && proto
== "" {
220 target
= "_" + service
+ "._" + proto
+ "." + name
222 lines
, err
:= queryDNS(ctx
, target
, "srv")
226 for _
, line
:= range lines
{
231 port
, _
, portOk
:= dtoi(f
[4])
232 priority
, _
, priorityOk
:= dtoi(f
[3])
233 weight
, _
, weightOk
:= dtoi(f
[2])
234 if !(portOk
&& priorityOk
&& weightOk
) {
237 addrs
= append(addrs
, &SRV
{absDomainName([]byte(f
[5])), uint16(port
), uint16(priority
), uint16(weight
)})
238 cname
= absDomainName([]byte(f
[0]))
240 byPriorityWeight(addrs
).sort()
244 func (*Resolver
) lookupMX(ctx context
.Context
, name
string) (mx
[]*MX
, err error
) {
245 lines
, err
:= queryDNS(ctx
, name
, "mx")
249 for _
, line
:= range lines
{
254 if pref
, _
, ok
:= dtoi(f
[2]); ok
{
255 mx
= append(mx
, &MX
{absDomainName([]byte(f
[3])), uint16(pref
)})
262 func (*Resolver
) lookupNS(ctx context
.Context
, name
string) (ns
[]*NS
, err error
) {
263 lines
, err
:= queryDNS(ctx
, name
, "ns")
267 for _
, line
:= range lines
{
272 ns
= append(ns
, &NS
{absDomainName([]byte(f
[2]))})
277 func (*Resolver
) lookupTXT(ctx context
.Context
, name
string) (txt
[]string, err error
) {
278 lines
, err
:= queryDNS(ctx
, name
, "txt")
282 for _
, line
:= range lines
{
283 if i
:= byteIndex(line
, '\t'); i
>= 0 {
284 txt
= append(txt
, absDomainName([]byte(line
[i
+1:])))
290 func (*Resolver
) lookupAddr(ctx context
.Context
, addr
string) (name
[]string, err error
) {
291 arpa
, err
:= reverseaddr(addr
)
295 lines
, err
:= queryDNS(ctx
, arpa
, "ptr")
299 for _
, line
:= range lines
{
304 name
= append(name
, absDomainName([]byte(f
[2])))