coredns/plugin/dnstap/msg/msg.go
2018-03-02 04:50:31 -08:00

159 lines
3.7 KiB
Go

package msg
import (
"errors"
"net"
"strconv"
"time"
tap "github.com/dnstap/golang-dnstap"
"github.com/miekg/dns"
)
// Builder helps to build a Dnstap message.
type Builder struct {
Packed []byte
SocketProto tap.SocketProtocol
SocketFam tap.SocketFamily
Address net.IP
Port uint32
TimeSec uint64
TimeNsec uint32
err 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 {
b.err = err
return b
}
p, err := strconv.ParseUint(port, 10, 32)
if err != nil {
b.err = err
return b
}
b.Port = uint32(p)
if ip := net.ParseIP(ip); ip != nil {
b.Address = []byte(ip)
if ip := ip.To4(); ip != nil {
b.SocketFam = tap.SocketFamily_INET
} else {
b.SocketFam = tap.SocketFamily_INET6
}
return b
}
b.err = errors.New("not an ip address")
return b
}
// Time adds the timestamp to the message.
func (b *Builder) Time(ts time.Time) *Builder {
b.TimeSec = uint64(ts.Unix())
b.TimeNsec = uint32(ts.Nanosecond())
return b
}
// ToClientResponse transforms Data into a client response message.
func (b *Builder) ToClientResponse() (*tap.Message, error) {
t := tap.Message_CLIENT_RESPONSE
return &tap.Message{
Type: &t,
SocketFamily: &b.SocketFam,
SocketProtocol: &b.SocketProto,
ResponseTimeSec: &b.TimeSec,
ResponseTimeNsec: &b.TimeNsec,
ResponseMessage: b.Packed,
QueryAddress: b.Address,
QueryPort: &b.Port,
}, b.err
}
// ToClientQuery transforms Data into a client query message.
func (b *Builder) ToClientQuery() (*tap.Message, error) {
t := tap.Message_CLIENT_QUERY
return &tap.Message{
Type: &t,
SocketFamily: &b.SocketFam,
SocketProtocol: &b.SocketProto,
QueryTimeSec: &b.TimeSec,
QueryTimeNsec: &b.TimeNsec,
QueryMessage: b.Packed,
QueryAddress: b.Address,
QueryPort: &b.Port,
}, b.err
}
// ToOutsideQuery transforms the data into a forwarder or resolver query message.
func (b *Builder) ToOutsideQuery(t tap.Message_Type) (*tap.Message, error) {
return &tap.Message{
Type: &t,
SocketFamily: &b.SocketFam,
SocketProtocol: &b.SocketProto,
QueryTimeSec: &b.TimeSec,
QueryTimeNsec: &b.TimeNsec,
QueryMessage: b.Packed,
ResponseAddress: b.Address,
ResponsePort: &b.Port,
}, b.err
}
// ToOutsideResponse transforms the data into a forwarder or resolver response message.
func (b *Builder) ToOutsideResponse(t tap.Message_Type) (*tap.Message, error) {
return &tap.Message{
Type: &t,
SocketFamily: &b.SocketFam,
SocketProtocol: &b.SocketProto,
ResponseTimeSec: &b.TimeSec,
ResponseTimeNsec: &b.TimeNsec,
ResponseMessage: b.Packed,
ResponseAddress: b.Address,
ResponsePort: &b.Port,
}, b.err
}