xfr.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. package dns
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. // Envelope is used when doing a zone transfer with a remote server.
  7. type Envelope struct {
  8. RR []RR // The set of RRs in the answer section of the xfr reply message.
  9. Error error // If something went wrong, this contains the error.
  10. }
  11. // A Transfer defines parameters that are used during a zone transfer.
  12. type Transfer struct {
  13. *Conn
  14. DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
  15. ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
  16. WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
  17. TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
  18. tsigTimersOnly bool
  19. }
  20. // Think we need to away to stop the transfer
  21. // In performs an incoming transfer with the server in a.
  22. // If you would like to set the source IP, or some other attribute
  23. // of a Dialer for a Transfer, you can do so by specifying the attributes
  24. // in the Transfer.Conn:
  25. //
  26. // d := net.Dialer{LocalAddr: transfer_source}
  27. // con, err := d.Dial("tcp", master)
  28. // dnscon := &dns.Conn{Conn:con}
  29. // transfer = &dns.Transfer{Conn: dnscon}
  30. // channel, err := transfer.In(message, master)
  31. //
  32. func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
  33. timeout := dnsTimeout
  34. if t.DialTimeout != 0 {
  35. timeout = t.DialTimeout
  36. }
  37. if t.Conn == nil {
  38. t.Conn, err = DialTimeout("tcp", a, timeout)
  39. if err != nil {
  40. return nil, err
  41. }
  42. }
  43. if err := t.WriteMsg(q); err != nil {
  44. return nil, err
  45. }
  46. env = make(chan *Envelope)
  47. go func() {
  48. if q.Question[0].Qtype == TypeAXFR {
  49. go t.inAxfr(q, env)
  50. return
  51. }
  52. if q.Question[0].Qtype == TypeIXFR {
  53. go t.inIxfr(q, env)
  54. return
  55. }
  56. }()
  57. return env, nil
  58. }
  59. func (t *Transfer) inAxfr(q *Msg, c chan *Envelope) {
  60. first := true
  61. defer t.Close()
  62. defer close(c)
  63. timeout := dnsTimeout
  64. if t.ReadTimeout != 0 {
  65. timeout = t.ReadTimeout
  66. }
  67. for {
  68. t.Conn.SetReadDeadline(time.Now().Add(timeout))
  69. in, err := t.ReadMsg()
  70. if err != nil {
  71. c <- &Envelope{nil, err}
  72. return
  73. }
  74. if q.Id != in.Id {
  75. c <- &Envelope{in.Answer, ErrId}
  76. return
  77. }
  78. if first {
  79. if in.Rcode != RcodeSuccess {
  80. c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
  81. return
  82. }
  83. if !isSOAFirst(in) {
  84. c <- &Envelope{in.Answer, ErrSoa}
  85. return
  86. }
  87. first = !first
  88. // only one answer that is SOA, receive more
  89. if len(in.Answer) == 1 {
  90. t.tsigTimersOnly = true
  91. c <- &Envelope{in.Answer, nil}
  92. continue
  93. }
  94. }
  95. if !first {
  96. t.tsigTimersOnly = true // Subsequent envelopes use this.
  97. if isSOALast(in) {
  98. c <- &Envelope{in.Answer, nil}
  99. return
  100. }
  101. c <- &Envelope{in.Answer, nil}
  102. }
  103. }
  104. }
  105. func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) {
  106. serial := uint32(0) // The first serial seen is the current server serial
  107. axfr := true
  108. n := 0
  109. qser := q.Ns[0].(*SOA).Serial
  110. defer t.Close()
  111. defer close(c)
  112. timeout := dnsTimeout
  113. if t.ReadTimeout != 0 {
  114. timeout = t.ReadTimeout
  115. }
  116. for {
  117. t.SetReadDeadline(time.Now().Add(timeout))
  118. in, err := t.ReadMsg()
  119. if err != nil {
  120. c <- &Envelope{nil, err}
  121. return
  122. }
  123. if q.Id != in.Id {
  124. c <- &Envelope{in.Answer, ErrId}
  125. return
  126. }
  127. if in.Rcode != RcodeSuccess {
  128. c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
  129. return
  130. }
  131. if n == 0 {
  132. // Check if the returned answer is ok
  133. if !isSOAFirst(in) {
  134. c <- &Envelope{in.Answer, ErrSoa}
  135. return
  136. }
  137. // This serial is important
  138. serial = in.Answer[0].(*SOA).Serial
  139. // Check if there are no changes in zone
  140. if qser >= serial {
  141. c <- &Envelope{in.Answer, nil}
  142. return
  143. }
  144. }
  145. // Now we need to check each message for SOA records, to see what we need to do
  146. t.tsigTimersOnly = true
  147. for _, rr := range in.Answer {
  148. if v, ok := rr.(*SOA); ok {
  149. if v.Serial == serial {
  150. n++
  151. // quit if it's a full axfr or the the servers' SOA is repeated the third time
  152. if axfr && n == 2 || n == 3 {
  153. c <- &Envelope{in.Answer, nil}
  154. return
  155. }
  156. } else if axfr {
  157. // it's an ixfr
  158. axfr = false
  159. }
  160. }
  161. }
  162. c <- &Envelope{in.Answer, nil}
  163. }
  164. }
  165. // Out performs an outgoing transfer with the client connecting in w.
  166. // Basic use pattern:
  167. //
  168. // ch := make(chan *dns.Envelope)
  169. // tr := new(dns.Transfer)
  170. // go tr.Out(w, r, ch)
  171. // ch <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}}
  172. // close(ch)
  173. // w.Hijack()
  174. // // w.Close() // Client closes connection
  175. //
  176. // The server is responsible for sending the correct sequence of RRs through the
  177. // channel ch.
  178. func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
  179. for x := range ch {
  180. r := new(Msg)
  181. // Compress?
  182. r.SetReply(q)
  183. r.Authoritative = true
  184. // assume it fits TODO(miek): fix
  185. r.Answer = append(r.Answer, x.RR...)
  186. if err := w.WriteMsg(r); err != nil {
  187. return err
  188. }
  189. }
  190. w.TsigTimersOnly(true)
  191. return nil
  192. }
  193. // ReadMsg reads a message from the transfer connection t.
  194. func (t *Transfer) ReadMsg() (*Msg, error) {
  195. m := new(Msg)
  196. p := make([]byte, MaxMsgSize)
  197. n, err := t.Read(p)
  198. if err != nil && n == 0 {
  199. return nil, err
  200. }
  201. p = p[:n]
  202. if err := m.Unpack(p); err != nil {
  203. return nil, err
  204. }
  205. if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
  206. if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
  207. return m, ErrSecret
  208. }
  209. // Need to work on the original message p, as that was used to calculate the tsig.
  210. err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
  211. t.tsigRequestMAC = ts.MAC
  212. }
  213. return m, err
  214. }
  215. // WriteMsg writes a message through the transfer connection t.
  216. func (t *Transfer) WriteMsg(m *Msg) (err error) {
  217. var out []byte
  218. if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
  219. if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
  220. return ErrSecret
  221. }
  222. out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
  223. } else {
  224. out, err = m.Pack()
  225. }
  226. if err != nil {
  227. return err
  228. }
  229. if _, err = t.Write(out); err != nil {
  230. return err
  231. }
  232. return nil
  233. }
  234. func isSOAFirst(in *Msg) bool {
  235. if len(in.Answer) > 0 {
  236. return in.Answer[0].Header().Rrtype == TypeSOA
  237. }
  238. return false
  239. }
  240. func isSOALast(in *Msg) bool {
  241. if len(in.Answer) > 0 {
  242. return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
  243. }
  244. return false
  245. }
  246. const errXFR = "bad xfr rcode: %d"