summaryrefslogtreecommitdiff
path: root/src/pkg/net/dnsclient.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/net/dnsclient.go')
-rw-r--r--src/pkg/net/dnsclient.go63
1 files changed, 48 insertions, 15 deletions
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index ea21117e3..f1cd47bb1 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -15,9 +15,9 @@
package net
import (
- "once"
"os"
"rand"
+ "sync"
"time"
)
@@ -30,6 +30,9 @@ type DNSError struct {
}
func (e *DNSError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
s := "lookup " + e.Name
if e.Server != "" {
s += " on " + e.Server
@@ -52,7 +55,7 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Er
out := new(dnsMsg)
out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
out.question = []dnsQuestion{
- dnsQuestion{name, qtype, dnsClassINET},
+ {name, qtype, dnsClassINET},
}
out.recursion_desired = true
msg, ok := out.Pack()
@@ -189,42 +192,46 @@ var dnserr os.Error
func loadConfig() { cfg, dnserr = dnsReadConfig() }
func isDomainName(s string) bool {
- // Requirements on DNS name:
- // * must not be empty.
- // * must be alphanumeric plus - and .
- // * each of the dot-separated elements must begin
- // and end with a letter or digit.
- // RFC 1035 required the element to begin with a letter,
- // but RFC 3696 says this has been relaxed to allow digits too.
- // still, there must be a letter somewhere in the entire name.
+ // See RFC 1035, RFC 3696.
if len(s) == 0 {
return false
}
+ if len(s) > 255 {
+ return false
+ }
if s[len(s)-1] != '.' { // simplify checking loop: make name end in dot
s += "."
}
last := byte('.')
ok := false // ok once we've seen a letter
+ partlen := 0
for i := 0; i < len(s); i++ {
c := s[i]
switch {
default:
return false
- case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
ok = true
+ partlen++
case '0' <= c && c <= '9':
// fine
+ partlen++
case c == '-':
// byte before dash cannot be dot
if last == '.' {
return false
}
+ partlen++
case c == '.':
// byte before dot cannot be dot, dash
if last == '.' || last == '-' {
return false
}
+ if partlen > 63 || partlen == 0 {
+ return false
+ }
+ partlen = 0
}
last = c
}
@@ -232,11 +239,13 @@ func isDomainName(s string) bool {
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}
}
- once.Do(loadConfig)
+ onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
return
@@ -290,7 +299,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
// It returns the canonical name for the host and an array of that
// host's addresses.
func LookupHost(name string) (cname string, addrs []string, err os.Error) {
- once.Do(loadConfig)
+ onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
return
@@ -317,9 +326,14 @@ type SRV struct {
Weight uint16
}
-func LookupSRV(name string) (cname string, addrs []*SRV, err os.Error) {
+// 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().
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
var records []dnsRR
- cname, records, err = lookup(name, dnsTypeSRV)
+ cname, records, err = lookup(target, dnsTypeSRV)
if err != nil {
return
}
@@ -330,3 +344,22 @@ func LookupSRV(name string) (cname string, addrs []*SRV, err os.Error) {
}
return
}
+
+type MX struct {
+ Host string
+ Pref uint16
+}
+
+func LookupMX(name string) (entries []*MX, err os.Error) {
+ var records []dnsRR
+ _, records, err = lookup(name, dnsTypeMX)
+ if err != nil {
+ return
+ }
+ entries = make([]*MX, len(records))
+ for i := 0; i < len(records); i++ {
+ r := records[i].(*dnsRR_MX)
+ entries[i] = &MX{r.Mx, r.Pref}
+ }
+ return
+}