| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | // Package taprw takes a query and intercepts the response.
 | 
					
						
							|  |  |  | // It will log both after the response is written.
 | 
					
						
							|  |  |  | package taprw
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							|  |  |  | 	"fmt"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/middleware/dnstap/msg"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tap "github.com/dnstap/golang-dnstap"
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | // Tapper is what ResponseWriter needs to log to dnstap.
 | 
					
						
							|  |  |  | type Tapper interface {
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | 	TapMessage(m *tap.Message) error
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | 	TapBuilder() msg.Builder
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | // ResponseWriter captures the client response and logs the query to dnstap.
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | // Single request use.
 | 
					
						
							|  |  |  | type ResponseWriter struct {
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | 	queryEpoch uint64
 | 
					
						
							|  |  |  | 	Query      *dns.Msg
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | 	dns.ResponseWriter
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | 	Tapper
 | 
					
						
							|  |  |  | 	err error
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | // DnstapError check if a dnstap error occurred during Write and returns it.
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | func (w ResponseWriter) DnstapError() error {
 | 
					
						
							|  |  |  | 	return w.err
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | // QueryEpoch sets the query epoch as reported by dnstap.
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | func (w *ResponseWriter) QueryEpoch() {
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | 	w.queryEpoch = msg.Epoch()
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | // WriteMsg writes back the response to the client and THEN works on logging the request
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | // and response to dnstap.
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | // Dnstap errors are to be checked by DnstapError.
 | 
					
						
							|  |  |  | func (w *ResponseWriter) WriteMsg(resp *dns.Msg) (writeErr error) {
 | 
					
						
							|  |  |  | 	writeErr = w.ResponseWriter.WriteMsg(resp)
 | 
					
						
							|  |  |  | 	writeEpoch := msg.Epoch()
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | 	b := w.TapBuilder()
 | 
					
						
							|  |  |  | 	b.TimeSec = w.queryEpoch
 | 
					
						
							|  |  |  | 	if err := func() (err error) {
 | 
					
						
							|  |  |  | 		err = b.AddrMsg(w.ResponseWriter.RemoteAddr(), w.Query)
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		return w.TapMessage(b.ToClientQuery())
 | 
					
						
							|  |  |  | 	}(); err != nil {
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | 		w.err = fmt.Errorf("client query: %s", err)
 | 
					
						
							|  |  |  | 		// don't forget to call DnstapError later
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if writeErr == nil {
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | 		if err := func() (err error) {
 | 
					
						
							|  |  |  | 			b.TimeSec = writeEpoch
 | 
					
						
							|  |  |  | 			if err = b.Msg(resp); err != nil {
 | 
					
						
							|  |  |  | 				return
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			return w.TapMessage(b.ToClientResponse())
 | 
					
						
							|  |  |  | 		}(); err != nil {
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | 			w.err = fmt.Errorf("client response: %s", err)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 12:41:41 +02:00
										 |  |  | 	return
 | 
					
						
							| 
									
										
										
										
											2017-07-24 23:12:50 +02:00
										 |  |  | }
 |