dns/xfr.go

194 lines
4.7 KiB
Go
Raw Normal View History

2011-03-17 02:21:35 +11:00
package dns
2012-12-02 18:41:49 +11:00
// XfrMsg is used when doing [IA]xfr with a remote server.
type XfrMsg struct {
RR []RR // The set of RRs in the answer section of the AXFR reply message.
Error error // If something went wrong, this contains the error.
}
2012-08-28 03:48:58 +10:00
// XfrReceive performs a [AI]xfr request (depends on the message's Qtype). It returns
2012-12-02 18:41:49 +11:00
// a channel of *XfrMsg on which the replies from the server are sent. At the end of
2012-08-28 03:48:58 +10:00
// the transfer the channel is closed.
2012-12-02 18:45:47 +11:00
// The messages are TSIG checked if
2012-08-28 03:48:58 +10:00
// needed, no other post-processing is performed. The caller must dissect the returned
// messages.
//
// Basic use pattern for receiving an AXFR:
//
2012-08-28 04:58:58 +10:00
// // m contains the AXFR request
2012-08-28 03:48:58 +10:00
// t, e := client.XfrReceive(m, "127.0.0.1:53")
// for r := range t {
2012-08-28 04:58:58 +10:00
// // ... deal with r.RR or r.Error
2012-08-28 03:48:58 +10:00
// }
2012-12-02 18:41:49 +11:00
func (c *Client) XfrReceive(q *Msg, a string) (chan *XfrMsg, error) {
2011-04-19 06:08:12 +10:00
w := new(reply)
w.client = c
w.addr = a
2011-09-10 22:48:22 +10:00
w.req = q
2012-08-07 04:34:09 +10:00
if err := w.dial(); err != nil {
return nil, err
2011-09-12 06:10:04 +10:00
}
2012-08-07 04:34:09 +10:00
if err := w.send(q); err != nil {
return nil, err
2011-04-19 06:08:12 +10:00
}
2012-12-02 18:41:49 +11:00
e := make(chan *XfrMsg)
2011-03-22 02:28:13 +11:00
switch q.Question[0].Qtype {
case TypeAXFR:
go w.axfrReceive(q, e)
return e, nil
2011-03-22 02:28:13 +11:00
case TypeIXFR:
go w.ixfrReceive(q, e)
return e, nil
2011-09-12 06:10:04 +10:00
default:
2012-09-13 05:13:57 +10:00
return nil, nil
2011-03-22 02:28:13 +11:00
}
panic("dns: not reached")
2011-03-22 01:44:51 +11:00
}
2012-12-02 18:41:49 +11:00
func (w *reply) axfrReceive(q *Msg, c chan *XfrMsg) {
2011-04-19 06:08:12 +10:00
first := true
2012-08-23 18:33:33 +10:00
defer w.conn.Close()
defer close(c)
2011-03-22 01:44:51 +11:00
for {
2012-08-07 04:34:09 +10:00
in, err := w.receive()
2011-03-22 01:44:51 +11:00
if err != nil {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{nil, err}
2011-09-10 22:48:22 +10:00
return
2011-03-22 01:44:51 +11:00
}
if in.Id != q.Id {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, ErrId}
2011-09-12 01:01:55 +10:00
return
}
2011-03-22 01:44:51 +11:00
if first {
if !checkXfrSOA(in, true) {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, ErrSoa}
2011-09-10 22:48:22 +10:00
return
2011-03-22 01:44:51 +11:00
}
first = !first
}
2011-03-19 00:13:42 +11:00
2011-03-22 01:44:51 +11:00
if !first {
2011-04-19 06:08:12 +10:00
w.tsigTimersOnly = true // Subsequent envelopes use this.
2011-09-10 22:48:22 +10:00
if checkXfrSOA(in, false) {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, nil}
2011-09-10 22:48:22 +10:00
return
2011-03-22 01:44:51 +11:00
}
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, nil}
2011-03-22 01:44:51 +11:00
}
}
panic("dns: not reached")
2011-04-18 17:58:15 +10:00
}
2012-12-02 18:41:49 +11:00
func (w *reply) ixfrReceive(q *Msg, c chan *XfrMsg) {
2011-03-22 01:44:51 +11:00
var serial uint32 // The first serial seen is the current server serial
first := true
2012-08-23 18:33:33 +10:00
defer w.conn.Close()
defer close(c)
2011-03-22 01:44:51 +11:00
for {
2012-08-07 04:34:09 +10:00
in, err := w.receive()
2011-09-12 06:10:04 +10:00
if err != nil {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, err}
2011-09-12 06:10:04 +10:00
return
}
if q.Id != in.Id {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, ErrId}
2011-03-22 01:44:51 +11:00
return
}
if first {
// A single SOA RR signals "no changes"
if len(in.Answer) == 1 && checkXfrSOA(in, true) {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, nil}
2011-09-12 06:10:04 +10:00
return
2011-03-22 01:44:51 +11:00
}
// Check if the returned answer is ok
2011-03-22 01:44:51 +11:00
if !checkXfrSOA(in, true) {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, ErrSoa}
2011-03-22 01:44:51 +11:00
return
}
// This serial is important
serial = in.Answer[0].(*RR_SOA).Serial
first = !first
}
// Now we need to check each message for SOA records, to see what we need to do
if !first {
2011-09-12 06:10:04 +10:00
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 {
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, nil}
2011-09-12 06:10:04 +10:00
return
}
}
2012-12-02 18:41:49 +11:00
c <- &XfrMsg{in.Answer, nil}
2011-03-22 01:44:51 +11:00
}
}
panic("dns: not reached")
2011-03-19 00:13:42 +11:00
}
2011-09-12 01:24:52 +10:00
2011-03-22 02:28:13 +11:00
// Check if he SOA record exists in the Answer section of
// the packet. If first is true the first RR must be a SOA
2012-08-28 16:14:12 +10:00
// if false, the last one should be a SOA.
2011-03-22 02:28:13 +11:00
func checkXfrSOA(in *Msg, first bool) bool {
if len(in.Answer) > 0 {
if first {
return in.Answer[0].Header().Rrtype == TypeSOA
} else {
return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
}
}
return false
}
2012-08-28 16:14:12 +10:00
2012-08-28 19:03:41 +10:00
// XfrSend performs an outgoing [AI]xfr depending on the request message. The
// caller is responsible for sending the correct sequence of RR sets through
2012-12-02 18:41:49 +11:00
// the channel c. For reasons of symmetry XfrMsg is re-used.
2012-08-28 19:03:41 +10:00
// Errors are signaled via the error pointer, when an error occurs the function
// sets the error and returns (it does not close the channel).
// TSIG and enveloping is handled by XfrSend.
//
// Basic use pattern for sending an AXFR:
//
// // q contains the AXFR request
2012-12-02 18:41:49 +11:00
// c := make(chan *XfrMsg)
2012-08-28 19:03:41 +10:00
// var e *error
// err := XfrSend(w, q, c, e)
// w.Hijack() // hijack the connection so that the library doesn't close it
2012-08-28 19:03:41 +10:00
// for _, rrset := range rrsets { // rrset is a []RR
2012-12-02 18:41:49 +11:00
// c <- &{XfrMsg{RR: rrset}
2012-08-28 19:03:41 +10:00
// if e != nil {
// close(c)
// break
// }
// }
// // w.Close() // Don't! Let the client close the connection
2012-12-02 18:41:49 +11:00
func XfrSend(w ResponseWriter, q *Msg, c chan *XfrMsg, e *error) error {
2012-08-28 17:27:55 +10:00
switch q.Question[0].Qtype {
2011-11-03 09:06:54 +11:00
case TypeAXFR, TypeIXFR:
2012-08-28 17:27:55 +10:00
go axfrSend(w, q, c, e)
return nil
2011-09-12 06:10:04 +10:00
default:
2012-09-13 05:13:57 +10:00
return nil
2011-09-10 22:59:21 +10:00
}
2012-10-10 17:56:34 +11:00
panic("dns: not reached")
2011-09-10 22:59:21 +10:00
}
// TODO(mg): count the RRs and the resulting size.
2012-12-02 18:41:49 +11:00
func axfrSend(w ResponseWriter, req *Msg, c chan *XfrMsg, e *error) {
2012-08-28 04:58:58 +10:00
rep := new(Msg)
rep.SetReply(req)
2012-09-06 00:31:48 +10:00
rep.Authoritative = true
2012-08-28 04:58:58 +10:00
for x := range c {
2012-08-28 16:14:12 +10:00
// assume it fits
2012-08-28 04:58:58 +10:00
rep.Answer = append(rep.Answer, x.RR...)
if err := w.WriteMsg(rep); e != nil {
2012-08-28 17:27:55 +10:00
*e = err
return
}
2012-08-28 21:12:55 +10:00
w.TsigTimersOnly(true)
2012-08-28 04:58:58 +10:00
rep.Answer = nil
}
}