xfr.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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 fully qualified
  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.Id, env)
  50. return
  51. }
  52. if q.Question[0].Qtype == TypeIXFR {
  53. go t.inIxfr(q.Id, env)
  54. return
  55. }
  56. }()
  57. return env, nil
  58. }
  59. func (t *Transfer) inAxfr(id uint16, 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 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(id uint16, c chan *Envelope) {
  106. serial := uint32(0) // The first serial seen is the current server serial
  107. first := true
  108. defer t.Close()
  109. defer close(c)
  110. timeout := dnsTimeout
  111. if t.ReadTimeout != 0 {
  112. timeout = t.ReadTimeout
  113. }
  114. for {
  115. t.SetReadDeadline(time.Now().Add(timeout))
  116. in, err := t.ReadMsg()
  117. if err != nil {
  118. c <- &Envelope{nil, err}
  119. return
  120. }
  121. if id != in.Id {
  122. c <- &Envelope{in.Answer, ErrId}
  123. return
  124. }
  125. if first {
  126. if in.Rcode != RcodeSuccess {
  127. c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
  128. return
  129. }
  130. // A single SOA RR signals "no changes"
  131. if len(in.Answer) == 1 && isSOAFirst(in) {
  132. c <- &Envelope{in.Answer, nil}
  133. return
  134. }
  135. // Check if the returned answer is ok
  136. if !isSOAFirst(in) {
  137. c <- &Envelope{in.Answer, ErrSoa}
  138. return
  139. }
  140. // This serial is important
  141. serial = in.Answer[0].(*SOA).Serial
  142. first = !first
  143. }
  144. // Now we need to check each message for SOA records, to see what we need to do
  145. if !first {
  146. t.tsigTimersOnly = true
  147. // If the last record in the IXFR contains the servers' SOA, we should quit
  148. if v, ok := in.Answer[len(in.Answer)-1].(*SOA); ok {
  149. if v.Serial == serial {
  150. c <- &Envelope{in.Answer, nil}
  151. return
  152. }
  153. }
  154. c <- &Envelope{in.Answer, nil}
  155. }
  156. }
  157. }
  158. // Out performs an outgoing transfer with the client connecting in w.
  159. // Basic use pattern:
  160. //
  161. // ch := make(chan *dns.Envelope)
  162. // tr := new(dns.Transfer)
  163. // go tr.Out(w, r, ch)
  164. // ch <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}}
  165. // close(ch)
  166. // w.Hijack()
  167. // // w.Close() // Client closes connection
  168. //
  169. // The server is responsible for sending the correct sequence of RRs through the
  170. // channel ch.
  171. func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
  172. for x := range ch {
  173. r := new(Msg)
  174. // Compress?
  175. r.SetReply(q)
  176. r.Authoritative = true
  177. // assume it fits TODO(miek): fix
  178. r.Answer = append(r.Answer, x.RR...)
  179. if err := w.WriteMsg(r); err != nil {
  180. return err
  181. }
  182. }
  183. w.TsigTimersOnly(true)
  184. return nil
  185. }
  186. // ReadMsg reads a message from the transfer connection t.
  187. func (t *Transfer) ReadMsg() (*Msg, error) {
  188. m := new(Msg)
  189. p := make([]byte, MaxMsgSize)
  190. n, err := t.Read(p)
  191. if err != nil && n == 0 {
  192. return nil, err
  193. }
  194. p = p[:n]
  195. if err := m.Unpack(p); err != nil {
  196. return nil, err
  197. }
  198. if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
  199. if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
  200. return m, ErrSecret
  201. }
  202. // Need to work on the original message p, as that was used to calculate the tsig.
  203. err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
  204. t.tsigRequestMAC = ts.MAC
  205. }
  206. return m, err
  207. }
  208. // WriteMsg writes a message through the transfer connection t.
  209. func (t *Transfer) WriteMsg(m *Msg) (err error) {
  210. var out []byte
  211. if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
  212. if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
  213. return ErrSecret
  214. }
  215. out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
  216. } else {
  217. out, err = m.Pack()
  218. }
  219. if err != nil {
  220. return err
  221. }
  222. if _, err = t.Write(out); err != nil {
  223. return err
  224. }
  225. return nil
  226. }
  227. func isSOAFirst(in *Msg) bool {
  228. if len(in.Answer) > 0 {
  229. return in.Answer[0].Header().Rrtype == TypeSOA
  230. }
  231. return false
  232. }
  233. func isSOALast(in *Msg) bool {
  234. if len(in.Answer) > 0 {
  235. return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
  236. }
  237. return false
  238. }
  239. const errXFR = "bad xfr rcode: %d"