Fix DNS over TCP

Actually send the 2 bytes length and also be prepared
to receive them.
This commit is contained in:
Miek Gieben 2010-12-31 14:11:52 +01:00
parent cc66917658
commit 0dcdbe4361
7 changed files with 96 additions and 8 deletions

View File

@ -17,17 +17,20 @@ include $(GOROOT)/src/Make.pkg
all: package
gomake -C dnssec package
gomake -C resolver package
# gomake -C xfr package
# gomake -C strconv package
install: $(INSTALLFILES)
gomake -C dnssec install
gomake -C resolver install
# gomake -C xfr package
# gomake -C strconv install
dnstest:
gotest
gomake -C dnssec test
gomake -C resolver test
# gomake -C xfr test
# gomake -C strconv test
_examples:

7
TODO
View File

@ -2,16 +2,21 @@ Todo:
* DNSSEC validation
* NSEC(3) secure denial of existence
* fix os.Erros usage, add DNSSEC related errors
* AXFR/IXFR support
* AXFR/IXFR support
* Notify support (send/receive)
* TKEY -- RFC 2930
* TSIG -- RFC 4635
* IDN?
* Unknown RRs?
* query-time, server in string ouput of dns.Msg
* Parsing from strings
* Server support (signing, receiving queries)
* Check the network order, it works now, but this is on Intel
Issues:
* Better sized buffers
* TC bit handling
* Fix TCP: should read 2 bytes of length
* shortened ipv6 addresses are not parsed correctly
* quoted quotes in txt records
* Convience functions?

View File

@ -4,4 +4,5 @@
include $(GOROOT)/src/Make.inc
TARG=q
GOFILES=q.go
DEPS=../../
include $(GOROOT)/src/Make.cmd

4
dns.go
View File

@ -6,13 +6,15 @@
// Package dns implements a full featured interface to the DNS.
// Supported RFCs and features include:
// * 1982 - Serial Arithmetic
// * 1034/1035
// * 1034/1035
// * 1876 - LOC record (incomplete)
// * 1995 - IXFR
// * 2671 - EDNS
// * 2915 - NAPTR record (incomplete)
// * 3225 - DO bit (DNSSEC OK)
// * 4033/4034/4035 - DNSSEC + validation functions
// * 5011 - NSID
// * 5936 - AXFR
// * IP6 support
// The package allows full control over what is send out to the DNS.
//

2
msg.go
View File

@ -60,6 +60,8 @@ var Rr_str = map[uint16]string{
TypeDNSKEY: "DNSKEY",
TypeNSEC3: "NSEC3",
TypeNSEC3PARAM: "NSEC3PARAM",
TypeAXFR: "AXFR", // Not real RRs
TypeIXFR: "IXFR",
}

View File

@ -88,14 +88,14 @@ func query(res *Resolver, msg chan DnsMsg) {
out.Dns.Id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
sending, ok := out.Dns.Pack()
if !ok {
println("pack failed")
//println("pack failed")
msg <- DnsMsg{nil, nil} // todo error
continue;
}
for i := 0; i < len(res.Servers); i++ {
server := res.Servers[i] + ":" + port
if res.Tcp == true {
if res.Tcp {
c, cerr = net.Dial("tcp", "", server)
} else {
c, cerr = net.Dial("udp", "", server)
@ -104,8 +104,14 @@ func query(res *Resolver, msg chan DnsMsg) {
err = cerr
continue
}
in, err = exchange(c, sending, res)
if res.Tcp {
in, err = exchange_tcp(c, sending, res)
} else {
in, err = exchange_udp(c, sending, res)
}
// Check id in.id != out.id
// TODO(mg)
c.Close()
if err != nil {
@ -124,7 +130,7 @@ func query(res *Resolver, msg chan DnsMsg) {
// Send a request on the connection and hope for a reply.
// Up to res.Attempts attempts.
func exchange(c net.Conn, m []byte, r *Resolver) (*dns.Msg, os.Error) {
func exchange_udp(c net.Conn, m []byte, r *Resolver) (*dns.Msg, os.Error) {
var timeout int64
var attempts int
if r.Mangle != nil {
@ -140,17 +146,19 @@ func exchange(c net.Conn, m []byte, r *Resolver) (*dns.Msg, os.Error) {
} else {
attempts = r.Attempts
}
for a:= 0; a < attempts; a++ {
n, err := c.Write(m)
if err != nil {
//println("error writing")
return nil, err
}
c.SetReadTimeout(timeout * 1e9) // nanoseconds
buf := make([]byte, dns.DefaultMsgSize) // More than enough.
buf := make([]byte, dns.DefaultMsgSize) // More than enough???
n, err = c.Read(buf)
if err != nil {
//println("error reading")
//println(err.String())
// More Go foo needed
//if e, ok := err.(Error); ok && e.Timeout() {
// continue
@ -166,3 +174,69 @@ func exchange(c net.Conn, m []byte, r *Resolver) (*dns.Msg, os.Error) {
}
return nil, nil // todo error
}
// Up to res.Attempts attempts.
func exchange_tcp(c net.Conn, m []byte, r *Resolver) (*dns.Msg, os.Error) {
var timeout int64
var attempts int
if r.Mangle != nil {
m = r.Mangle(m)
}
if r.Timeout == 0 {
timeout = 1
} else {
timeout = int64(r.Timeout)
}
if r.Attempts == 0 {
attempts = 1
} else {
attempts = r.Attempts
}
ls := make([]byte, 2) // sender length
lr := make([]byte, 2) // receiver length
var length uint16
ls[0] = byte(len(m) >> 8)
ls[1] = byte(len(m))
for a := 0; a < attempts; a++ {
// With DNS over TCP we first send the length
_, err := c.Write(ls)
if err != nil {
return nil, err
}
// And then send the message
_, err = c.Write(m)
if err != nil {
return nil, err
}
c.SetReadTimeout(timeout * 1e9) // nanoseconds
// The server replies with two bytes length
_, err = c.Read(lr)
if err != nil {
return nil, err
}
length = uint16(lr[0])<<8 | uint16(lr[1])
// if length is 0??
// And then the message
buf := make([]byte, length)
_, err = c.Read(buf)
if err != nil {
//println("error reading")
//println(err.String())
// More Go foo needed
//if e, ok := err.(Error); ok && e.Timeout() {
// continue
//}
return nil, err
}
in := new(dns.Msg)
if !in.Unpack(buf) {
// println("unpacking went wrong")
continue
}
return in, nil
}
return nil, nil // todo error
}

View File

@ -60,6 +60,7 @@ const (
TypeNSEC3PARAM = 51
// valid Question.qtype only
TypeIXFR = 251
TypeAXFR = 252
TypeMAILB = 253
TypeMAILA = 254