Fix incoming [IA]xfr
Make the function return a new channel, which is closed at the end of the transfer. This way you can just use 'range' to loop over the records.
This commit is contained in:
parent
d0e4f0409a
commit
f26963f4c3
|
@ -30,17 +30,13 @@ func main() {
|
|||
m.SetTsig(name, dns.HmacMD5, 300, m.MsgHdr.Id, time.Now().Unix())
|
||||
}
|
||||
|
||||
if err := client.XfrReceive(m, *nameserver); err == nil {
|
||||
for r := range client.ReplyChan {
|
||||
if r.Error != nil {
|
||||
if r.Error == dns.ErrXfrLast {
|
||||
fmt.Printf("%v\n", r.Reply)
|
||||
}
|
||||
break
|
||||
if t, e := client.XfrReceive(m, *nameserver); e == nil {
|
||||
for r := range t {
|
||||
if r.Error == nil {
|
||||
fmt.Printf("%v\n", r.Reply)
|
||||
}
|
||||
fmt.Printf("%v\n", r.Reply)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Error %v\n", err)
|
||||
fmt.Printf("Error %v\n", e)
|
||||
}
|
||||
}
|
||||
|
|
63
xfr.go
63
xfr.go
|
@ -1,48 +1,59 @@
|
|||
package dns
|
||||
|
||||
// XfrReceives requests an incoming Ixfr or Axfr. If the message q's question
|
||||
// section contains an AXFR type an Axfr is performed, if it is IXFR it does an Ixfr.
|
||||
// Each message will be send along the Client's reply channel as it is received.
|
||||
// The last message send has Exchange.Error set to ErrXfrLast
|
||||
// to signal there is nothing more to come.
|
||||
func (c *Client) XfrReceive(q *Msg, a string) error {
|
||||
// section has type TypeAXFR an Axfr is performed, if it is TypeIXFR it does an Ixfr.
|
||||
// The [AI]xfr's records are returned on the channel. Note the with an IXFR the client
|
||||
// needs to determine if records are to be removed are added.
|
||||
// The channel is closed when the transfer is terminated.
|
||||
//
|
||||
// Basic use pattern for setting up a transfer:
|
||||
//
|
||||
// t, _ := client.XfrReceive(m, "127.0.0.1:53")
|
||||
// for r := range t {
|
||||
// //
|
||||
// }
|
||||
func (c *Client) XfrReceive(q *Msg, a string) (chan *Exchange, error) {
|
||||
w := new(reply)
|
||||
w.client = c
|
||||
w.addr = a
|
||||
w.req = q
|
||||
if err := w.Dial(); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if err := w.Send(q); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
e := make(chan *Exchange)
|
||||
switch q.Question[0].Qtype {
|
||||
case TypeAXFR:
|
||||
go w.axfrReceive()
|
||||
go w.axfrReceive(e)
|
||||
return e, nil
|
||||
case TypeIXFR:
|
||||
go w.ixfrReceive()
|
||||
go w.ixfrReceive(e)
|
||||
return e, nil
|
||||
default:
|
||||
return ErrXfrType
|
||||
return nil, ErrXfrType
|
||||
}
|
||||
return nil
|
||||
panic("not reached")
|
||||
}
|
||||
|
||||
func (w *reply) axfrReceive() {
|
||||
func (w *reply) axfrReceive(c chan *Exchange) {
|
||||
first := true
|
||||
defer w.Close()
|
||||
defer close(c)
|
||||
for {
|
||||
in, err := w.Receive()
|
||||
if err != nil {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), err}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), err}
|
||||
return
|
||||
}
|
||||
if w.req.Id != in.Id {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrId}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrId}
|
||||
return
|
||||
}
|
||||
if first {
|
||||
if !checkXfrSOA(in, true) {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrSoa}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrSoa}
|
||||
return
|
||||
}
|
||||
first = !first
|
||||
|
@ -51,41 +62,40 @@ func (w *reply) axfrReceive() {
|
|||
if !first {
|
||||
w.tsigTimersOnly = true // Subsequent envelopes use this.
|
||||
if checkXfrSOA(in, false) {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrLast}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrLast}
|
||||
return
|
||||
}
|
||||
w.Client().ReplyChan <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: nil}
|
||||
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: nil}
|
||||
}
|
||||
}
|
||||
panic("not reached")
|
||||
return
|
||||
}
|
||||
|
||||
func (w *reply) ixfrReceive() {
|
||||
func (w *reply) ixfrReceive(c chan *Exchange) {
|
||||
var serial uint32 // The first serial seen is the current server serial
|
||||
first := true
|
||||
defer w.Close()
|
||||
defer close(c)
|
||||
for {
|
||||
in, err := w.Receive()
|
||||
if err != nil {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), err}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), err}
|
||||
return
|
||||
}
|
||||
if w.req.Id != in.Id {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrId}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrId}
|
||||
return
|
||||
}
|
||||
|
||||
if first {
|
||||
// A single SOA RR signals "no changes"
|
||||
if len(in.Answer) == 1 && checkXfrSOA(in, true) {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrLast}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), nil}
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the returned answer is ok
|
||||
if !checkXfrSOA(in, true) {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrSoa}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrSoa}
|
||||
return
|
||||
}
|
||||
// This serial is important
|
||||
|
@ -99,15 +109,14 @@ func (w *reply) ixfrReceive() {
|
|||
// If the last record in the IXFR contains the servers' SOA, we should quit
|
||||
if v, ok := in.Answer[len(in.Answer)-1].(*RR_SOA); ok {
|
||||
if v.Serial == serial {
|
||||
w.Client().ReplyChan <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrLast}
|
||||
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), nil}
|
||||
return
|
||||
}
|
||||
}
|
||||
w.Client().ReplyChan <- &Exchange{Request: w.req, Reply: in}
|
||||
c <- &Exchange{Request: w.req, Reply: in}
|
||||
}
|
||||
}
|
||||
panic("not reached")
|
||||
return
|
||||
}
|
||||
|
||||
// XfrSend performs an outgoing Ixfr or Axfr. The function is xfr agnostic, it is
|
||||
|
|
Loading…
Reference in New Issue