Fixes for axfr,ixfr

This commit is contained in:
Miek Gieben 2011-02-25 20:23:33 +01:00
parent 2b5a97570a
commit c1297a4f9c
2 changed files with 105 additions and 94 deletions

View File

@ -9,7 +9,7 @@ func main() {
res := new(dns.Resolver)
res.FromFile("/etc/resolv.conf")
ch := make(chan *dns.Msg)
ch := make(chan dns.RR)
m := new(dns.Msg)
m.Question = make([]dns.Question, 1)

View File

@ -94,94 +94,11 @@ func (res *Resolver) Query(q *Msg) (d *Msg, err os.Error) {
return in, nil
}
// Start an AXFR, q should contain a message with the question
// for an AXFR: "miek.nl" ANY AXFR. All incoming axfr snippets
// are returned on the channel m. The function closes the
// channel to signal the end of the AXFR.
func (res *Resolver) Ixfr(q *Msg, m chan *Msg) {
var port string
var err os.Error
var in *Msg
if res.Port == "" {
port = "53"
} else {
port = res.Port
}
var _ = err // TODO(mg)
if q.Id == 0 {
q.SetId()
}
sending, ok := q.Pack()
if !ok {
m <- nil
return
}
Server:
for i := 0; i < len(res.Servers); i++ {
server := res.Servers[i] + ":" + port
c, cerr := net.Dial("tcp", "", server)
if cerr != nil {
err = cerr
continue Server
}
first := true
// Start the AXFR
for {
if first {
in, cerr = exchangeTCP(c, sending, res, true)
} else {
in, err = exchangeTCP(c, sending, res, false)
}
if cerr != nil {
// Failed to send, try the next
err = cerr
c.Close()
continue Server
}
if in.Id != q.Id {
m <- nil
return
}
if first {
if !checkSOA(in, true) {
c.Close()
continue Server
}
m <- in
first = !first
}
if !first {
if !checkSOA(in, false) {
// Soa record not the last one
m <- in
continue
} else {
c.Close()
m <- in
close(m)
return
}
}
}
panic("not reached")
return
}
close(m)
return
}
// Start an IXFR, q should contain a message with the question
// for an IXFR: "miek.nl" ANY IXFR. All incoming ixfr snippets
// are returned on the channel m. The function closes the
// channel to signal the end of the IXFR.
func (res *Resolver) Axfr(q *Msg, m chan *Msg) {
func (res *Resolver) Ixfr(q *Msg, m chan RR) {
var port string
var err os.Error
var in *Msg
@ -203,6 +120,7 @@ func (res *Resolver) Axfr(q *Msg, m chan *Msg) {
return
}
defer close(m)
Server:
for i := 0; i < len(res.Servers); i++ {
server := res.Servers[i] + ":" + port
@ -212,7 +130,10 @@ Server:
continue Server
}
first := true
// Start the AXFR
var serial int // The first serial seen is the current server serial
var _ = serial
defer c.Close()
for {
if first {
in, cerr = exchangeTCP(c, sending, res, true)
@ -227,28 +148,112 @@ Server:
continue Server
}
if in.Id != q.Id {
m <- nil
// Query ID mismatch
c.Close()
return
}
if first {
// A single SOA RR signals "no changes"
if len(in.Answer) == 1 && checkSOA(in, true) {
c.Close()
return
}
// But still check if the returned answer is ok
if !checkSOA(in, true) {
c.Close()
continue Server
}
// This serial is important
serial = int(in.Answer[0].(*RR_SOA).Serial)
sendFromMsg(in, m)
first = !first
}
// Now we need to check each message for SOA records, to see what we need to do
if !first {
}
}
panic("not reached")
return
}
return
}
// Start an AXFR, q should contain a message with the question
// for an AXFR: "miek.nl" ANY AXFR. All incoming axfr snippets
// are returned on the channel m. The function closes the
// channel to signal the end of the AXFR.
func (res *Resolver) Axfr(q *Msg, m chan RR) {
var port string
var err os.Error
var in *Msg
if res.Port == "" {
port = "53"
} else {
port = res.Port
}
var _ = err // TODO(mg)
if q.Id == 0 {
q.SetId()
}
sending, ok := q.Pack()
if !ok {
m <- nil
return
}
defer close(m)
Server:
for i := 0; i < len(res.Servers); i++ {
server := res.Servers[i] + ":" + port
c, cerr := net.Dial("tcp", "", server)
if cerr != nil {
err = cerr
continue Server
}
first := true
defer c.Close() // TODO(mg): if not open?
for {
if first {
in, cerr = exchangeTCP(c, sending, res, true)
} else {
in, err = exchangeTCP(c, sending, res, false)
}
if cerr != nil {
// Failed to send, try the next
err = cerr
c.Close()
continue Server
}
if in.Id != q.Id {
c.Close()
return
}
if first {
if !checkSOA(in, true) {
c.Close()
c.Close()
continue Server
}
m <- in
sendFromMsg(in, m)
first = !first
}
if !first {
if !checkSOA(in, false) {
// Soa record not the last one
m <- in
sendFromMsg(in, m)
continue
} else {
c.Close()
m <- in
close(m)
c.Close()
sendFromMsg(in, m)
return
}
}
@ -256,7 +261,6 @@ Server:
panic("not reached")
return
}
close(m)
return
}
@ -431,3 +435,10 @@ func checkSOA(in *Msg, first bool) bool {
}
return false
}
// Send the answer section to the channel
func sendFromMsg(in *Msg, c chan RR) {
for _, r := range in.Answer {
c <- r
}
}