diff options
Diffstat (limited to 'plugin/dnstap/msg/msg.go')
-rw-r--r-- | plugin/dnstap/msg/msg.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/plugin/dnstap/msg/msg.go b/plugin/dnstap/msg/msg.go new file mode 100644 index 000000000..07930929e --- /dev/null +++ b/plugin/dnstap/msg/msg.go @@ -0,0 +1,168 @@ +// 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. +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, + } +} |