Fix TCP sending
esp. when an imcomplete message is send back from the server. Fix {A,I}XFR also Add DNSError
This commit is contained in:
parent
43ebf75fac
commit
daf625264e
1
TODO
1
TODO
|
@ -14,6 +14,7 @@ Todo:
|
||||||
|
|
||||||
Issues:
|
Issues:
|
||||||
* Better sized buffers
|
* Better sized buffers
|
||||||
|
* Make the testsuite work with public DNS servers
|
||||||
* TC bit handling
|
* TC bit handling
|
||||||
* shortened ipv6 addresses are not parsed correctly
|
* shortened ipv6 addresses are not parsed correctly
|
||||||
* quoted quotes in txt records
|
* quoted quotes in txt records
|
||||||
|
|
14
dns.go
14
dns.go
|
@ -27,6 +27,20 @@ import (
|
||||||
|
|
||||||
const Year68 = 2 << (32 - 1)
|
const Year68 = 2 << (32 - 1)
|
||||||
|
|
||||||
|
type DNSError struct {
|
||||||
|
Error string
|
||||||
|
Name string
|
||||||
|
Server string
|
||||||
|
IsTimeout bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DNSError) String() string {
|
||||||
|
if e == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
return e.Error
|
||||||
|
}
|
||||||
|
|
||||||
type RR interface {
|
type RR interface {
|
||||||
Header() *RR_Header
|
Header() *RR_Header
|
||||||
String() string
|
String() string
|
||||||
|
|
|
@ -14,8 +14,8 @@ func TestAXFR(t *testing.T) {
|
||||||
res.Servers = []string{"127.0.0.1"}
|
res.Servers = []string{"127.0.0.1"}
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.Question = make([]dns.Question, 1)
|
m.Question = make([]dns.Question, 1)
|
||||||
// ask something
|
//m.Question[0] = dns.Question{"miek.nl", dns.TypeAXFR, dns.ClassINET}
|
||||||
m.Question[0] = dns.Question{"miek.nl", dns.TypeAXFR, dns.ClassINET}
|
m.Question[0] = dns.Question{"atoom.net", dns.TypeAXFR, dns.ClassINET}
|
||||||
|
|
||||||
ch <- DnsMsg{m, nil}
|
ch <- DnsMsg{m, nil}
|
||||||
for dm := range ch {
|
for dm := range ch {
|
||||||
|
|
|
@ -97,7 +97,7 @@ func query(res *Resolver, msg chan DnsMsg) {
|
||||||
} else {
|
} else {
|
||||||
c, cerr = net.Dial("udp", "", server)
|
c, cerr = net.Dial("udp", "", server)
|
||||||
}
|
}
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
if cerr != nil {
|
if cerr != nil {
|
||||||
err = cerr
|
err = cerr
|
||||||
continue
|
continue
|
||||||
|
@ -168,53 +168,53 @@ func axfr(res *Resolver, msg chan DnsMsg) {
|
||||||
err = cerr
|
err = cerr
|
||||||
continue SERVER
|
continue SERVER
|
||||||
}
|
}
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
first := true
|
first := true
|
||||||
// Start the AXFR
|
// Start the AXFR
|
||||||
for {
|
for {
|
||||||
if first {
|
if first {
|
||||||
in, cerr = exchange_tcp(c, sending, res, true)
|
in, cerr = exchange_tcp(c, sending, res, true)
|
||||||
} else {
|
} else {
|
||||||
in, cerr = exchange_tcp(c, sending, res, false)
|
in, cerr = exchange_tcp(c, sending, res, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cerr != nil {
|
if cerr != nil {
|
||||||
// Failed to send, try the next
|
// Failed to send, try the next
|
||||||
err = cerr
|
err = cerr
|
||||||
continue SERVER
|
continue SERVER
|
||||||
}
|
}
|
||||||
if first {
|
if first {
|
||||||
if !checkSOA(in, true) {
|
if !checkSOA(in, true) {
|
||||||
// SOA record not there...
|
// SOA record not there...
|
||||||
c.Close()
|
c.Close()
|
||||||
continue SERVER
|
continue SERVER
|
||||||
}
|
}
|
||||||
first = !first
|
first = !first
|
||||||
}
|
}
|
||||||
|
|
||||||
if !first {
|
if !first {
|
||||||
if !checkSOA(in, false) {
|
if !checkSOA(in, false) {
|
||||||
// Soa record not the last one
|
// Soa record not the last one
|
||||||
msg <- DnsMsg{in, nil}
|
msg <- DnsMsg{in, nil}
|
||||||
continue
|
continue
|
||||||
// next
|
// next
|
||||||
} else {
|
} else {
|
||||||
c.Close()
|
c.Close()
|
||||||
msg <- DnsMsg{in, nil}
|
msg <- DnsMsg{in, nil}
|
||||||
close(msg)
|
close(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(msg)
|
close(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// With 1 successfull server, we dont get here, so
|
// With 1 successfull server, we dont get here, so
|
||||||
// We've failed
|
// We've failed
|
||||||
msg <- DnsMsg{nil, err} // TODO Err
|
msg <- DnsMsg{nil, err} // TODO Err
|
||||||
close(msg)
|
close(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -240,13 +240,13 @@ func exchange_udp(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Er
|
||||||
attempts = r.Attempts
|
attempts = r.Attempts
|
||||||
}
|
}
|
||||||
for a := 0; a < attempts; a++ {
|
for a := 0; a < attempts; a++ {
|
||||||
if send {
|
if send {
|
||||||
_, err := c.Write(m)
|
_, err := c.Write(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//println("error writing")
|
//println("error writing")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SetReadTimeout(timeout * 1e9) // nanoseconds
|
c.SetReadTimeout(timeout * 1e9) // nanoseconds
|
||||||
buf := make([]byte, dns.DefaultMsgSize) // More than enough???
|
buf := make([]byte, dns.DefaultMsgSize) // More than enough???
|
||||||
|
@ -273,7 +273,7 @@ func exchange_udp(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Er
|
||||||
// Up to res.Attempts attempts.
|
// Up to res.Attempts attempts.
|
||||||
func exchange_tcp(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Error) {
|
func exchange_tcp(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Error) {
|
||||||
var timeout int64
|
var timeout int64
|
||||||
var attempts int
|
var attempts, n int
|
||||||
if r.Mangle != nil {
|
if r.Mangle != nil {
|
||||||
m = r.Mangle(m)
|
m = r.Mangle(m)
|
||||||
}
|
}
|
||||||
|
@ -294,20 +294,20 @@ func exchange_tcp(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Er
|
||||||
ls[0] = byte(len(m) >> 8)
|
ls[0] = byte(len(m) >> 8)
|
||||||
ls[1] = byte(len(m))
|
ls[1] = byte(len(m))
|
||||||
for a := 0; a < attempts; a++ {
|
for a := 0; a < attempts; a++ {
|
||||||
// only send something when told so
|
// only send something when told so
|
||||||
if send {
|
if send {
|
||||||
// With DNS over TCP we first send the length
|
// With DNS over TCP we first send the length
|
||||||
_, err := c.Write(ls)
|
_, err := c.Write(ls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// And then send the message
|
// And then send the message
|
||||||
_, err = c.Write(m)
|
_, err = c.Write(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SetReadTimeout(timeout * 1e9) // nanoseconds
|
c.SetReadTimeout(timeout * 1e9) // nanoseconds
|
||||||
// The server replies with two bytes length
|
// The server replies with two bytes length
|
||||||
|
@ -319,16 +319,19 @@ func exchange_tcp(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Er
|
||||||
// if length is 0??
|
// if length is 0??
|
||||||
// And then the message
|
// And then the message
|
||||||
buf := make([]byte, length)
|
buf := make([]byte, length)
|
||||||
_, err = c.Read(buf)
|
|
||||||
|
n, err = c.Read(buf)
|
||||||
if err != nil {
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
i := n
|
||||||
|
if i < int(length) {
|
||||||
|
n, err = c.Read(buf[i:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
i += n
|
||||||
|
}
|
||||||
in := new(dns.Msg)
|
in := new(dns.Msg)
|
||||||
if !in.Unpack(buf) {
|
if !in.Unpack(buf) {
|
||||||
// println("unpacking went wrong")
|
// println("unpacking went wrong")
|
||||||
|
|
Loading…
Reference in New Issue