Easier way to dnstap? (#1496)

* Easier way to dnstap?

* Remove unnecessary function parameter from Tapper

* golint

* golint 2

* Proxy dnstap tests

* README.md & doc

* net.IP

* Proxy test was incorrect

* Small changes

* Update README.md

* Was not reporting dnstap errors + test

* Wasn't working at all, now it's ok

* Thanks Travis
This commit is contained in:
varyoo 2018-03-01 03:19:01 +01:00 committed by Miek Gieben
parent f697b33283
commit 6bb08ffee4
12 changed files with 274 additions and 255 deletions

View file

@ -1,157 +1,153 @@
// 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 plugin configuration.
// Builder helps to build a Dnstap message.
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
Address net.IP
Port uint32
TimeSec uint64
err error
}
// HostPort decodes into Data any string returned by dnsutil.ParseHostPortOrFile.
func (d *Data) HostPort(addr string) error {
// New returns a new Builder
func New() *Builder {
return &Builder{}
}
// Addr adds the remote address to the message.
func (b *Builder) Addr(remote net.Addr) *Builder {
if b.err != nil {
return b
}
switch addr := remote.(type) {
case *net.TCPAddr:
b.Address = addr.IP
b.Port = uint32(addr.Port)
b.SocketProto = tap.SocketProtocol_TCP
case *net.UDPAddr:
b.Address = addr.IP
b.Port = uint32(addr.Port)
b.SocketProto = tap.SocketProtocol_UDP
default:
b.err = errors.New("unknown remote address type")
return b
}
if b.Address.To4() != nil {
b.SocketFam = tap.SocketFamily_INET
} else {
b.SocketFam = tap.SocketFamily_INET6
}
return b
}
// Msg adds the raw DNS message to the dnstap message.
func (b *Builder) Msg(m *dns.Msg) *Builder {
if b.err != nil {
return b
}
b.Packed, b.err = m.Pack()
return b
}
// HostPort adds the remote address as encoded by dnsutil.ParseHostPortOrFile to the message.
func (b *Builder) HostPort(addr string) *Builder {
ip, port, err := net.SplitHostPort(addr)
if err != nil {
return err
b.err = err
return b
}
p, err := strconv.ParseUint(port, 10, 32)
if err != nil {
return err
b.err = err
return b
}
d.Port = uint32(p)
b.Port = uint32(p)
if ip := net.ParseIP(ip); ip != nil {
d.Address = []byte(ip)
b.Address = []byte(ip)
if ip := ip.To4(); ip != nil {
d.SocketFam = tap.SocketFamily_INET
b.SocketFam = tap.SocketFamily_INET
} else {
d.SocketFam = tap.SocketFamily_INET6
b.SocketFam = tap.SocketFamily_INET6
}
return nil
return b
}
return errors.New("not an ip address")
b.err = errors.New("not an ip address")
return b
}
// 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
// Time adds the timestamp to the message.
func (b *Builder) Time(ts time.Time) *Builder {
b.TimeSec = uint64(ts.Unix())
return b
}
// ToClientResponse transforms Data into a client response message.
func (d *Data) ToClientResponse() *tap.Message {
func (b *Builder) ToClientResponse() (*tap.Message, error) {
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,
}
SocketFamily: &b.SocketFam,
SocketProtocol: &b.SocketProto,
ResponseTimeSec: &b.TimeSec,
ResponseMessage: b.Packed,
QueryAddress: b.Address,
QueryPort: &b.Port,
}, b.err
}
// ToClientQuery transforms Data into a client query message.
func (d *Data) ToClientQuery() *tap.Message {
func (b *Builder) ToClientQuery() (*tap.Message, error) {
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,
}
SocketFamily: &b.SocketFam,
SocketProtocol: &b.SocketProto,
QueryTimeSec: &b.TimeSec,
QueryMessage: b.Packed,
QueryAddress: b.Address,
QueryPort: &b.Port,
}, b.err
}
// ToOutsideQuery transforms the data into a forwarder or resolver query message.
func (d *Data) ToOutsideQuery(t tap.Message_Type) *tap.Message {
func (b *Builder) ToOutsideQuery(t tap.Message_Type) (*tap.Message, error) {
return &tap.Message{
Type: &t,
SocketFamily: &d.SocketFam,
SocketProtocol: &d.SocketProto,
QueryTimeSec: &d.TimeSec,
QueryMessage: d.Packed,
ResponseAddress: d.Address,
ResponsePort: &d.Port,
}
SocketFamily: &b.SocketFam,
SocketProtocol: &b.SocketProto,
QueryTimeSec: &b.TimeSec,
QueryMessage: b.Packed,
ResponseAddress: b.Address,
ResponsePort: &b.Port,
}, b.err
}
// ToOutsideResponse transforms the data into a forwarder or resolver response message.
func (d *Data) ToOutsideResponse(t tap.Message_Type) *tap.Message {
func (b *Builder) ToOutsideResponse(t tap.Message_Type) (*tap.Message, error) {
return &tap.Message{
Type: &t,
SocketFamily: &d.SocketFam,
SocketProtocol: &d.SocketProto,
ResponseTimeSec: &d.TimeSec,
ResponseMessage: d.Packed,
ResponseAddress: d.Address,
ResponsePort: &d.Port,
}
SocketFamily: &b.SocketFam,
SocketProtocol: &b.SocketProto,
ResponseTimeSec: &b.TimeSec,
ResponseMessage: b.Packed,
ResponseAddress: b.Address,
ResponsePort: &b.Port,
}, b.err
}