diff options
Diffstat (limited to 'middleware/dnstap')
-rw-r--r-- | middleware/dnstap/README.md | 61 | ||||
-rw-r--r-- | middleware/dnstap/handler.go | 79 | ||||
-rw-r--r-- | middleware/dnstap/handler_test.go | 65 | ||||
-rw-r--r-- | middleware/dnstap/msg/msg.go | 168 | ||||
-rw-r--r-- | middleware/dnstap/msg/msg_test.go | 42 | ||||
-rw-r--r-- | middleware/dnstap/msg/wrapper.go | 26 | ||||
-rw-r--r-- | middleware/dnstap/out/socket.go | 86 | ||||
-rw-r--r-- | middleware/dnstap/out/socket_test.go | 94 | ||||
-rw-r--r-- | middleware/dnstap/out/tcp.go | 59 | ||||
-rw-r--r-- | middleware/dnstap/out/tcp_test.go | 66 | ||||
-rw-r--r-- | middleware/dnstap/setup.go | 98 | ||||
-rw-r--r-- | middleware/dnstap/setup_test.go | 34 | ||||
-rw-r--r-- | middleware/dnstap/taprw/writer.go | 73 | ||||
-rw-r--r-- | middleware/dnstap/taprw/writer_test.go | 82 | ||||
-rw-r--r-- | middleware/dnstap/test/helpers.go | 80 |
15 files changed, 0 insertions, 1113 deletions
diff --git a/middleware/dnstap/README.md b/middleware/dnstap/README.md deleted file mode 100644 index d91c9422c..000000000 --- a/middleware/dnstap/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# dnstap - -*dnstap* enables logging to dnstap, a flexible, structured binary log format for DNS software: http://dnstap.info. - -There is a buffer, expect at least 13 requests before the server sends its dnstap messages to the socket. - -## Syntax - -~~~ txt -dnstap SOCKET [full] -~~~ - -* **SOCKET** is the socket path supplied to the dnstap command line tool. -* `full` to include the wire-format DNS message. - -## Examples - -Log information about client requests and responses to */tmp/dnstap.sock*. - -~~~ txt -dnstap /tmp/dnstap.sock -~~~ - -Log information including the wire-format DNS message about client requests and responses to */tmp/dnstap.sock*. - -~~~ txt -dnstap unix:///tmp/dnstap.sock full -~~~ - -Log to a remote endpoint. - -~~~ txt -dnstap tcp://127.0.0.1:6000 full -~~~ - -## Dnstap command line tool - -~~~ sh -go get github.com/dnstap/golang-dnstap -cd $GOPATH/src/github.com/dnstap/golang-dnstap/dnstap -go build -./dnstap -~~~ - -The following command listens on the given socket and decodes messages to stdout. - -~~~ sh -dnstap -u /tmp/dnstap.sock -~~~ - -The following command listens on the given socket and saves message payloads to a binary dnstap-format log file. - -~~~ sh -dnstap -u /tmp/dnstap.sock -w /tmp/test.dnstap -~~~ - -Listen for dnstap messages on port 6000. - -~~~ sh -dnstap -l 127.0.0.1:6000 -~~~ diff --git a/middleware/dnstap/handler.go b/middleware/dnstap/handler.go deleted file mode 100644 index eb2924be5..000000000 --- a/middleware/dnstap/handler.go +++ /dev/null @@ -1,79 +0,0 @@ -package dnstap - -import ( - "fmt" - "io" - - "github.com/coredns/coredns/middleware" - "github.com/coredns/coredns/middleware/dnstap/msg" - "github.com/coredns/coredns/middleware/dnstap/taprw" - - tap "github.com/dnstap/golang-dnstap" - "github.com/miekg/dns" - "golang.org/x/net/context" -) - -// Dnstap is the dnstap handler. -type Dnstap struct { - Next middleware.Handler - Out io.Writer - Pack bool -} - -type ( - // Tapper is implemented by the Context passed by the dnstap handler. - Tapper interface { - TapMessage(*tap.Message) error - TapBuilder() msg.Builder - } - tapContext struct { - context.Context - Dnstap - } -) - -// TapperFromContext will return a Tapper if the dnstap middleware is enabled. -func TapperFromContext(ctx context.Context) (t Tapper) { - t, _ = ctx.(Tapper) - return -} - -func tapMessageTo(w io.Writer, m *tap.Message) error { - frame, err := msg.Marshal(m) - if err != nil { - return fmt.Errorf("marshal: %s", err) - } - _, err = w.Write(frame) - return err -} - -// TapMessage implements Tapper. -func (h Dnstap) TapMessage(m *tap.Message) error { - return tapMessageTo(h.Out, m) -} - -// TapBuilder implements Tapper. -func (h Dnstap) TapBuilder() msg.Builder { - return msg.Builder{Full: h.Pack} -} - -// ServeDNS logs the client query and response to dnstap and passes the dnstap Context. -func (h Dnstap) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { - rw := &taprw.ResponseWriter{ResponseWriter: w, Tapper: &h, Query: r} - rw.QueryEpoch() - - code, err := middleware.NextOrFailure(h.Name(), h.Next, tapContext{ctx, h}, rw, r) - if err != nil { - // ignore dnstap errors - return code, err - } - - if err := rw.DnstapError(); err != nil { - return code, middleware.Error("dnstap", err) - } - - return code, nil -} - -// Name returns dnstap. -func (h Dnstap) Name() string { return "dnstap" } diff --git a/middleware/dnstap/handler_test.go b/middleware/dnstap/handler_test.go deleted file mode 100644 index dfdde582d..000000000 --- a/middleware/dnstap/handler_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package dnstap - -import ( - "errors" - "fmt" - "testing" - - "github.com/coredns/coredns/middleware/dnstap/test" - mwtest "github.com/coredns/coredns/middleware/test" - - tap "github.com/dnstap/golang-dnstap" - "github.com/golang/protobuf/proto" - "github.com/miekg/dns" - "golang.org/x/net/context" -) - -func testCase(t *testing.T, tapq, tapr *tap.Message, q, r *dns.Msg) { - w := writer{} - w.queue = append(w.queue, tapq, tapr) - h := Dnstap{ - Next: mwtest.HandlerFunc(func(_ context.Context, - w dns.ResponseWriter, _ *dns.Msg) (int, error) { - - return 0, w.WriteMsg(r) - }), - Out: &w, - Pack: false, - } - _, err := h.ServeDNS(context.TODO(), &mwtest.ResponseWriter{}, q) - if err != nil { - t.Fatal(err) - } -} - -type writer struct { - queue []*tap.Message -} - -func (w *writer) Write(b []byte) (int, error) { - e := tap.Dnstap{} - if err := proto.Unmarshal(b, &e); err != nil { - return 0, err - } - if len(w.queue) == 0 { - return 0, errors.New("message not expected") - } - if !test.MsgEqual(w.queue[0], e.Message) { - return 0, fmt.Errorf("want: %v, have: %v", w.queue[0], e.Message) - } - w.queue = w.queue[1:] - return len(b), nil -} - -func TestDnstap(t *testing.T) { - q := mwtest.Case{Qname: "example.org", Qtype: dns.TypeA}.Msg() - r := mwtest.Case{ - Qname: "example.org.", Qtype: dns.TypeA, - Answer: []dns.RR{ - mwtest.A("example.org. 3600 IN A 10.0.0.1"), - }, - }.Msg() - tapq := test.TestingData().ToClientQuery() - tapr := test.TestingData().ToClientResponse() - testCase(t, tapq, tapr, q, r) -} diff --git a/middleware/dnstap/msg/msg.go b/middleware/dnstap/msg/msg.go deleted file mode 100644 index 0e2cd5d40..000000000 --- a/middleware/dnstap/msg/msg.go +++ /dev/null @@ -1,168 +0,0 @@ -// Package msg helps to build a dnstap Message. -package msg - -import ( - "errors" - "net" - "strconv" - "time" - - tap "github.com/dnstap/golang-dnstap" - "github.com/miekg/dns" -) - -// Builder helps to build Data by being aware of the dnstap middleware configuration. -type Builder struct { - Full bool - Data -} - -// AddrMsg parses the info of net.Addr and dns.Msg. -func (b *Builder) AddrMsg(a net.Addr, m *dns.Msg) (err error) { - err = b.RemoteAddr(a) - if err != nil { - return - } - return b.Msg(m) -} - -// Msg parses the info of dns.Msg. -func (b *Builder) Msg(m *dns.Msg) (err error) { - if b.Full { - err = b.Pack(m) - } - return -} - -// Data helps to build a dnstap Message. -// It can be transformed into the actual Message using this package. -type Data struct { - Packed []byte - SocketProto tap.SocketProtocol - SocketFam tap.SocketFamily - Address []byte - Port uint32 - TimeSec uint64 -} - -// HostPort decodes into Data any string returned by dnsutil.ParseHostPortOrFile. -func (d *Data) HostPort(addr string) error { - ip, port, err := net.SplitHostPort(addr) - if err != nil { - return err - } - p, err := strconv.ParseUint(port, 10, 32) - if err != nil { - return err - } - d.Port = uint32(p) - - if ip := net.ParseIP(ip); ip != nil { - d.Address = []byte(ip) - if ip := ip.To4(); ip != nil { - d.SocketFam = tap.SocketFamily_INET - } else { - d.SocketFam = tap.SocketFamily_INET6 - } - return nil - } - return errors.New("not an ip address") -} - -// RemoteAddr parses the information about the remote address into Data. -func (d *Data) RemoteAddr(remote net.Addr) error { - switch addr := remote.(type) { - case *net.TCPAddr: - d.Address = addr.IP - d.Port = uint32(addr.Port) - d.SocketProto = tap.SocketProtocol_TCP - case *net.UDPAddr: - d.Address = addr.IP - d.Port = uint32(addr.Port) - d.SocketProto = tap.SocketProtocol_UDP - default: - return errors.New("unknown remote address type") - } - - if a := net.IP(d.Address); a.To4() != nil { - d.SocketFam = tap.SocketFamily_INET - } else { - d.SocketFam = tap.SocketFamily_INET6 - } - - return nil -} - -// Pack encodes the DNS message into Data. -func (d *Data) Pack(m *dns.Msg) error { - packed, err := m.Pack() - if err != nil { - return err - } - d.Packed = packed - return nil -} - -// Epoch returns the epoch time in seconds. -func Epoch() uint64 { - return uint64(time.Now().Unix()) -} - -// Epoch sets the dnstap message epoch. -func (d *Data) Epoch() { - d.TimeSec = Epoch() -} - -// ToClientResponse transforms Data into a client response message. -func (d *Data) ToClientResponse() *tap.Message { - t := tap.Message_CLIENT_RESPONSE - return &tap.Message{ - Type: &t, - SocketFamily: &d.SocketFam, - SocketProtocol: &d.SocketProto, - ResponseTimeSec: &d.TimeSec, - ResponseMessage: d.Packed, - QueryAddress: d.Address, - QueryPort: &d.Port, - } -} - -// ToClientQuery transforms Data into a client query message. -func (d *Data) ToClientQuery() *tap.Message { - t := tap.Message_CLIENT_QUERY - return &tap.Message{ - Type: &t, - SocketFamily: &d.SocketFam, - SocketProtocol: &d.SocketProto, - QueryTimeSec: &d.TimeSec, - QueryMessage: d.Packed, - QueryAddress: d.Address, - QueryPort: &d.Port, - } -} - -// ToOutsideQuery transforms the data into a forwarder or resolver query message. -func (d *Data) ToOutsideQuery(t tap.Message_Type) *tap.Message { - return &tap.Message{ - Type: &t, - SocketFamily: &d.SocketFam, - SocketProtocol: &d.SocketProto, - QueryTimeSec: &d.TimeSec, - QueryMessage: d.Packed, - ResponseAddress: d.Address, - ResponsePort: &d.Port, - } -} - -// ToOutsideResponse transforms the data into a forwarder or resolver response message. -func (d *Data) ToOutsideResponse(t tap.Message_Type) *tap.Message { - return &tap.Message{ - Type: &t, - SocketFamily: &d.SocketFam, - SocketProtocol: &d.SocketProto, - ResponseTimeSec: &d.TimeSec, - ResponseMessage: d.Packed, - ResponseAddress: d.Address, - ResponsePort: &d.Port, - } -} diff --git a/middleware/dnstap/msg/msg_test.go b/middleware/dnstap/msg/msg_test.go deleted file mode 100644 index 2f80a90cd..000000000 --- a/middleware/dnstap/msg/msg_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package msg - -import ( - "net" - "reflect" - "testing" - - "github.com/coredns/coredns/middleware/test" - "github.com/coredns/coredns/request" - - tap "github.com/dnstap/golang-dnstap" - "github.com/miekg/dns" -) - -func testRequest(t *testing.T, expected Data, r request.Request) { - d := Data{} - if err := d.RemoteAddr(r.W.RemoteAddr()); err != nil { - t.Fail() - return - } - if d.SocketProto != expected.SocketProto || - d.SocketFam != expected.SocketFam || - !reflect.DeepEqual(d.Address, expected.Address) || - d.Port != expected.Port { - t.Fatalf("expected: %v, have: %v", expected, d) - return - } -} -func TestRequest(t *testing.T) { - testRequest(t, Data{ - SocketProto: tap.SocketProtocol_UDP, - SocketFam: tap.SocketFamily_INET, - Address: net.ParseIP("10.240.0.1"), - Port: 40212, - }, testingRequest()) -} -func testingRequest() request.Request { - m := new(dns.Msg) - m.SetQuestion("example.com.", dns.TypeA) - m.SetEdns0(4097, true) - return request.Request{W: &test.ResponseWriter{}, Req: m} -} diff --git a/middleware/dnstap/msg/wrapper.go b/middleware/dnstap/msg/wrapper.go deleted file mode 100644 index a74c604d8..000000000 --- a/middleware/dnstap/msg/wrapper.go +++ /dev/null @@ -1,26 +0,0 @@ -package msg - -import ( - "fmt" - - lib "github.com/dnstap/golang-dnstap" - "github.com/golang/protobuf/proto" -) - -func wrap(m *lib.Message) *lib.Dnstap { - t := lib.Dnstap_MESSAGE - return &lib.Dnstap{ - Type: &t, - Message: m, - } -} - -// Marshal encodes the message to a binary dnstap payload. -func Marshal(m *lib.Message) (data []byte, err error) { - data, err = proto.Marshal(wrap(m)) - if err != nil { - err = fmt.Errorf("proto: %s", err) - return - } - return -} diff --git a/middleware/dnstap/out/socket.go b/middleware/dnstap/out/socket.go deleted file mode 100644 index 520dcf1d8..000000000 --- a/middleware/dnstap/out/socket.go +++ /dev/null @@ -1,86 +0,0 @@ -package out - -import ( - "fmt" - "net" - - fs "github.com/farsightsec/golang-framestream" -) - -// Socket is a Frame Streams encoder over a UNIX socket. -type Socket struct { - path string - enc *fs.Encoder - conn net.Conn - err error -} - -func openSocket(s *Socket) error { - conn, err := net.Dial("unix", s.path) - if err != nil { - return err - } - s.conn = conn - - enc, err := fs.NewEncoder(conn, &fs.EncoderOptions{ - ContentType: []byte("protobuf:dnstap.Dnstap"), - Bidirectional: true, - }) - if err != nil { - return err - } - s.enc = enc - - s.err = nil - return nil -} - -// NewSocket will always return a new Socket. -// err if nothing is listening to it, it will attempt to reconnect on the next Write. -func NewSocket(path string) (s *Socket, err error) { - s = &Socket{path: path} - if err = openSocket(s); err != nil { - err = fmt.Errorf("open socket: %s", err) - s.err = err - return - } - return -} - -// Write a single Frame Streams frame. -func (s *Socket) Write(frame []byte) (int, error) { - if s.err != nil { - // is the dnstap tool listening? - if err := openSocket(s); err != nil { - return 0, fmt.Errorf("open socket: %s", err) - } - } - n, err := s.enc.Write(frame) - if err != nil { - // the dnstap command line tool is down - s.conn.Close() - s.err = err - return 0, err - } - return n, nil - -} - -// Close the socket and flush the remaining frames. -func (s *Socket) Close() error { - if s.err != nil { - // nothing to close - return nil - } - - defer s.conn.Close() - - if err := s.enc.Flush(); err != nil { - return fmt.Errorf("flush: %s", err) - } - if err := s.enc.Close(); err != nil { - return err - } - - return nil -} diff --git a/middleware/dnstap/out/socket_test.go b/middleware/dnstap/out/socket_test.go deleted file mode 100644 index 050a38d36..000000000 --- a/middleware/dnstap/out/socket_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package out - -import ( - "net" - "testing" - - fs "github.com/farsightsec/golang-framestream" -) - -func acceptOne(t *testing.T, l net.Listener) { - server, err := l.Accept() - if err != nil { - t.Fatalf("server accept: %s", err) - return - } - - dec, err := fs.NewDecoder(server, &fs.DecoderOptions{ - ContentType: []byte("protobuf:dnstap.Dnstap"), - Bidirectional: true, - }) - if err != nil { - t.Fatalf("server decoder: %s", err) - return - } - - if _, err := dec.Decode(); err != nil { - t.Errorf("server decode: %s", err) - } - - if err := server.Close(); err != nil { - t.Error(err) - } -} -func sendOne(socket *Socket) error { - if _, err := socket.Write([]byte("frame")); err != nil { - return err - } - if err := socket.enc.Flush(); err != nil { - // Would happen during Write in real life. - socket.conn.Close() - socket.err = err - return err - } - return nil -} -func TestSocket(t *testing.T) { - socket, err := NewSocket("dnstap.sock") - if err == nil { - t.Fatal("new socket: not listening but no error") - return - } - - if err := sendOne(socket); err == nil { - t.Fatal("not listening but no error") - return - } - - l, err := net.Listen("unix", "dnstap.sock") - if err != nil { - t.Fatal(err) - return - } - - wait := make(chan bool) - go func() { - acceptOne(t, l) - wait <- true - }() - - if err := sendOne(socket); err != nil { - t.Fatalf("send one: %s", err) - return - } - - <-wait - if err := sendOne(socket); err == nil { - panic("must fail") - } - - go func() { - acceptOne(t, l) - wait <- true - }() - - if err := sendOne(socket); err != nil { - t.Fatalf("send one: %s", err) - return - } - - <-wait - if err := l.Close(); err != nil { - t.Error(err) - } -} diff --git a/middleware/dnstap/out/tcp.go b/middleware/dnstap/out/tcp.go deleted file mode 100644 index 8d2c25270..000000000 --- a/middleware/dnstap/out/tcp.go +++ /dev/null @@ -1,59 +0,0 @@ -package out - -import ( - "net" - "time" - - fs "github.com/farsightsec/golang-framestream" -) - -// TCP is a Frame Streams encoder over TCP. -type TCP struct { - address string - frames [][]byte -} - -// NewTCP returns a TCP writer. -func NewTCP(address string) *TCP { - s := &TCP{address: address} - s.frames = make([][]byte, 0, 13) // 13 messages buffer - return s -} - -// Write a single Frame Streams frame. -func (s *TCP) Write(frame []byte) (n int, err error) { - s.frames = append(s.frames, frame) - if len(s.frames) == cap(s.frames) { - return len(frame), s.Flush() - } - return len(frame), nil -} - -// Flush the remaining frames. -func (s *TCP) Flush() error { - defer func() { - s.frames = s.frames[0:] - }() - c, err := net.DialTimeout("tcp", s.address, time.Second) - if err != nil { - return err - } - enc, err := fs.NewEncoder(c, &fs.EncoderOptions{ - ContentType: []byte("protobuf:dnstap.Dnstap"), - Bidirectional: true, - }) - if err != nil { - return err - } - for _, frame := range s.frames { - if _, err = enc.Write(frame); err != nil { - return err - } - } - return enc.Flush() -} - -// Close is an alias to Flush to satisfy io.WriteCloser similarly to type Socket. -func (s *TCP) Close() error { - return s.Flush() -} diff --git a/middleware/dnstap/out/tcp_test.go b/middleware/dnstap/out/tcp_test.go deleted file mode 100644 index 113603cd4..000000000 --- a/middleware/dnstap/out/tcp_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package out - -import ( - "net" - "testing" -) - -func sendOneTCP(tcp *TCP) error { - if _, err := tcp.Write([]byte("frame")); err != nil { - return err - } - if err := tcp.Flush(); err != nil { - return err - } - return nil -} -func TestTCP(t *testing.T) { - tcp := NewTCP("localhost:14000") - - if err := sendOneTCP(tcp); err == nil { - t.Fatal("Not listening but no error.") - return - } - - l, err := net.Listen("tcp", "localhost:14000") - if err != nil { - t.Fatal(err) - return - } - - wait := make(chan bool) - go func() { - acceptOne(t, l) - wait <- true - }() - - if err := sendOneTCP(tcp); err != nil { - t.Fatalf("send one: %s", err) - return - } - - <-wait - - // TODO: When the server isn't responding according to the framestream protocol - // the thread is blocked. - /* - if err := sendOneTCP(tcp); err == nil { - panic("must fail") - } - */ - - go func() { - acceptOne(t, l) - wait <- true - }() - - if err := sendOneTCP(tcp); err != nil { - t.Fatalf("send one: %s", err) - return - } - - <-wait - if err := l.Close(); err != nil { - t.Error(err) - } -} diff --git a/middleware/dnstap/setup.go b/middleware/dnstap/setup.go deleted file mode 100644 index 63a3eb099..000000000 --- a/middleware/dnstap/setup.go +++ /dev/null @@ -1,98 +0,0 @@ -package dnstap - -import ( - "fmt" - "io" - "log" - "strings" - - "github.com/coredns/coredns/core/dnsserver" - "github.com/coredns/coredns/middleware" - "github.com/coredns/coredns/middleware/dnstap/out" - "github.com/coredns/coredns/middleware/pkg/dnsutil" - - "github.com/mholt/caddy" - "github.com/mholt/caddy/caddyfile" -) - -func init() { - caddy.RegisterPlugin("dnstap", caddy.Plugin{ - ServerType: "dns", - Action: wrapSetup, - }) -} - -func wrapSetup(c *caddy.Controller) error { - if err := setup(c); err != nil { - return middleware.Error("dnstap", err) - } - return nil -} - -type config struct { - target string - socket bool - full bool -} - -func parseConfig(d *caddyfile.Dispenser) (c config, err error) { - d.Next() // directive name - - if !d.Args(&c.target) { - return c, d.ArgErr() - } - - if strings.HasPrefix(c.target, "tcp://") { - // remote IP endpoint - servers, err := dnsutil.ParseHostPortOrFile(c.target[6:]) - if err != nil { - return c, d.ArgErr() - } - c.target = servers[0] - } else { - // default to UNIX socket - if strings.HasPrefix(c.target, "unix://") { - c.target = c.target[7:] - } - c.socket = true - } - - c.full = d.NextArg() && d.Val() == "full" - - return -} - -func setup(c *caddy.Controller) error { - conf, err := parseConfig(&c.Dispenser) - if err != nil { - return err - } - - dnstap := Dnstap{Pack: conf.full} - - var o io.WriteCloser - if conf.socket { - o, err = out.NewSocket(conf.target) - if err != nil { - log.Printf("[WARN] Can't connect to %s at the moment: %s", conf.target, err) - } - } else { - o = out.NewTCP(conf.target) - } - dnstap.Out = o - - c.OnShutdown(func() error { - if err := o.Close(); err != nil { - return fmt.Errorf("output: %s", err) - } - return nil - }) - - dnsserver.GetConfig(c).AddMiddleware( - func(next middleware.Handler) middleware.Handler { - dnstap.Next = next - return dnstap - }) - - return nil -} diff --git a/middleware/dnstap/setup_test.go b/middleware/dnstap/setup_test.go deleted file mode 100644 index fc1dc98e0..000000000 --- a/middleware/dnstap/setup_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package dnstap - -import ( - "github.com/mholt/caddy" - "testing" -) - -func TestConfig(t *testing.T) { - tests := []struct { - file string - path string - full bool - socket bool - fail bool - }{ - {"dnstap dnstap.sock full", "dnstap.sock", true, true, false}, - {"dnstap unix://dnstap.sock", "dnstap.sock", false, true, false}, - {"dnstap tcp://127.0.0.1:6000", "127.0.0.1:6000", false, false, false}, - {"dnstap", "fail", false, true, true}, - } - for _, c := range tests { - cad := caddy.NewTestController("dns", c.file) - conf, err := parseConfig(&cad.Dispenser) - if c.fail { - if err == nil { - t.Errorf("%s: %s", c.file, err) - } - } else if err != nil || conf.target != c.path || - conf.full != c.full || conf.socket != c.socket { - - t.Errorf("expected: %+v\nhave: %+v\nerror: %s\n", c, conf, err) - } - } -} diff --git a/middleware/dnstap/taprw/writer.go b/middleware/dnstap/taprw/writer.go deleted file mode 100644 index 99572afd9..000000000 --- a/middleware/dnstap/taprw/writer.go +++ /dev/null @@ -1,73 +0,0 @@ -// 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" -) - -// Tapper is what ResponseWriter needs to log to dnstap. -type Tapper interface { - TapMessage(m *tap.Message) error - TapBuilder() msg.Builder -} - -// ResponseWriter captures the client response and logs the query to dnstap. -// Single request use. -type ResponseWriter struct { - queryEpoch uint64 - Query *dns.Msg - dns.ResponseWriter - Tapper - err error -} - -// DnstapError check if a dnstap error occurred during Write and returns it. -func (w ResponseWriter) DnstapError() error { - return w.err -} - -// QueryEpoch sets the query epoch as reported by dnstap. -func (w *ResponseWriter) QueryEpoch() { - w.queryEpoch = msg.Epoch() -} - -// WriteMsg writes back the response to the client and THEN works on logging the request -// and response to dnstap. -// 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() - - 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 { - w.err = fmt.Errorf("client query: %s", err) - // don't forget to call DnstapError later - } - - if writeErr == nil { - if err := func() (err error) { - b.TimeSec = writeEpoch - if err = b.Msg(resp); err != nil { - return - } - return w.TapMessage(b.ToClientResponse()) - }(); err != nil { - w.err = fmt.Errorf("client response: %s", err) - } - } - - return -} diff --git a/middleware/dnstap/taprw/writer_test.go b/middleware/dnstap/taprw/writer_test.go deleted file mode 100644 index 426f1f580..000000000 --- a/middleware/dnstap/taprw/writer_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package taprw - -import ( - "errors" - "testing" - - "github.com/coredns/coredns/middleware/dnstap/msg" - "github.com/coredns/coredns/middleware/dnstap/test" - mwtest "github.com/coredns/coredns/middleware/test" - - tap "github.com/dnstap/golang-dnstap" - "github.com/miekg/dns" -) - -type TapFailer struct { -} - -func (TapFailer) TapMessage(*tap.Message) error { - return errors.New("failed") -} -func (TapFailer) TapBuilder() msg.Builder { - return msg.Builder{Full: true} -} - -func TestDnstapError(t *testing.T) { - rw := ResponseWriter{ - Query: new(dns.Msg), - ResponseWriter: &mwtest.ResponseWriter{}, - Tapper: TapFailer{}, - } - if err := rw.WriteMsg(new(dns.Msg)); err != nil { - t.Errorf("dnstap error during Write: %s", err) - } - if rw.DnstapError() == nil { - t.Fatal("no dnstap error") - } -} - -func testingMsg() (m *dns.Msg) { - m = new(dns.Msg) - m.SetQuestion("example.com.", dns.TypeA) - m.SetEdns0(4097, true) - return -} - -func TestClientQueryResponse(t *testing.T) { - trapper := test.TrapTapper{Full: true} - m := testingMsg() - rw := ResponseWriter{ - Query: m, - Tapper: &trapper, - ResponseWriter: &mwtest.ResponseWriter{}, - } - d := test.TestingData() - - // will the wire-format msg be reported? - bin, err := m.Pack() - if err != nil { - t.Fatal(err) - return - } - d.Packed = bin - - if err := rw.WriteMsg(m); err != nil { - t.Fatal(err) - return - } - if l := len(trapper.Trap); l != 2 { - t.Fatalf("%d msg trapped", l) - return - } - want := d.ToClientQuery() - have := trapper.Trap[0] - if !test.MsgEqual(want, have) { - t.Fatalf("query: want: %v\nhave: %v", want, have) - } - want = d.ToClientResponse() - have = trapper.Trap[1] - if !test.MsgEqual(want, have) { - t.Fatalf("response: want: %v\nhave: %v", want, have) - } -} diff --git a/middleware/dnstap/test/helpers.go b/middleware/dnstap/test/helpers.go deleted file mode 100644 index 46ba327ab..000000000 --- a/middleware/dnstap/test/helpers.go +++ /dev/null @@ -1,80 +0,0 @@ -package test - -import ( - "net" - "reflect" - - "github.com/coredns/coredns/middleware/dnstap/msg" - - tap "github.com/dnstap/golang-dnstap" - "golang.org/x/net/context" -) - -// Context is a message trap. -type Context struct { - context.Context - TrapTapper -} - -// TestingData returns the Data matching coredns/test.ResponseWriter. -func TestingData() (d *msg.Data) { - d = &msg.Data{ - SocketFam: tap.SocketFamily_INET, - SocketProto: tap.SocketProtocol_UDP, - Address: net.ParseIP("10.240.0.1"), - Port: 40212, - } - return -} - -type comp struct { - Type *tap.Message_Type - SF *tap.SocketFamily - SP *tap.SocketProtocol - QA []byte - RA []byte - QP *uint32 - RP *uint32 - QTSec bool - RTSec bool - RM []byte - QM []byte -} - -func toComp(m *tap.Message) comp { - return comp{ - Type: m.Type, - SF: m.SocketFamily, - SP: m.SocketProtocol, - QA: m.QueryAddress, - RA: m.ResponseAddress, - QP: m.QueryPort, - RP: m.ResponsePort, - QTSec: m.QueryTimeSec != nil, - RTSec: m.ResponseTimeSec != nil, - RM: m.ResponseMessage, - QM: m.QueryMessage, - } -} - -// MsgEqual compares two dnstap messages ignoring timestamps. -func MsgEqual(a, b *tap.Message) bool { - return reflect.DeepEqual(toComp(a), toComp(b)) -} - -// TrapTapper traps messages. -type TrapTapper struct { - Trap []*tap.Message - Full bool -} - -// TapMessage adds the message to the trap. -func (t *TrapTapper) TapMessage(m *tap.Message) error { - t.Trap = append(t.Trap, m) - return nil -} - -// TapBuilder returns a test msg.Builder. -func (t *TrapTapper) TapBuilder() msg.Builder { - return msg.Builder{Full: t.Full} -} |