Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
9ded954a
Commit
9ded954a
authored
Jun 13, 2011
by
Alex Brainman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
net: rearrange source files so we could run more tests on windows
R=rsc CC=golang-dev
https://golang.org/cl/4603043
parent
95b8137a
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
442 additions
and
427 deletions
+442
-427
src/pkg/net/Makefile
src/pkg/net/Makefile
+9
-6
src/pkg/net/dnsclient.go
src/pkg/net/dnsclient.go
+20
-347
src/pkg/net/dnsclient_unix.go
src/pkg/net/dnsclient_unix.go
+262
-0
src/pkg/net/dnsmsg_test.go
src/pkg/net/dnsmsg_test.go
+0
-7
src/pkg/net/dnsname_test.go
src/pkg/net/dnsname_test.go
+0
-4
src/pkg/net/lookup_unix.go
src/pkg/net/lookup_unix.go
+126
-0
src/pkg/net/lookup_windows.go
src/pkg/net/lookup_windows.go
+25
-59
src/pkg/net/net_test.go
src/pkg/net/net_test.go
+0
-4
No files found.
src/pkg/net/Makefile
View file @
9ded954a
...
@@ -7,6 +7,7 @@ include ../../Make.inc
...
@@ -7,6 +7,7 @@ include ../../Make.inc
TARG
=
net
TARG
=
net
GOFILES
=
\
GOFILES
=
\
dial.go
\
dial.go
\
dnsclient.go
\
dnsmsg.go
\
dnsmsg.go
\
fd_
$(GOOS)
.go
\
fd_
$(GOOS)
.go
\
hosts.go
\
hosts.go
\
...
@@ -14,7 +15,6 @@ GOFILES=\
...
@@ -14,7 +15,6 @@ GOFILES=\
ip.go
\
ip.go
\
ipsock.go
\
ipsock.go
\
iprawsock.go
\
iprawsock.go
\
lookup.go
\
net.go
\
net.go
\
parse.go
\
parse.go
\
pipe.go
\
pipe.go
\
...
@@ -24,11 +24,12 @@ GOFILES=\
...
@@ -24,11 +24,12 @@ GOFILES=\
unixsock.go
\
unixsock.go
\
GOFILES_freebsd
=
\
GOFILES_freebsd
=
\
dnsclient.go
\
dnsclient
_unix
.go
\
dnsconfig.go
\
dnsconfig.go
\
fd.go
\
fd.go
\
file.go
\
file.go
\
interface_bsd.go
\
interface_bsd.go
\
lookup_unix.go
\
newpollserver.go
\
newpollserver.go
\
port.go
\
port.go
\
sendfile_stub.go
\
sendfile_stub.go
\
...
@@ -39,11 +40,12 @@ CGOFILES_freebsd=\
...
@@ -39,11 +40,12 @@ CGOFILES_freebsd=\
cgo_unix.go
\
cgo_unix.go
\
GOFILES_darwin
=
\
GOFILES_darwin
=
\
dnsclient.go
\
dnsclient
_unix
.go
\
dnsconfig.go
\
dnsconfig.go
\
fd.go
\
fd.go
\
file.go
\
file.go
\
interface_bsd.go
\
interface_bsd.go
\
lookup_unix.go
\
newpollserver.go
\
newpollserver.go
\
port.go
\
port.go
\
sendfile_stub.go
\
sendfile_stub.go
\
...
@@ -54,11 +56,12 @@ CGOFILES_darwin=\
...
@@ -54,11 +56,12 @@ CGOFILES_darwin=\
cgo_unix.go
\
cgo_unix.go
\
GOFILES_linux
=
\
GOFILES_linux
=
\
dnsclient.go
\
dnsclient
_unix
.go
\
dnsconfig.go
\
dnsconfig.go
\
fd.go
\
fd.go
\
file.go
\
file.go
\
interface_linux.go
\
interface_linux.go
\
lookup_unix.go
\
newpollserver.go
\
newpollserver.go
\
port.go
\
port.go
\
sendfile_linux.go
\
sendfile_linux.go
\
...
@@ -66,6 +69,7 @@ GOFILES_linux=\
...
@@ -66,6 +69,7 @@ GOFILES_linux=\
GOFILES_plan9
=
\
GOFILES_plan9
=
\
interface_stub.go
\
interface_stub.go
\
lookup_unix.go
\
sendfile_stub.go
\
sendfile_stub.go
\
ifeq
($(GOARCH),arm)
ifeq
($(GOARCH),arm)
...
@@ -78,10 +82,9 @@ CGOFILES_linux=\
...
@@ -78,10 +82,9 @@ CGOFILES_linux=\
endif
endif
GOFILES_windows
=
\
GOFILES_windows
=
\
cgo_stub.go
\
file_windows.go
\
file_windows.go
\
interface_stub.go
\
interface_stub.go
\
resolv
_windows.go
\
lookup
_windows.go
\
sendfile_windows.go
\
sendfile_windows.go
\
sock_windows.go
\
sock_windows.go
\
...
...
src/pkg/net/dnsclient.go
View file @
9ded954a
...
@@ -2,16 +2,6 @@
...
@@ -2,16 +2,6 @@
// Use of this source code is governed by a BSD-style
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// license that can be found in the LICENSE file.
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.
// TODO(rsc):
// Check periodically whether /etc/resolv.conf has changed.
// Could potentially handle many outstanding lookups faster.
// Could have a small cache.
// Random UDP source port (net.Dial should do that for us).
// Random request IDs.
package
net
package
net
import
(
import
(
...
@@ -19,9 +9,6 @@ import (
...
@@ -19,9 +9,6 @@ import (
"fmt"
"fmt"
"os"
"os"
"rand"
"rand"
"sync"
"time"
"sort"
)
)
// DNSError represents a DNS lookup error.
// DNSError represents a DNS lookup error.
...
@@ -49,54 +36,31 @@ func (e *DNSError) Temporary() bool { return e.IsTimeout }
...
@@ -49,54 +36,31 @@ func (e *DNSError) Temporary() bool { return e.IsTimeout }
const
noSuchHost
=
"no such host"
const
noSuchHost
=
"no such host"
// Send a request on the connection and hope for a reply.
// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
// Up to cfg.attempts attempts.
// address addr suitable for rDNS (PTR) record lookup or an error if it fails
func
exchange
(
cfg
*
dnsConfig
,
c
Conn
,
name
string
,
qtype
uint16
)
(
*
dnsMsg
,
os
.
Error
)
{
// to parse the IP address.
if
len
(
name
)
>=
256
{
func
reverseaddr
(
addr
string
)
(
arpa
string
,
err
os
.
Error
)
{
return
nil
,
&
DNSError
{
Error
:
"name too long"
,
Name
:
name
}
ip
:=
ParseIP
(
addr
)
}
if
ip
==
nil
{
out
:=
new
(
dnsMsg
)
return
""
,
&
DNSError
{
Error
:
"unrecognized address"
,
Name
:
addr
}
out
.
id
=
uint16
(
rand
.
Int
())
^
uint16
(
time
.
Nanoseconds
())
out
.
question
=
[]
dnsQuestion
{
{
name
,
qtype
,
dnsClassINET
},
}
out
.
recursion_desired
=
true
msg
,
ok
:=
out
.
Pack
()
if
!
ok
{
return
nil
,
&
DNSError
{
Error
:
"internal error - cannot pack message"
,
Name
:
name
}
}
for
attempt
:=
0
;
attempt
<
cfg
.
attempts
;
attempt
++
{
n
,
err
:=
c
.
Write
(
msg
)
if
err
!=
nil
{
return
nil
,
err
}
c
.
SetReadTimeout
(
int64
(
cfg
.
timeout
)
*
1e9
)
// nanoseconds
buf
:=
make
([]
byte
,
2000
)
// More than enough.
n
,
err
=
c
.
Read
(
buf
)
if
err
!=
nil
{
if
e
,
ok
:=
err
.
(
Error
);
ok
&&
e
.
Timeout
()
{
continue
}
return
nil
,
err
}
buf
=
buf
[
0
:
n
]
in
:=
new
(
dnsMsg
)
if
!
in
.
Unpack
(
buf
)
||
in
.
id
!=
out
.
id
{
continue
}
}
return
in
,
nil
if
ip
.
To4
()
!=
nil
{
return
fmt
.
Sprintf
(
"%d.%d.%d.%d.in-addr.arpa."
,
ip
[
15
],
ip
[
14
],
ip
[
13
],
ip
[
12
]),
nil
}
}
var
server
string
// Must be IPv6
if
a
:=
c
.
RemoteAddr
();
a
!=
nil
{
var
buf
bytes
.
Buffer
server
=
a
.
String
()
// Add it, in reverse, to the buffer
for
i
:=
len
(
ip
)
-
1
;
i
>=
0
;
i
--
{
s
:=
fmt
.
Sprintf
(
"%02x"
,
ip
[
i
])
buf
.
WriteByte
(
s
[
1
])
buf
.
WriteByte
(
'.'
)
buf
.
WriteByte
(
s
[
0
])
buf
.
WriteByte
(
'.'
)
}
}
return
nil
,
&
DNSError
{
Error
:
"no answer from server"
,
Name
:
name
,
Server
:
server
,
IsTimeout
:
true
}
// Append "ip6.arpa." and return (buf already has the final .)
return
buf
.
String
()
+
"ip6.arpa."
,
nil
}
}
// Find answer for name in dns message.
// Find answer for name in dns message.
// On return, if err == nil, addrs != nil.
// On return, if err == nil, addrs != nil.
func
answer
(
name
,
server
string
,
dns
*
dnsMsg
,
qtype
uint16
)
(
cname
string
,
addrs
[]
dnsRR
,
err
os
.
Error
)
{
func
answer
(
name
,
server
string
,
dns
*
dnsMsg
,
qtype
uint16
)
(
cname
string
,
addrs
[]
dnsRR
,
err
os
.
Error
)
{
...
@@ -150,63 +114,6 @@ Cname:
...
@@ -150,63 +114,6 @@ Cname:
return
""
,
nil
,
&
DNSError
{
Error
:
"too many redirects"
,
Name
:
name
,
Server
:
server
}
return
""
,
nil
,
&
DNSError
{
Error
:
"too many redirects"
,
Name
:
name
,
Server
:
server
}
}
}
// Do a lookup for a single name, which must be rooted
// (otherwise answer will not find the answers).
func
tryOneName
(
cfg
*
dnsConfig
,
name
string
,
qtype
uint16
)
(
cname
string
,
addrs
[]
dnsRR
,
err
os
.
Error
)
{
if
len
(
cfg
.
servers
)
==
0
{
return
""
,
nil
,
&
DNSError
{
Error
:
"no DNS servers"
,
Name
:
name
}
}
for
i
:=
0
;
i
<
len
(
cfg
.
servers
);
i
++
{
// Calling Dial here is scary -- we have to be sure
// not to dial a name that will require a DNS lookup,
// or Dial will call back here to translate it.
// The DNS config parser has already checked that
// all the cfg.servers[i] are IP addresses, which
// Dial will use without a DNS lookup.
server
:=
cfg
.
servers
[
i
]
+
":53"
c
,
cerr
:=
Dial
(
"udp"
,
server
)
if
cerr
!=
nil
{
err
=
cerr
continue
}
msg
,
merr
:=
exchange
(
cfg
,
c
,
name
,
qtype
)
c
.
Close
()
if
merr
!=
nil
{
err
=
merr
continue
}
cname
,
addrs
,
err
=
answer
(
name
,
server
,
msg
,
qtype
)
if
err
==
nil
||
err
.
(
*
DNSError
)
.
Error
==
noSuchHost
{
break
}
}
return
}
func
convertRR_A
(
records
[]
dnsRR
)
[]
IP
{
addrs
:=
make
([]
IP
,
len
(
records
))
for
i
,
rr
:=
range
records
{
a
:=
rr
.
(
*
dnsRR_A
)
.
A
addrs
[
i
]
=
IPv4
(
byte
(
a
>>
24
),
byte
(
a
>>
16
),
byte
(
a
>>
8
),
byte
(
a
))
}
return
addrs
}
func
convertRR_AAAA
(
records
[]
dnsRR
)
[]
IP
{
addrs
:=
make
([]
IP
,
len
(
records
))
for
i
,
rr
:=
range
records
{
a
:=
make
(
IP
,
16
)
copy
(
a
,
rr
.
(
*
dnsRR_AAAA
)
.
AAAA
[
:
])
addrs
[
i
]
=
a
}
return
addrs
}
var
cfg
*
dnsConfig
var
dnserr
os
.
Error
func
loadConfig
()
{
cfg
,
dnserr
=
dnsReadConfig
()
}
func
isDomainName
(
s
string
)
bool
{
func
isDomainName
(
s
string
)
bool
{
// See RFC 1035, RFC 3696.
// See RFC 1035, RFC 3696.
if
len
(
s
)
==
0
{
if
len
(
s
)
==
0
{
...
@@ -255,141 +162,6 @@ func isDomainName(s string) bool {
...
@@ -255,141 +162,6 @@ func isDomainName(s string) bool {
return
ok
return
ok
}
}
var
onceLoadConfig
sync
.
Once
func
lookup
(
name
string
,
qtype
uint16
)
(
cname
string
,
addrs
[]
dnsRR
,
err
os
.
Error
)
{
if
!
isDomainName
(
name
)
{
return
name
,
nil
,
&
DNSError
{
Error
:
"invalid domain name"
,
Name
:
name
}
}
onceLoadConfig
.
Do
(
loadConfig
)
if
dnserr
!=
nil
||
cfg
==
nil
{
err
=
dnserr
return
}
// If name is rooted (trailing dot) or has enough dots,
// try it by itself first.
rooted
:=
len
(
name
)
>
0
&&
name
[
len
(
name
)
-
1
]
==
'.'
if
rooted
||
count
(
name
,
'.'
)
>=
cfg
.
ndots
{
rname
:=
name
if
!
rooted
{
rname
+=
"."
}
// Can try as ordinary name.
cname
,
addrs
,
err
=
tryOneName
(
cfg
,
rname
,
qtype
)
if
err
==
nil
{
return
}
}
if
rooted
{
return
}
// Otherwise, try suffixes.
for
i
:=
0
;
i
<
len
(
cfg
.
search
);
i
++
{
rname
:=
name
+
"."
+
cfg
.
search
[
i
]
if
rname
[
len
(
rname
)
-
1
]
!=
'.'
{
rname
+=
"."
}
cname
,
addrs
,
err
=
tryOneName
(
cfg
,
rname
,
qtype
)
if
err
==
nil
{
return
}
}
// Last ditch effort: try unsuffixed.
rname
:=
name
if
!
rooted
{
rname
+=
"."
}
cname
,
addrs
,
err
=
tryOneName
(
cfg
,
rname
,
qtype
)
if
err
==
nil
{
return
}
return
}
// goLookupHost is the native Go implementation of LookupHost.
// Used only if cgoLookupHost refuses to handle the request
// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
// Normally we let cgo use the C library resolver instead of
// depending on our lookup code, so that Go and C get the same
// answers.
func
goLookupHost
(
name
string
)
(
addrs
[]
string
,
err
os
.
Error
)
{
// Use entries from /etc/hosts if they match.
addrs
=
lookupStaticHost
(
name
)
if
len
(
addrs
)
>
0
{
return
}
onceLoadConfig
.
Do
(
loadConfig
)
if
dnserr
!=
nil
||
cfg
==
nil
{
err
=
dnserr
return
}
ips
,
err
:=
goLookupIP
(
name
)
if
err
!=
nil
{
return
}
addrs
=
make
([]
string
,
0
,
len
(
ips
))
for
_
,
ip
:=
range
ips
{
addrs
=
append
(
addrs
,
ip
.
String
())
}
return
}
// goLookupIP is the native Go implementation of LookupIP.
// Used only if cgoLookupIP refuses to handle the request
// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
// Normally we let cgo use the C library resolver instead of
// depending on our lookup code, so that Go and C get the same
// answers.
func
goLookupIP
(
name
string
)
(
addrs
[]
IP
,
err
os
.
Error
)
{
onceLoadConfig
.
Do
(
loadConfig
)
if
dnserr
!=
nil
||
cfg
==
nil
{
err
=
dnserr
return
}
var
records
[]
dnsRR
var
cname
string
cname
,
records
,
err
=
lookup
(
name
,
dnsTypeA
)
if
err
!=
nil
{
return
}
addrs
=
convertRR_A
(
records
)
if
cname
!=
""
{
name
=
cname
}
_
,
records
,
err
=
lookup
(
name
,
dnsTypeAAAA
)
if
err
!=
nil
&&
len
(
addrs
)
>
0
{
// Ignore error because A lookup succeeded.
err
=
nil
}
if
err
!=
nil
{
return
}
addrs
=
append
(
addrs
,
convertRR_AAAA
(
records
)
...
)
return
}
// goLookupCNAME is the native Go implementation of LookupCNAME.
// Used only if cgoLookupCNAME refuses to handle the request
// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
// Normally we let cgo use the C library resolver instead of
// depending on our lookup code, so that Go and C get the same
// answers.
func
goLookupCNAME
(
name
string
)
(
cname
string
,
err
os
.
Error
)
{
onceLoadConfig
.
Do
(
loadConfig
)
if
dnserr
!=
nil
||
cfg
==
nil
{
err
=
dnserr
return
}
_
,
rr
,
err
:=
lookup
(
name
,
dnsTypeCNAME
)
if
err
!=
nil
{
return
}
cname
=
rr
[
0
]
.
(
*
dnsRR_CNAME
)
.
Cname
return
}
// An SRV represents a single DNS SRV record.
// An SRV represents a single DNS SRV record.
type
SRV
struct
{
type
SRV
struct
{
Target
string
Target
string
...
@@ -436,35 +208,6 @@ func shuffleSRVByWeight(addrs []*SRV) {
...
@@ -436,35 +208,6 @@ func shuffleSRVByWeight(addrs []*SRV) {
}
}
}
}
// LookupSRV tries to resolve an SRV query of the given service,
// protocol, and domain name, as specified in RFC 2782. In most cases
// the proto argument can be the same as the corresponding
// Addr.Network(). The returned records are sorted by priority
// and randomized by weight within a priority.
func
LookupSRV
(
service
,
proto
,
name
string
)
(
cname
string
,
addrs
[]
*
SRV
,
err
os
.
Error
)
{
target
:=
"_"
+
service
+
"._"
+
proto
+
"."
+
name
var
records
[]
dnsRR
cname
,
records
,
err
=
lookup
(
target
,
dnsTypeSRV
)
if
err
!=
nil
{
return
}
addrs
=
make
([]
*
SRV
,
len
(
records
))
for
i
,
rr
:=
range
records
{
r
:=
rr
.
(
*
dnsRR_SRV
)
addrs
[
i
]
=
&
SRV
{
r
.
Target
,
r
.
Port
,
r
.
Priority
,
r
.
Weight
}
}
sort
.
Sort
(
byPriorityWeight
(
addrs
))
i
:=
0
for
j
:=
1
;
j
<
len
(
addrs
);
j
++
{
if
addrs
[
i
]
.
Priority
!=
addrs
[
j
]
.
Priority
{
shuffleSRVByWeight
(
addrs
[
i
:
j
])
i
=
j
}
}
shuffleSRVByWeight
(
addrs
[
i
:
len
(
addrs
)])
return
}
// An MX represents a single DNS MX record.
// An MX represents a single DNS MX record.
type
MX
struct
{
type
MX
struct
{
Host
string
Host
string
...
@@ -479,73 +222,3 @@ func (s byPref) Len() int { return len(s) }
...
@@ -479,73 +222,3 @@ func (s byPref) Len() int { return len(s) }
func
(
s
byPref
)
Less
(
i
,
j
int
)
bool
{
return
s
[
i
]
.
Pref
<
s
[
j
]
.
Pref
}
func
(
s
byPref
)
Less
(
i
,
j
int
)
bool
{
return
s
[
i
]
.
Pref
<
s
[
j
]
.
Pref
}
func
(
s
byPref
)
Swap
(
i
,
j
int
)
{
s
[
i
],
s
[
j
]
=
s
[
j
],
s
[
i
]
}
func
(
s
byPref
)
Swap
(
i
,
j
int
)
{
s
[
i
],
s
[
j
]
=
s
[
j
],
s
[
i
]
}
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
func
LookupMX
(
name
string
)
(
mx
[]
*
MX
,
err
os
.
Error
)
{
_
,
rr
,
err
:=
lookup
(
name
,
dnsTypeMX
)
if
err
!=
nil
{
return
}
mx
=
make
([]
*
MX
,
len
(
rr
))
for
i
:=
range
rr
{
r
:=
rr
[
i
]
.
(
*
dnsRR_MX
)
mx
[
i
]
=
&
MX
{
r
.
Mx
,
r
.
Pref
}
}
// Shuffle the records to match RFC 5321 when sorted
for
i
:=
range
mx
{
j
:=
rand
.
Intn
(
i
+
1
)
mx
[
i
],
mx
[
j
]
=
mx
[
j
],
mx
[
i
]
}
sort
.
Sort
(
byPref
(
mx
))
return
}
// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
// address addr suitable for rDNS (PTR) record lookup or an error if it fails
// to parse the IP address.
func
reverseaddr
(
addr
string
)
(
arpa
string
,
err
os
.
Error
)
{
ip
:=
ParseIP
(
addr
)
if
ip
==
nil
{
return
""
,
&
DNSError
{
Error
:
"unrecognized address"
,
Name
:
addr
}
}
if
ip
.
To4
()
!=
nil
{
return
fmt
.
Sprintf
(
"%d.%d.%d.%d.in-addr.arpa."
,
ip
[
15
],
ip
[
14
],
ip
[
13
],
ip
[
12
]),
nil
}
// Must be IPv6
var
buf
bytes
.
Buffer
// Add it, in reverse, to the buffer
for
i
:=
len
(
ip
)
-
1
;
i
>=
0
;
i
--
{
s
:=
fmt
.
Sprintf
(
"%02x"
,
ip
[
i
])
buf
.
WriteByte
(
s
[
1
])
buf
.
WriteByte
(
'.'
)
buf
.
WriteByte
(
s
[
0
])
buf
.
WriteByte
(
'.'
)
}
// Append "ip6.arpa." and return (buf already has the final .)
return
buf
.
String
()
+
"ip6.arpa."
,
nil
}
// LookupAddr performs a reverse lookup for the given address, returning a list
// of names mapping to that address.
func
LookupAddr
(
addr
string
)
(
name
[]
string
,
err
os
.
Error
)
{
name
=
lookupStaticAddr
(
addr
)
if
len
(
name
)
>
0
{
return
}
var
arpa
string
arpa
,
err
=
reverseaddr
(
addr
)
if
err
!=
nil
{
return
}
var
records
[]
dnsRR
_
,
records
,
err
=
lookup
(
arpa
,
dnsTypePTR
)
if
err
!=
nil
{
return
}
name
=
make
([]
string
,
len
(
records
))
for
i
:=
range
records
{
r
:=
records
[
i
]
.
(
*
dnsRR_PTR
)
name
[
i
]
=
r
.
Ptr
}
return
}
src/pkg/net/dnsclient_unix.go
0 → 100644
View file @
9ded954a
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.
// TODO(rsc):
// Check periodically whether /etc/resolv.conf has changed.
// Could potentially handle many outstanding lookups faster.
// Could have a small cache.
// Random UDP source port (net.Dial should do that for us).
// Random request IDs.
package
net
import
(
"os"
"rand"
"sync"
"time"
)
// Send a request on the connection and hope for a reply.
// Up to cfg.attempts attempts.
func
exchange
(
cfg
*
dnsConfig
,
c
Conn
,
name
string
,
qtype
uint16
)
(
*
dnsMsg
,
os
.
Error
)
{
if
len
(
name
)
>=
256
{
return
nil
,
&
DNSError
{
Error
:
"name too long"
,
Name
:
name
}
}
out
:=
new
(
dnsMsg
)
out
.
id
=
uint16
(
rand
.
Int
())
^
uint16
(
time
.
Nanoseconds
())
out
.
question
=
[]
dnsQuestion
{
{
name
,
qtype
,
dnsClassINET
},
}
out
.
recursion_desired
=
true
msg
,
ok
:=
out
.
Pack
()
if
!
ok
{
return
nil
,
&
DNSError
{
Error
:
"internal error - cannot pack message"
,
Name
:
name
}
}
for
attempt
:=
0
;
attempt
<
cfg
.
attempts
;
attempt
++
{
n
,
err
:=
c
.
Write
(
msg
)
if
err
!=
nil
{
return
nil
,
err
}
c
.
SetReadTimeout
(
int64
(
cfg
.
timeout
)
*
1e9
)
// nanoseconds
buf
:=
make
([]
byte
,
2000
)
// More than enough.
n
,
err
=
c
.
Read
(
buf
)
if
err
!=
nil
{
if
e
,
ok
:=
err
.
(
Error
);
ok
&&
e
.
Timeout
()
{
continue
}
return
nil
,
err
}
buf
=
buf
[
0
:
n
]
in
:=
new
(
dnsMsg
)
if
!
in
.
Unpack
(
buf
)
||
in
.
id
!=
out
.
id
{
continue
}
return
in
,
nil
}
var
server
string
if
a
:=
c
.
RemoteAddr
();
a
!=
nil
{
server
=
a
.
String
()
}
return
nil
,
&
DNSError
{
Error
:
"no answer from server"
,
Name
:
name
,
Server
:
server
,
IsTimeout
:
true
}
}
// Do a lookup for a single name, which must be rooted
// (otherwise answer will not find the answers).
func
tryOneName
(
cfg
*
dnsConfig
,
name
string
,
qtype
uint16
)
(
cname
string
,
addrs
[]
dnsRR
,
err
os
.
Error
)
{
if
len
(
cfg
.
servers
)
==
0
{
return
""
,
nil
,
&
DNSError
{
Error
:
"no DNS servers"
,
Name
:
name
}
}
for
i
:=
0
;
i
<
len
(
cfg
.
servers
);
i
++
{
// Calling Dial here is scary -- we have to be sure
// not to dial a name that will require a DNS lookup,
// or Dial will call back here to translate it.
// The DNS config parser has already checked that
// all the cfg.servers[i] are IP addresses, which
// Dial will use without a DNS lookup.
server
:=
cfg
.
servers
[
i
]
+
":53"
c
,
cerr
:=
Dial
(
"udp"
,
server
)
if
cerr
!=
nil
{
err
=
cerr
continue
}
msg
,
merr
:=
exchange
(
cfg
,
c
,
name
,
qtype
)
c
.
Close
()
if
merr
!=
nil
{
err
=
merr
continue
}
cname
,
addrs
,
err
=
answer
(
name
,
server
,
msg
,
qtype
)
if
err
==
nil
||
err
.
(
*
DNSError
)
.
Error
==
noSuchHost
{
break
}
}
return
}
func
convertRR_A
(
records
[]
dnsRR
)
[]
IP
{
addrs
:=
make
([]
IP
,
len
(
records
))
for
i
,
rr
:=
range
records
{
a
:=
rr
.
(
*
dnsRR_A
)
.
A
addrs
[
i
]
=
IPv4
(
byte
(
a
>>
24
),
byte
(
a
>>
16
),
byte
(
a
>>
8
),
byte
(
a
))
}
return
addrs
}
func
convertRR_AAAA
(
records
[]
dnsRR
)
[]
IP
{
addrs
:=
make
([]
IP
,
len
(
records
))
for
i
,
rr
:=
range
records
{
a
:=
make
(
IP
,
16
)
copy
(
a
,
rr
.
(
*
dnsRR_AAAA
)
.
AAAA
[
:
])
addrs
[
i
]
=
a
}
return
addrs
}
var
cfg
*
dnsConfig
var
dnserr
os
.
Error
func
loadConfig
()
{
cfg
,
dnserr
=
dnsReadConfig
()
}
var
onceLoadConfig
sync
.
Once
func
lookup
(
name
string
,
qtype
uint16
)
(
cname
string
,
addrs
[]
dnsRR
,
err
os
.
Error
)
{
if
!
isDomainName
(
name
)
{
return
name
,
nil
,
&
DNSError
{
Error
:
"invalid domain name"
,
Name
:
name
}
}
onceLoadConfig
.
Do
(
loadConfig
)
if
dnserr
!=
nil
||
cfg
==
nil
{
err
=
dnserr
return
}
// If name is rooted (trailing dot) or has enough dots,
// try it by itself first.
rooted
:=
len
(
name
)
>
0
&&
name
[
len
(
name
)
-
1
]
==
'.'
if
rooted
||
count
(
name
,
'.'
)
>=
cfg
.
ndots
{
rname
:=
name
if
!
rooted
{
rname
+=
"."
}
// Can try as ordinary name.
cname
,
addrs
,
err
=
tryOneName
(
cfg
,
rname
,
qtype
)
if
err
==
nil
{
return
}
}
if
rooted
{
return
}
// Otherwise, try suffixes.
for
i
:=
0
;
i
<
len
(
cfg
.
search
);
i
++
{
rname
:=
name
+
"."
+
cfg
.
search
[
i
]
if
rname
[
len
(
rname
)
-
1
]
!=
'.'
{
rname
+=
"."
}
cname
,
addrs
,
err
=
tryOneName
(
cfg
,
rname
,
qtype
)
if
err
==
nil
{
return
}
}
// Last ditch effort: try unsuffixed.
rname
:=
name
if
!
rooted
{
rname
+=
"."
}
cname
,
addrs
,
err
=
tryOneName
(
cfg
,
rname
,
qtype
)
if
err
==
nil
{
return
}
return
}
// goLookupHost is the native Go implementation of LookupHost.
// Used only if cgoLookupHost refuses to handle the request
// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
// Normally we let cgo use the C library resolver instead of
// depending on our lookup code, so that Go and C get the same
// answers.
func
goLookupHost
(
name
string
)
(
addrs
[]
string
,
err
os
.
Error
)
{
// Use entries from /etc/hosts if they match.
addrs
=
lookupStaticHost
(
name
)
if
len
(
addrs
)
>
0
{
return
}
onceLoadConfig
.
Do
(
loadConfig
)
if
dnserr
!=
nil
||
cfg
==
nil
{
err
=
dnserr
return
}
ips
,
err
:=
goLookupIP
(
name
)
if
err
!=
nil
{
return
}
addrs
=
make
([]
string
,
0
,
len
(
ips
))
for
_
,
ip
:=
range
ips
{
addrs
=
append
(
addrs
,
ip
.
String
())
}
return
}
// goLookupIP is the native Go implementation of LookupIP.
// Used only if cgoLookupIP refuses to handle the request
// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
// Normally we let cgo use the C library resolver instead of
// depending on our lookup code, so that Go and C get the same
// answers.
func
goLookupIP
(
name
string
)
(
addrs
[]
IP
,
err
os
.
Error
)
{
onceLoadConfig
.
Do
(
loadConfig
)
if
dnserr
!=
nil
||
cfg
==
nil
{
err
=
dnserr
return
}
var
records
[]
dnsRR
var
cname
string
cname
,
records
,
err
=
lookup
(
name
,
dnsTypeA
)
if
err
!=
nil
{
return
}
addrs
=
convertRR_A
(
records
)
if
cname
!=
""
{
name
=
cname
}
_
,
records
,
err
=
lookup
(
name
,
dnsTypeAAAA
)
if
err
!=
nil
&&
len
(
addrs
)
>
0
{
// Ignore error because A lookup succeeded.
err
=
nil
}
if
err
!=
nil
{
return
}
addrs
=
append
(
addrs
,
convertRR_AAAA
(
records
)
...
)
return
}
// goLookupCNAME is the native Go implementation of LookupCNAME.
// Used only if cgoLookupCNAME refuses to handle the request
// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
// Normally we let cgo use the C library resolver instead of
// depending on our lookup code, so that Go and C get the same
// answers.
func
goLookupCNAME
(
name
string
)
(
cname
string
,
err
os
.
Error
)
{
onceLoadConfig
.
Do
(
loadConfig
)
if
dnserr
!=
nil
||
cfg
==
nil
{
err
=
dnserr
return
}
_
,
rr
,
err
:=
lookup
(
name
,
dnsTypeCNAME
)
if
err
!=
nil
{
return
}
cname
=
rr
[
0
]
.
(
*
dnsRR_CNAME
)
.
Cname
return
}
src/pkg/net/dnsmsg_test.go
View file @
9ded954a
...
@@ -6,14 +6,10 @@ package net
...
@@ -6,14 +6,10 @@ package net
import
(
import
(
"encoding/hex"
"encoding/hex"
"runtime"
"testing"
"testing"
)
)
func
TestDNSParseSRVReply
(
t
*
testing
.
T
)
{
func
TestDNSParseSRVReply
(
t
*
testing
.
T
)
{
if
runtime
.
GOOS
==
"windows"
{
return
}
data
,
err
:=
hex
.
DecodeString
(
dnsSRVReply
)
data
,
err
:=
hex
.
DecodeString
(
dnsSRVReply
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
...
@@ -45,9 +41,6 @@ func TestDNSParseSRVReply(t *testing.T) {
...
@@ -45,9 +41,6 @@ func TestDNSParseSRVReply(t *testing.T) {
}
}
func
TestDNSParseCorruptSRVReply
(
t
*
testing
.
T
)
{
func
TestDNSParseCorruptSRVReply
(
t
*
testing
.
T
)
{
if
runtime
.
GOOS
==
"windows"
{
return
}
data
,
err
:=
hex
.
DecodeString
(
dnsSRVCorruptReply
)
data
,
err
:=
hex
.
DecodeString
(
dnsSRVCorruptReply
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
...
...
src/pkg/net/dnsname_test.go
View file @
9ded954a
...
@@ -6,7 +6,6 @@ package net
...
@@ -6,7 +6,6 @@ package net
import
(
import
(
"testing"
"testing"
"runtime"
)
)
type
testCase
struct
{
type
testCase
struct
{
...
@@ -55,9 +54,6 @@ func getTestCases(ch chan<- testCase) {
...
@@ -55,9 +54,6 @@ func getTestCases(ch chan<- testCase) {
}
}
func
TestDNSNames
(
t
*
testing
.
T
)
{
func
TestDNSNames
(
t
*
testing
.
T
)
{
if
runtime
.
GOOS
==
"windows"
{
return
}
ch
:=
make
(
chan
testCase
)
ch
:=
make
(
chan
testCase
)
go
getTestCases
(
ch
)
go
getTestCases
(
ch
)
for
tc
:=
range
ch
{
for
tc
:=
range
ch
{
...
...
src/pkg/net/lookup.go
→
src/pkg/net/lookup
_unix
.go
View file @
9ded954a
...
@@ -6,6 +6,8 @@ package net
...
@@ -6,6 +6,8 @@ package net
import
(
import
(
"os"
"os"
"rand"
"sort"
)
)
// LookupHost looks up the given host using the local resolver.
// LookupHost looks up the given host using the local resolver.
...
@@ -48,3 +50,77 @@ func LookupCNAME(name string) (cname string, err os.Error) {
...
@@ -48,3 +50,77 @@ func LookupCNAME(name string) (cname string, err os.Error) {
}
}
return
return
}
}
// LookupSRV tries to resolve an SRV query of the given service,
// protocol, and domain name, as specified in RFC 2782. In most cases
// the proto argument can be the same as the corresponding
// Addr.Network(). The returned records are sorted by priority
// and randomized by weight within a priority.
func
LookupSRV
(
service
,
proto
,
name
string
)
(
cname
string
,
addrs
[]
*
SRV
,
err
os
.
Error
)
{
target
:=
"_"
+
service
+
"._"
+
proto
+
"."
+
name
var
records
[]
dnsRR
cname
,
records
,
err
=
lookup
(
target
,
dnsTypeSRV
)
if
err
!=
nil
{
return
}
addrs
=
make
([]
*
SRV
,
len
(
records
))
for
i
,
rr
:=
range
records
{
r
:=
rr
.
(
*
dnsRR_SRV
)
addrs
[
i
]
=
&
SRV
{
r
.
Target
,
r
.
Port
,
r
.
Priority
,
r
.
Weight
}
}
sort
.
Sort
(
byPriorityWeight
(
addrs
))
i
:=
0
for
j
:=
1
;
j
<
len
(
addrs
);
j
++
{
if
addrs
[
i
]
.
Priority
!=
addrs
[
j
]
.
Priority
{
shuffleSRVByWeight
(
addrs
[
i
:
j
])
i
=
j
}
}
shuffleSRVByWeight
(
addrs
[
i
:
len
(
addrs
)])
return
}
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
func
LookupMX
(
name
string
)
(
mx
[]
*
MX
,
err
os
.
Error
)
{
_
,
rr
,
err
:=
lookup
(
name
,
dnsTypeMX
)
if
err
!=
nil
{
return
}
mx
=
make
([]
*
MX
,
len
(
rr
))
for
i
:=
range
rr
{
r
:=
rr
[
i
]
.
(
*
dnsRR_MX
)
mx
[
i
]
=
&
MX
{
r
.
Mx
,
r
.
Pref
}
}
// Shuffle the records to match RFC 5321 when sorted
for
i
:=
range
mx
{
j
:=
rand
.
Intn
(
i
+
1
)
mx
[
i
],
mx
[
j
]
=
mx
[
j
],
mx
[
i
]
}
sort
.
Sort
(
byPref
(
mx
))
return
}
// LookupAddr performs a reverse lookup for the given address, returning a list
// of names mapping to that address.
func
LookupAddr
(
addr
string
)
(
name
[]
string
,
err
os
.
Error
)
{
name
=
lookupStaticAddr
(
addr
)
if
len
(
name
)
>
0
{
return
}
var
arpa
string
arpa
,
err
=
reverseaddr
(
addr
)
if
err
!=
nil
{
return
}
var
records
[]
dnsRR
_
,
records
,
err
=
lookup
(
arpa
,
dnsTypePTR
)
if
err
!=
nil
{
return
}
name
=
make
([]
string
,
len
(
records
))
for
i
:=
range
records
{
r
:=
records
[
i
]
.
(
*
dnsRR_PTR
)
name
[
i
]
=
r
.
Ptr
}
return
}
src/pkg/net/
resolv
_windows.go
→
src/pkg/net/
lookup
_windows.go
View file @
9ded954a
...
@@ -14,8 +14,8 @@ import (
...
@@ -14,8 +14,8 @@ import (
var
hostentLock
sync
.
Mutex
var
hostentLock
sync
.
Mutex
var
serventLock
sync
.
Mutex
var
serventLock
sync
.
Mutex
func
go
LookupHost
(
name
string
)
(
addrs
[]
string
,
err
os
.
Error
)
{
func
LookupHost
(
name
string
)
(
addrs
[]
string
,
err
os
.
Error
)
{
ips
,
err
:=
go
LookupIP
(
name
)
ips
,
err
:=
LookupIP
(
name
)
if
err
!=
nil
{
if
err
!=
nil
{
return
return
}
}
...
@@ -26,7 +26,7 @@ func goLookupHost(name string) (addrs []string, err os.Error) {
...
@@ -26,7 +26,7 @@ func goLookupHost(name string) (addrs []string, err os.Error) {
return
return
}
}
func
go
LookupIP
(
name
string
)
(
addrs
[]
IP
,
err
os
.
Error
)
{
func
LookupIP
(
name
string
)
(
addrs
[]
IP
,
err
os
.
Error
)
{
hostentLock
.
Lock
()
hostentLock
.
Lock
()
defer
hostentLock
.
Unlock
()
defer
hostentLock
.
Unlock
()
h
,
e
:=
syscall
.
GetHostByName
(
name
)
h
,
e
:=
syscall
.
GetHostByName
(
name
)
...
@@ -47,7 +47,23 @@ func goLookupIP(name string) (addrs []IP, err os.Error) {
...
@@ -47,7 +47,23 @@ func goLookupIP(name string) (addrs []IP, err os.Error) {
return
addrs
,
nil
return
addrs
,
nil
}
}
func
goLookupCNAME
(
name
string
)
(
cname
string
,
err
os
.
Error
)
{
func
LookupPort
(
network
,
service
string
)
(
port
int
,
err
os
.
Error
)
{
switch
network
{
case
"tcp4"
,
"tcp6"
:
network
=
"tcp"
case
"udp4"
,
"udp6"
:
network
=
"udp"
}
serventLock
.
Lock
()
defer
serventLock
.
Unlock
()
s
,
e
:=
syscall
.
GetServByName
(
service
,
network
)
if
e
!=
0
{
return
0
,
os
.
NewSyscallError
(
"GetServByName"
,
e
)
}
return
int
(
syscall
.
Ntohs
(
s
.
Port
)),
nil
}
func
LookupCNAME
(
name
string
)
(
cname
string
,
err
os
.
Error
)
{
var
r
*
syscall
.
DNSRecord
var
r
*
syscall
.
DNSRecord
e
:=
syscall
.
DnsQuery
(
name
,
syscall
.
DNS_TYPE_CNAME
,
0
,
nil
,
&
r
,
nil
)
e
:=
syscall
.
DnsQuery
(
name
,
syscall
.
DNS_TYPE_CNAME
,
0
,
nil
,
&
r
,
nil
)
if
int
(
e
)
!=
0
{
if
int
(
e
)
!=
0
{
...
@@ -61,13 +77,6 @@ func goLookupCNAME(name string) (cname string, err os.Error) {
...
@@ -61,13 +77,6 @@ func goLookupCNAME(name string) (cname string, err os.Error) {
return
return
}
}
type
SRV
struct
{
Target
string
Port
uint16
Priority
uint16
Weight
uint16
}
func
LookupSRV
(
service
,
proto
,
name
string
)
(
cname
string
,
addrs
[]
*
SRV
,
err
os
.
Error
)
{
func
LookupSRV
(
service
,
proto
,
name
string
)
(
cname
string
,
addrs
[]
*
SRV
,
err
os
.
Error
)
{
var
r
*
syscall
.
DNSRecord
var
r
*
syscall
.
DNSRecord
target
:=
"_"
+
service
+
"._"
+
proto
+
"."
+
name
target
:=
"_"
+
service
+
"._"
+
proto
+
"."
+
name
...
@@ -87,55 +96,12 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
...
@@ -87,55 +96,12 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return
name
,
addrs
,
nil
return
name
,
addrs
,
nil
}
}
func
goLookupPort
(
network
,
service
string
)
(
port
int
,
err
os
.
Error
)
{
// TODO(brainman): implement LookupMX and LookupAddr.
switch
network
{
case
"tcp4"
,
"tcp6"
:
network
=
"tcp"
case
"udp4"
,
"udp6"
:
network
=
"udp"
}
serventLock
.
Lock
()
defer
serventLock
.
Unlock
()
s
,
e
:=
syscall
.
GetServByName
(
service
,
network
)
if
e
!=
0
{
return
0
,
os
.
NewSyscallError
(
"GetServByName"
,
e
)
}
return
int
(
syscall
.
Ntohs
(
s
.
Port
)),
nil
}
// TODO(brainman): Following code is only to get tests running.
func
LookupMX
(
name
string
)
(
mx
[]
*
MX
,
err
os
.
Error
)
{
return
nil
,
os
.
NewSyscallError
(
"LookupMX"
,
syscall
.
EWINDOWS
)
func
isDomainName
(
s
string
)
bool
{
panic
(
"unimplemented"
)
}
func
reverseaddr
(
addr
string
)
(
arpa
string
,
err
os
.
Error
)
{
panic
(
"unimplemented"
)
}
func
answer
(
name
,
server
string
,
dns
*
dnsMsg
,
qtype
uint16
)
(
cname
string
,
addrs
[]
dnsRR
,
err
os
.
Error
)
{
panic
(
"unimplemented"
)
}
}
// DNSError represents a DNS lookup error.
func
LookupAddr
(
addr
string
)
(
name
[]
string
,
err
os
.
Error
)
{
type
DNSError
struct
{
return
nil
,
os
.
NewSyscallError
(
"LookupAddr"
,
syscall
.
EWINDOWS
)
Error
string
// description of the error
Name
string
// name looked for
Server
string
// server used
IsTimeout
bool
}
}
func
(
e
*
DNSError
)
String
()
string
{
if
e
==
nil
{
return
"<nil>"
}
s
:=
"lookup "
+
e
.
Name
if
e
.
Server
!=
""
{
s
+=
" on "
+
e
.
Server
}
s
+=
": "
+
e
.
Error
return
s
}
func
(
e
*
DNSError
)
Timeout
()
bool
{
return
e
.
IsTimeout
}
func
(
e
*
DNSError
)
Temporary
()
bool
{
return
e
.
IsTimeout
}
src/pkg/net/net_test.go
View file @
9ded954a
...
@@ -7,7 +7,6 @@ package net
...
@@ -7,7 +7,6 @@ package net
import
(
import
(
"flag"
"flag"
"regexp"
"regexp"
"runtime"
"testing"
"testing"
)
)
...
@@ -103,9 +102,6 @@ var revAddrTests = []struct {
...
@@ -103,9 +102,6 @@ var revAddrTests = []struct {
}
}
func
TestReverseAddress
(
t
*
testing
.
T
)
{
func
TestReverseAddress
(
t
*
testing
.
T
)
{
if
runtime
.
GOOS
==
"windows"
{
return
}
for
i
,
tt
:=
range
revAddrTests
{
for
i
,
tt
:=
range
revAddrTests
{
a
,
e
:=
reverseaddr
(
tt
.
Addr
)
a
,
e
:=
reverseaddr
(
tt
.
Addr
)
if
len
(
tt
.
ErrPrefix
)
>
0
&&
e
==
nil
{
if
len
(
tt
.
ErrPrefix
)
>
0
&&
e
==
nil
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment