Read/Write works, but axfr still fails

This commit is contained in:
Miek Gieben 2011-03-20 19:58:55 +01:00
parent de9a1da6aa
commit b1f63f57c4
6 changed files with 162 additions and 363 deletions

View File

@ -37,5 +37,4 @@ func (dns *Msg) SetAxfr(z string, class uint16) {
dns.Question = make([]Question, 1)
dns.Question[0] = Question{z, TypeAXFR, class}
}
// IsIxfr/IsAxfr?

32
dns.go
View File

@ -51,11 +51,16 @@ func (e *Error) String() string {
type Conn struct {
// The current UDP connection.
UDP *net.UDPConn
// The current TCP connection.
TCP *net.TCPConn
// The remote side of the connection.
Addr net.Addr
// If TSIG is used, this holds all the information
Signature *Tsig
// Timeout in sec
Timeout int
@ -69,16 +74,21 @@ func (d *Conn) Read(p []byte) (n int, err os.Error) {
}
switch {
case d.UDP != nil:
n, err = d.UDP.Read(p)
var addr net.Addr
n, addr, err = d.UDP.ReadFromUDP(p)
if err != nil {
return n, err
}
d.Addr = addr
case d.TCP != nil:
n, err = d.TCP.Read(p[0:1])
if len(p) < 1 {
return 0, &Error{Error: "Buffer too small to read"}
}
n, err = d.TCP.Read(p[0:2])
if err != nil || n != 2 {
return n, err
}
l, _ := unpackUint16(p[0:1], 0)
l, _ := unpackUint16(p[0:2], 0)
if l == 0 {
return 0, &Error{Error: "received nil msg length", Server: d.Addr}
}
@ -182,17 +192,15 @@ func (d *Conn) SetTimeout() (err os.Error) {
return
}
// Fix those here...!
// ReadTsig
// WriteTsig
func (d *Conn) Exchange(request []byte, nosend bool) (reply []byte, err os.Error) {
var n int
n, err = d.Write(request)
if err != nil {
return nil, err
}
// Layer violation to safe memory. (Its okay then.)
if !nosend {
n, err = d.Write(request)
if err != nil {
return nil, err
}
}
// Layer violation to save memory. Its okay then...
if d.UDP == nil {
reply = make([]byte, MaxMsgSize)
} else {

5
msg.go
View File

@ -16,7 +16,7 @@ package dns
import (
"os"
// "fmt"
"fmt"
"reflect"
"net"
"rand"
@ -210,6 +210,7 @@ func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
Loop:
for {
if off >= len(msg) {
println(off, len(msg))
return "", len(msg), false
}
c := int(msg[off])
@ -657,7 +658,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
case "domain-name":
s, off, ok = unpackDomainName(msg, off)
if !ok {
//fmt.Fprintf(os.Stderr, "dns: failure unpacking domain-name")
fmt.Fprintf(os.Stderr, "dns: failure unpacking domain-name")
return len(msg), false
}
case "size-base32":

View File

@ -45,54 +45,40 @@ type Resolver struct {
//
// Note that message id checking is left to the caller.
func (res *Resolver) Query(q *Msg) (d *Msg, err os.Error) {
var (
c net.Conn
port string
inb []byte
)
in := new(Msg)
if len(res.Servers) == 0 {
return nil, &Error{Error: "No servers defined"}
}
if res.Rtt == nil {
res.Rtt = make(map[string]int64)
}
if res.Port == "" {
port = "53"
} else {
port = res.Port
var c net.Conn
var inb []byte
in := new(Msg)
port, err := check(res, q)
if err != nil {
return nil, err
}
if q.Id == 0 {
// No Id sed, set it
q.Id = Id()
}
sending, ok := q.Pack()
if !ok {
return nil, &Error{Error: ErrPack}
}
for i := 0; i < len(res.Servers); i++ {
d := new(Conn)
d := new(Conn)
server := res.Servers[i] + ":" + port
t := time.Nanoseconds()
if res.Tcp {
c, err = net.Dial("tcp", "", server)
d.TCP = c.(*net.TCPConn)
d.Addr = d.TCP.RemoteAddr()
d.TCP = c.(*net.TCPConn)
d.Addr = d.TCP.RemoteAddr()
} else {
c, err = net.Dial("udp", "", server)
d.UDP = c.(*net.UDPConn)
d.Addr = d.UDP.RemoteAddr()
d.UDP = c.(*net.UDPConn)
d.Addr = d.UDP.RemoteAddr()
}
if err != nil {
continue
}
inb, err = d.Exchange(sending, false)
if err != nil {
continue
}
in.Unpack(inb)
}
inb, err = d.Exchange(sending, false)
if err != nil {
continue
}
in.Unpack(inb)
res.Rtt[server] = time.Nanoseconds() - t
c.Close()
break
@ -118,22 +104,13 @@ type Xfr struct {
func (res *Resolver) Ixfr(q *Msg, m chan Xfr) {
// TSIG
var (
port string
x Xfr
inb []byte
)
x Xfr
inb []byte
)
in := new(Msg)
if res.Port == "" {
port = "53"
} else {
port = res.Port
}
if res.Rtt == nil {
res.Rtt = make(map[string]int64)
}
if q.Id == 0 {
q.Id = Id()
port, err := check(res, q)
if err != nil {
return
}
defer close(m)
@ -149,36 +126,37 @@ Server:
if err != nil {
continue Server
}
first := true
var serial uint32 // The first serial seen is the current server serial
d := new(Conn)
d.TCP = c.(*net.TCPConn)
d.Addr = d.TCP.RemoteAddr()
first := true
defer c.Close()
for {
if first {
inb, err = exchangeTCP(c, sending, res, true)
in.Unpack(inb)
inb, err = d.Exchange(sending, false)
} else {
inb, err = exchangeTCP(c, sending, res, false)
in.Unpack(inb)
inb, err = d.Exchange(sending, true)
}
if err != nil {
// Failed to send, try the next
c.Close()
continue Server
}
in.Unpack(inb) // error!
if in.Id != q.Id {
return
}
if first {
// A single SOA RR signals "no changes"
if len(in.Answer) == 1 && checkAxfrSOA(in, true) {
if len(in.Answer) == 1 && checkXfrSOA(in, true) {
return
}
// But still check if the returned answer is ok
if !checkAxfrSOA(in, true) {
if !checkXfrSOA(in, true) {
c.Close()
continue Server
}
@ -228,22 +206,11 @@ Server:
// the zone as-is. Xfr.Add is always true.
// The channel is closed to signal the end of the AXFR.
func (res *Resolver) AxfrTSIG(q *Msg, m chan Xfr, secret string) {
var (
port string
inb []byte
)
var inb []byte
in := new(Msg)
if res.Port == "" {
port = "53"
} else {
port = res.Port
}
if res.Rtt == nil {
res.Rtt = make(map[string]int64)
}
if q.Id == 0 {
q.Id = Id()
port, err := check(res, q)
if err != nil {
return
}
defer close(m)
@ -252,14 +219,14 @@ func (res *Resolver) AxfrTSIG(q *Msg, m chan Xfr, secret string) {
return
}
var tsig bool
var reqmac string
var tsig bool
var reqmac string
// Check if there is a TSIG added to the request msg
if len(q.Extra) > 0 {
tsig = q.Extra[len(q.Extra)-1].Header().Rrtype == TypeTSIG
if tsig {
reqmac = q.Extra[len(q.Extra)-1].(*RR_TSIG).MAC
}
tsig = q.Extra[len(q.Extra)-1].Header().Rrtype == TypeTSIG
if tsig {
reqmac = q.Extra[len(q.Extra)-1].(*RR_TSIG).MAC
}
}
Server:
@ -269,42 +236,44 @@ Server:
if err != nil {
continue Server
}
d := new(Conn)
d.TCP = c.(*net.TCPConn)
d.Addr = d.TCP.RemoteAddr()
first := true
defer c.Close() // TODO(mg): if not open?
for {
if first {
inb, err = exchangeTCP(c, sending, res, true)
in.Unpack(inb)
inb, err = d.Exchange(sending, false)
} else {
inb, err = exchangeTCP(c, sending, res, false)
in.Unpack(inb)
inb, err = d.Exchange(sending, true)
}
if err != nil {
// Failed to send, try the next
c.Close()
continue Server
}
in.Unpack(inb)
if in.Id != q.Id {
c.Close()
return
}
if tsig && len(in.Extra) > 0 { // What if not included?
t := in.Extra[len(in.Extra)-1]
if t.Header().Rrtype == TypeTSIG {
if t.(*RR_TSIG).Verify(inb, secret, reqmac, first) {
// Set the MAC for the next round.
reqmac = t.(*RR_TSIG).MAC
} else {
c.Close()
return
}
}
}
if tsig && len(in.Extra) > 0 { // What if not included?
t := in.Extra[len(in.Extra)-1]
if t.Header().Rrtype == TypeTSIG {
if t.(*RR_TSIG).Verify(inb, secret, reqmac, first) {
// Set the MAC for the next round.
reqmac = t.(*RR_TSIG).MAC
} else {
c.Close()
return
}
}
}
if first {
if !checkAxfrSOA(in, true) {
if !checkXfrSOA(in, true) {
c.Close()
continue Server
}
@ -312,12 +281,12 @@ Server:
}
if !first {
if !checkAxfrSOA(in, false) {
if !checkXfrSOA(in, false) {
// Soa record not the last one
sendFromMsg(in, m, false)
sendMsg(in, m, false)
continue
} else {
sendFromMsg(in, m, true)
sendMsg(in, m, true)
return
}
}
@ -335,23 +304,12 @@ Server:
// the zone as-is. Xfr.Add is always true.
// The channel is closed to signal the end of the AXFR.
func (res *Resolver) Axfr(q *Msg, m chan Xfr) {
var (
port string
inb []byte
)
var inb []byte
port, err := check(res, q)
if err != nil {
return
}
in := new(Msg)
if res.Port == "" {
port = "53"
} else {
port = res.Port
}
if res.Rtt == nil {
res.Rtt = make(map[string]int64)
}
if q.Id == 0 {
q.Id = Id()
}
defer close(m)
sending, ok := q.Pack()
@ -366,29 +324,31 @@ Server:
if err != nil {
continue Server
}
d := new(Conn)
d.TCP = c.(*net.TCPConn)
d.Addr = d.TCP.RemoteAddr()
first := true
defer c.Close() // TODO(mg): if not open?
for {
if first {
inb, err = exchangeTCP(c, sending, res, true)
in.Unpack(inb)
inb, err = d.Exchange(sending, false)
} else {
inb, err = exchangeTCP(c, sending, res, false)
in.Unpack(inb)
inb, err = d.Exchange(sending, true)
}
if err != nil {
// Failed to send, try the next
c.Close()
continue Server
}
if !in.Unpack(inb) {
println("Failed to unpack")
}
if in.Id != q.Id {
c.Close()
return
}
if first {
if !checkAxfrSOA(in, true) {
if !checkXfrSOA(in, true) {
c.Close()
continue Server
}
@ -396,12 +356,12 @@ Server:
}
if !first {
if !checkAxfrSOA(in, false) {
if !checkXfrSOA(in, false) {
// Soa record not the last one
sendFromMsg(in, m, false)
sendMsg(in, m, false)
continue
} else {
sendFromMsg(in, m, true)
sendMsg(in, m, true)
return
}
}
@ -412,158 +372,10 @@ Server:
return
}
// Send a request on the connection and hope for a reply.
// Up to res.Attempts attempts. If send is false, nothing
// is send.
func exchangeUDP(c net.Conn, m []byte, r *Resolver, send bool) ([]byte, 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
}
for a := 0; a < attempts; a++ {
if send {
err := sendUDP(m, c)
if err != nil {
if e, ok := err.(net.Error); ok && e.Timeout() {
continue
}
return nil, err
}
}
c.SetReadTimeout(timeout * 1e9) // nanoseconds
buf, err := recvUDP(c)
if err != nil {
if e, ok := err.(net.Error); ok && e.Timeout() {
continue
}
return nil, err
}
return buf, nil
}
return nil, &Error{Error: ErrServ}
}
// Up to res.Attempts attempts.
func exchangeTCP(c net.Conn, m []byte, r *Resolver, send bool) ([]byte, 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
}
for a := 0; a < attempts; a++ {
// only send something when told so
if send {
err := sendTCP(m, c)
if err != nil {
if e, ok := err.(net.Error); ok && e.Timeout() {
continue
}
return nil, err
}
}
c.SetReadTimeout(timeout * 1e9) // nanoseconds
// The server replies with two bytes length.
buf, err := recvTCP(c)
if err != nil {
if e, ok := err.(net.Error); ok && e.Timeout() {
continue
}
return nil, err
}
return buf, nil
}
return nil, &Error{Error: ErrServ}
}
func sendUDP(m []byte, c net.Conn) os.Error {
_, err := c.Write(m)
if err != nil {
return err
}
return nil
}
func recvUDP(c net.Conn) ([]byte, os.Error) {
m := make([]byte, DefaultMsgSize)
n, err := c.Read(m)
if err != nil {
return nil, err
}
m = m[:n]
return m, nil
}
func sendTCP(m []byte, c net.Conn) os.Error {
l := make([]byte, 2)
l[0] = byte(len(m) >> 8)
l[1] = byte(len(m))
// First we send the length
_, err := c.Write(l)
if err != nil {
return err
}
// And the the message
_, err = c.Write(m)
if err != nil {
return err
}
return nil
}
func recvTCP(c net.Conn) ([]byte, os.Error) {
l := make([]byte, 2) // The server replies with two bytes length.
_, err := c.Read(l)
if err != nil {
return nil, err
}
length := uint16(l[0])<<8 | uint16(l[1])
if length == 0 {
return nil, &Error{Error: "received nil msg length", Server: c.RemoteAddr()}
}
m := make([]byte, length)
n, cerr := c.Read(m)
if cerr != nil {
return nil, cerr
}
i := n
for i < int(length) {
n, err = c.Read(m[i:])
if err != nil {
return nil, err
}
i += n
}
return m, nil
}
// Check if he SOA record exists in the Answer section of
// the packet. If first is true the first RR must be a soa
// if false, the last one should be a SOA
func checkAxfrSOA(in *Msg, first bool) bool {
func checkXfrSOA(in *Msg, first bool) bool {
if len(in.Answer) > 0 {
if first {
return in.Answer[0].Header().Rrtype == TypeSOA
@ -575,7 +387,7 @@ func checkAxfrSOA(in *Msg, first bool) bool {
}
// Send the answer section to the channel
func sendFromMsg(in *Msg, c chan Xfr, nosoa bool) {
func sendMsg(in *Msg, c chan Xfr, nosoa bool) {
x := Xfr{Add: true}
for k, r := range in.Answer {
if nosoa && k == len(in.Answer)-1 {
@ -585,3 +397,19 @@ func sendFromMsg(in *Msg, c chan Xfr, nosoa bool) {
c <- x
}
}
// Some assorted checks on the resolver
func check(res *Resolver, q *Msg) (port string, err os.Error) {
if res.Port == "" {
port = "53"
} else {
port = res.Port
}
if res.Rtt == nil {
res.Rtt = make(map[string]int64)
}
if q.Id == 0 {
q.Id = Id()
}
return
}

View File

@ -11,71 +11,58 @@ import (
"net"
)
// Do I want this
type Server struct {
ServeUDP func(*net.UDPConn, net.Addr, *Msg) os.Error
ServeTCP func(*net.TCPConn, net.Addr, *Msg) os.Error
/* notify stuff here? */
/* tsig here */
}
// For both -> logging
func ServeUDP(l *net.UDPConn, f func(*net.UDPConn, net.Addr, *Msg)) os.Error {
func ServeUDP(l *net.UDPConn, f func(*Conn, *Msg)) os.Error {
for {
m := make([]byte, DefaultMsgSize)
n, radd, e := l.ReadFromUDP(m)
n, addr, e := l.ReadFromUDP(m)
if e != nil {
continue
}
m = m[:n]
d := new(Conn)
d.UDP = l
d.Addr = addr
msg := new(Msg)
if !msg.Unpack(m) {
continue
}
go f(l, radd, msg)
go f(d, msg)
}
panic("not reached")
}
func ServeTCP(l *net.TCPListener, f func(*net.TCPConn, net.Addr, *Msg)) os.Error {
b := make([]byte, 2)
func ServeTCP(l *net.TCPListener, f func(*Conn, *Msg)) os.Error {
for {
c, e := l.AcceptTCP()
if e != nil {
return e
}
n, e := c.Read(b)
if e != nil {
continue
}
d := new(Conn)
d.TCP = c
d.Addr = c.RemoteAddr()
length := uint16(b[0])<<8 | uint16(b[1])
if length == 0 {
return &Error{Error: "received nil msg length"}
}
m := make([]byte, length)
m := make([]byte, MaxMsgSize) // This may start to hurt someday.
n, e := d.Read(m)
if e != nil {
continue
}
m = m[:n]
n, e = c.Read(m)
if e != nil {
continue
}
i := n
if i < int(length) {
n, e = c.Read(m[i:])
if e != nil {
continue
}
i += n
}
msg := new(Msg)
if !msg.Unpack(m) {
// Logging??
continue
}
go f(c, c.RemoteAddr(), msg)
go f(d, msg)
}
panic("not reached")
}
func ListenAndServeTCP(addr string, f func(*net.TCPConn, net.Addr, *Msg)) os.Error {
func ListenAndServeTCP(addr string, f func(*Conn, *Msg)) os.Error {
a, err := net.ResolveTCPAddr(addr)
if err != nil {
return err
@ -88,7 +75,7 @@ func ListenAndServeTCP(addr string, f func(*net.TCPConn, net.Addr, *Msg)) os.Err
return err
}
func ListenAndServeUDP(addr string, f func(*net.UDPConn, net.Addr, *Msg)) os.Error {
func ListenAndServeUDP(addr string, f func(*Conn, *Msg)) os.Error {
a, err := net.ResolveUDPAddr(addr)
if err != nil {
return err
@ -100,39 +87,3 @@ func ListenAndServeUDP(addr string, f func(*net.UDPConn, net.Addr, *Msg)) os.Err
err = ServeUDP(l, f)
return err
}
// Send a buffer on the TCP connection.
func SendTCP(m []byte, c *net.TCPConn, a net.Addr) os.Error {
l := make([]byte, 2)
l[0] = byte(len(m) >> 8)
l[1] = byte(len(m))
// First we send the length
n, err := c.Write(l)
if err != nil {
return err
}
// And the the message
n, err = c.Write(m)
if err != nil {
return err
}
i := n
for i < len(m) {
n, err = c.Write(m)
if err != nil {
return err
}
i += n
}
return nil
}
// Send a buffer to the remove address. Only here because
// of the symmetry with SendTCP().
func SendUDP(m []byte, c *net.UDPConn, a net.Addr) os.Error {
_, err := c.WriteTo(m, a)
if err != nil {
return err
}
return nil
}

14
tsig.go
View File

@ -10,6 +10,19 @@ import (
"encoding/hex"
)
type Tsig struct {
// The name of the key.
Name string
Fudge uint16
TimeSigned uint64
Algorithm string
// Tsig secret encoded in base64.
Secret string
// MAC (if known)
MAC string
}
// HMAC hashing codes. These are transmitted as domain names.
const (
HmacMD5 = "hmac-md5.sig-alg.reg.int."
@ -34,7 +47,6 @@ func (rr *RR_TSIG) Header() *RR_Header {
return &rr.Hdr
}
// move to defaults.go?
func (rr *RR_TSIG) SetDefaults() {
rr.Header().Ttl = 0
rr.Header().Class = ClassANY