WIP: middleware/dnstap (#711)

middleware/dnstap add
This commit is contained in:
varyoo
2017-07-24 23:12:50 +02:00
committed by Miek Gieben
parent f33b02689c
commit 1b7492be6e
41 changed files with 3537 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
// Package msg helps to build a dnstap Message.
package msg
import (
"errors"
"net"
"time"
"github.com/coredns/coredns/request"
tap "github.com/dnstap/golang-dnstap"
"github.com/miekg/dns"
)
// Data helps to build a dnstap Message.
// It can be transformed into the actual Message using this package.
type Data struct {
Type tap.Message_Type
Packed []byte
SocketProto tap.SocketProtocol
SocketFam tap.SocketFamily
Address []byte
Port uint32
TimeSec uint64
}
func (d *Data) FromRequest(r request.Request) error {
switch addr := r.W.RemoteAddr().(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
}
func (d *Data) Pack(m *dns.Msg) error {
packed, err := m.Pack()
if err != nil {
return err
}
d.Packed = packed
return nil
}
func (d *Data) Epoch() {
d.TimeSec = uint64(time.Now().Unix())
}
// Transform the data into a client response message.
func (d *Data) ToClientResponse() *tap.Message {
d.Type = tap.Message_CLIENT_RESPONSE
return &tap.Message{
Type: &d.Type,
SocketFamily: &d.SocketFam,
SocketProtocol: &d.SocketProto,
ResponseTimeSec: &d.TimeSec,
ResponseMessage: d.Packed,
QueryAddress: d.Address,
QueryPort: &d.Port,
}
}
// Transform the data into a client query message.
func (d *Data) ToClientQuery() *tap.Message {
d.Type = tap.Message_CLIENT_QUERY
return &tap.Message{
Type: &d.Type,
SocketFamily: &d.SocketFam,
SocketProtocol: &d.SocketProto,
QueryTimeSec: &d.TimeSec,
QueryMessage: d.Packed,
QueryAddress: d.Address,
QueryPort: &d.Port,
}
}

View File

@@ -0,0 +1,42 @@
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.FromRequest(r); 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}
}

View File

@@ -0,0 +1,25 @@
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,
}
}
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
}