Add Ixfr back in
Fix ixfr. Don't be smart about iterpreting the ixfr itself, just funnel the packets back to the client, but do obey the ixfr algorithm
This commit is contained in:
parent
d367484d6f
commit
caf69b662c
89
xfr.go
89
xfr.go
|
@ -8,38 +8,44 @@ import (
|
|||
// section contains an AXFR type an Axfr is performed. If q's question
|
||||
// section contains an IXFR type an Ixfr is performed.
|
||||
// Each message will be send along the Client's reply channel as it
|
||||
// is received.
|
||||
// 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) os.Error {
|
||||
w := new(reply)
|
||||
w.client = c
|
||||
w.addr = a
|
||||
w.req = q
|
||||
|
||||
if err := w.Dial(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.Send(q); err != nil {
|
||||
return err
|
||||
}
|
||||
// conn should be set now
|
||||
switch q.Question[0].Qtype {
|
||||
case TypeAXFR:
|
||||
go w.axfrReceive()
|
||||
case TypeIXFR:
|
||||
// go w.ixfrReceive()
|
||||
go w.ixfrReceive()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *reply) axfrReceive() {
|
||||
first := true
|
||||
defer w.Close()
|
||||
for {
|
||||
in, err := w.Receive()
|
||||
if err != nil {
|
||||
w.Client().ChannelReply <- &Exchange{Request: w.req, Reply: in, Error: err}
|
||||
w.Client().ChannelReply <- &Exchange{w.req, in, err}
|
||||
return
|
||||
}
|
||||
/* id check */
|
||||
|
||||
if first {
|
||||
if !checkXfrSOA(in, true) {
|
||||
w.Client().ChannelReply <- &Exchange{Request: w.req, Reply: in, Error: ErrXfrSoa}
|
||||
w.Client().ChannelReply <- &Exchange{w.req, in, ErrXfrSoa}
|
||||
return
|
||||
}
|
||||
first = !first
|
||||
|
@ -47,44 +53,43 @@ func (w *reply) axfrReceive() {
|
|||
|
||||
if !first {
|
||||
w.tsigTimersOnly = true // Subsequent envelopes use this.
|
||||
w.Client().ChannelReply <- &Exchange{Request: w.req, Reply: in}
|
||||
if checkXfrSOA(in, false) {
|
||||
w.Client().ChannelReply <- &Exchange{w.req, in, ErrXfrLast}
|
||||
return
|
||||
}
|
||||
w.Client().ChannelReply <- &Exchange{Request: w.req, Reply: in}
|
||||
}
|
||||
}
|
||||
panic("not reached")
|
||||
return
|
||||
}
|
||||
/*
|
||||
|
||||
func (d *Conn) ixfrReceive(q *Msg, m chan *Xfr) {
|
||||
defer close(m)
|
||||
func (w *reply) ixfrReceive() {
|
||||
var serial uint32 // The first serial seen is the current server serial
|
||||
var x *Xfr
|
||||
first := true
|
||||
in := new(Msg)
|
||||
defer w.Close()
|
||||
for {
|
||||
in, err := w.Receive()
|
||||
if err != nil {
|
||||
w.Client().ChannelReply <- &Exchange{w.req, in, err}
|
||||
return
|
||||
}
|
||||
|
||||
err := d.ReadMsg(in)
|
||||
if err != nil {
|
||||
m <- &Xfr{true, nil, err}
|
||||
return
|
||||
}
|
||||
if in.Id != q.Id {
|
||||
m <- &Xfr{true, nil, ErrId}
|
||||
if w.req.Id != in.Id {
|
||||
w.Client().ChannelReply <- &Exchange{w.req, in, ErrId}
|
||||
return
|
||||
}
|
||||
|
||||
if first {
|
||||
// A single SOA RR signals "no changes"
|
||||
if len(in.Answer) == 1 && checkXfrSOA(in, true) {
|
||||
return
|
||||
w.Client().ChannelReply <- &Exchange{w.req, in, ErrXfrLast}
|
||||
return
|
||||
}
|
||||
|
||||
// But still check if the returned answer is ok
|
||||
// Check if the returned answer is ok
|
||||
if !checkXfrSOA(in, true) {
|
||||
m <- &Xfr{true, nil, ErrXfrSoa}
|
||||
w.Client().ChannelReply <- &Exchange{w.req, in, ErrXfrSoa}
|
||||
return
|
||||
}
|
||||
// This serial is important
|
||||
|
@ -93,40 +98,22 @@ func (d *Conn) ixfrReceive(q *Msg, m chan *Xfr) {
|
|||
}
|
||||
|
||||
// Now we need to check each message for SOA records, to see what we need to do
|
||||
x.Add = true
|
||||
if !first {
|
||||
if d.Tsig != nil {
|
||||
d.Tsig.TimersOnly = true
|
||||
}
|
||||
for k, r := range in.Answer {
|
||||
// If the last record in the IXFR contains the servers' SOA, we should quit
|
||||
if r.Header().Rrtype == TypeSOA {
|
||||
switch {
|
||||
case r.(*RR_SOA).Serial == serial:
|
||||
if k == len(in.Answer)-1 {
|
||||
// last rr is SOA with correct serial
|
||||
//m <- r dont' send it
|
||||
return
|
||||
}
|
||||
x.Add = true
|
||||
if k != 0 {
|
||||
// Intermediate SOA
|
||||
continue
|
||||
}
|
||||
case r.(*RR_SOA).Serial != serial:
|
||||
x.Add = false
|
||||
continue // Don't need to see this SOA
|
||||
}
|
||||
}
|
||||
x.RR = r
|
||||
m <- x
|
||||
}
|
||||
w.tsigTimersOnly = true
|
||||
// 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().ChannelReply <- &Exchange{w.req, in, ErrXfrLast}
|
||||
return
|
||||
}
|
||||
}
|
||||
w.Client().ChannelReply <- &Exchange{Request: w.req, Reply: in}
|
||||
}
|
||||
}
|
||||
panic("not reached")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
// Perform an outgoing Ixfr or Axfr. If the message q's question
|
||||
// section contains an AXFR type an Axfr is performed. If q's question
|
||||
// section contains an IXFR type an Ixfr is performed.
|
||||
|
@ -195,7 +182,7 @@ func (d *Conn) axfrWrite(q *Msg, m chan *Xfr, e chan os.Error) {
|
|||
*/
|
||||
|
||||
// Check if he SOA record exists in the Answer section of
|
||||
// the packet. If first is true the first RR must be a soa
|
||||
// the packet. If first is true the first RR must be a SOA
|
||||
// if false, the last one should be a SOA
|
||||
func checkXfrSOA(in *Msg, first bool) bool {
|
||||
if len(in.Answer) > 0 {
|
||||
|
|
Loading…
Reference in New Issue