This is a rewrite of almost everything. The provided modules no longer rely on undocumented/deprecated behavior. It's no longer possible to have multiple DNS "servers" on different sockets, but the new version allows serving arbitrary records. Records can be defined in the config or Caddyfile. The provider communicates with the Server via a channel.
250 lines
5.9 KiB
Go
250 lines
5.9 KiB
Go
package stub
|
|
|
|
import (
|
|
"github.com/libdns/libdns"
|
|
"github.com/miekg/dns"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
// Wrapper for logging (relevant parts of) dns.Msg
|
|
type LoggableDNSMsg struct{ *dns.Msg }
|
|
|
|
// MarshalLogObject satisfies the zapcore.ObjectMarshaler interface.
|
|
func (m LoggableDNSMsg) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
|
// adapted version of MsgHdr.String() from github.com/miekg/dns
|
|
enc.AddUint16("id", m.Id)
|
|
enc.AddString("opcode", dns.OpcodeToString[m.Opcode])
|
|
enc.AddString("status", dns.RcodeToString[m.Rcode])
|
|
|
|
flag_array := func(arr zapcore.ArrayEncoder) error {
|
|
if m.Response {
|
|
arr.AppendString("qr")
|
|
}
|
|
if m.Authoritative {
|
|
arr.AppendString("aa")
|
|
}
|
|
if m.Truncated {
|
|
arr.AppendString("tc")
|
|
}
|
|
if m.RecursionDesired {
|
|
arr.AppendString("rd")
|
|
}
|
|
if m.RecursionAvailable {
|
|
arr.AppendString("ra")
|
|
}
|
|
if m.Zero {
|
|
arr.AppendString("z")
|
|
}
|
|
if m.AuthenticatedData {
|
|
arr.AppendString("ad")
|
|
}
|
|
if m.CheckingDisabled {
|
|
arr.AppendString("cd")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
enc.AddArray("flags", zapcore.ArrayMarshalerFunc(flag_array))
|
|
|
|
log_questions(enc, &m.Question)
|
|
log_answers(enc, &m.Answer)
|
|
// not logged:
|
|
// - EDNS0 "OPT pseudosection" from m.IsEdns0()
|
|
// - "authority section" in m.Ns
|
|
// - "additional section" in m.Extra
|
|
|
|
return nil
|
|
}
|
|
|
|
func log_answers(enc zapcore.ObjectEncoder, answers *[]dns.RR) {
|
|
if len(*answers) > 0 {
|
|
array := func(arr zapcore.ArrayEncoder) error {
|
|
for _, r := range *answers {
|
|
object := func(obj zapcore.ObjectEncoder) error {
|
|
log_RR(obj, r)
|
|
return nil
|
|
}
|
|
arr.AppendObject(zapcore.ObjectMarshalerFunc(object))
|
|
}
|
|
return nil
|
|
}
|
|
enc.AddArray("answer", zapcore.ArrayMarshalerFunc(array))
|
|
}
|
|
}
|
|
|
|
func log_questions(enc zapcore.ObjectEncoder, questions *[]dns.Question) {
|
|
if len(*questions) > 0 {
|
|
array := func(arr zapcore.ArrayEncoder) error {
|
|
for _, q := range *questions {
|
|
object := func(obj zapcore.ObjectEncoder) error {
|
|
obj.AddString("name", q.Name)
|
|
obj.AddString("class", dns.ClassToString[q.Qclass])
|
|
obj.AddString("type", dns.TypeToString[q.Qtype])
|
|
return nil
|
|
}
|
|
arr.AppendObject(zapcore.ObjectMarshalerFunc(object))
|
|
}
|
|
return nil
|
|
}
|
|
enc.AddArray("question", zapcore.ArrayMarshalerFunc(array))
|
|
}
|
|
}
|
|
|
|
// Only logs the "content"/values of the RR for common types
|
|
func log_RR(enc zapcore.ObjectEncoder, rr dns.RR) {
|
|
hdr := rr.Header()
|
|
enc.AddString("name", hdr.Name)
|
|
enc.AddString("class", dns.ClassToString[hdr.Class])
|
|
enc.AddString("type", dns.TypeToString[hdr.Rrtype])
|
|
enc.AddUint32("TTL", hdr.Ttl)
|
|
switch r := rr.(type) {
|
|
case *dns.A:
|
|
enc.AddString("A", r.A.String())
|
|
case *dns.AAAA:
|
|
enc.AddString("AAAA", r.AAAA.String())
|
|
case *dns.AFSDB:
|
|
// case *dns.AMTRELAY:
|
|
case *dns.ANY: // empty
|
|
case *dns.APL:
|
|
case *dns.AVC:
|
|
case *dns.CAA:
|
|
enc.AddUint8("flag", r.Flag)
|
|
enc.AddString("tag", r.Tag)
|
|
enc.AddString("value", r.Value)
|
|
case *dns.CDNSKEY:
|
|
case *dns.CDS:
|
|
case *dns.CERT:
|
|
case *dns.CNAME:
|
|
enc.AddString("target", r.Target)
|
|
case *dns.CSYNC:
|
|
case *dns.DHCID:
|
|
case *dns.DLV:
|
|
case *dns.DNAME:
|
|
enc.AddString("target", r.Target)
|
|
case *dns.DNSKEY:
|
|
case *dns.DS:
|
|
case *dns.EID:
|
|
case *dns.EUI48:
|
|
case *dns.EUI64:
|
|
case *dns.GID:
|
|
case *dns.GPOS:
|
|
case *dns.HINFO:
|
|
case *dns.HIP:
|
|
case *dns.HTTPS:
|
|
// case *dns.IPSECKEY:
|
|
case *dns.KEY:
|
|
case *dns.KX:
|
|
case *dns.L32:
|
|
case *dns.L64:
|
|
case *dns.LOC:
|
|
case *dns.LP:
|
|
case *dns.MB:
|
|
case *dns.MD:
|
|
case *dns.MF:
|
|
case *dns.MG:
|
|
case *dns.MINFO:
|
|
case *dns.MR:
|
|
case *dns.MX:
|
|
enc.AddString("MX", r.Mx)
|
|
enc.AddUint16("preference", r.Preference)
|
|
case *dns.NAPTR:
|
|
case *dns.NID:
|
|
case *dns.NIMLOC:
|
|
case *dns.NINFO:
|
|
case *dns.NS:
|
|
enc.AddString("NS", r.Ns)
|
|
case *dns.NSAPPTR:
|
|
case *dns.NSEC:
|
|
case *dns.NSEC3:
|
|
case *dns.NSEC3PARAM:
|
|
case *dns.NULL:
|
|
case *dns.OPENPGPKEY:
|
|
enc.AddString("public_key", r.PublicKey)
|
|
case *dns.OPT:
|
|
case *dns.PTR:
|
|
enc.AddString("PTR", r.Ptr)
|
|
case *dns.PX:
|
|
case *dns.RKEY:
|
|
case *dns.RP:
|
|
case *dns.RRSIG:
|
|
case *dns.RT:
|
|
case *dns.SIG:
|
|
case *dns.SMIMEA:
|
|
case *dns.SOA:
|
|
enc.AddString("NS", r.Ns)
|
|
enc.AddString("mbox", r.Mbox)
|
|
enc.AddUint32("serial", r.Serial)
|
|
enc.AddUint32("retry", r.Retry)
|
|
enc.AddUint32("refresh", r.Refresh)
|
|
enc.AddUint32("expire", r.Expire)
|
|
enc.AddUint32("minttl", r.Minttl)
|
|
case *dns.SPF:
|
|
zap.Strings("TXT", r.Txt).AddTo(enc)
|
|
case *dns.SRV:
|
|
enc.AddUint16("priority", r.Priority)
|
|
enc.AddUint16("weight", r.Weight)
|
|
enc.AddUint16("port", r.Port)
|
|
enc.AddString("target", r.Target)
|
|
case *dns.SSHFP:
|
|
enc.AddUint8("algorithm", r.Algorithm)
|
|
enc.AddUint8("type", r.Type)
|
|
enc.AddString("fingerprint", r.FingerPrint)
|
|
case *dns.SVCB:
|
|
case *dns.TA:
|
|
case *dns.TALINK:
|
|
case *dns.TKEY:
|
|
case *dns.TLSA:
|
|
case *dns.TSIG:
|
|
case *dns.TXT:
|
|
zap.Strings("TXT", r.Txt).AddTo(enc)
|
|
case *dns.UID:
|
|
case *dns.UINFO:
|
|
case *dns.URI:
|
|
case *dns.X25:
|
|
case *dns.ZONEMD:
|
|
default:
|
|
}
|
|
}
|
|
|
|
func log_libdns_record(record *libdns.Record) zapcore.ObjectMarshaler {
|
|
f := func(enc zapcore.ObjectEncoder) error {
|
|
enc.AddString("ID", record.ID)
|
|
enc.AddString("type", record.Type)
|
|
enc.AddString("name", record.Name)
|
|
enc.AddString("value", record.Value)
|
|
enc.AddString("TTL", record.TTL.String())
|
|
if record.Priority != 0 {
|
|
enc.AddInt("priority", record.Priority)
|
|
}
|
|
return nil
|
|
}
|
|
return zapcore.ObjectMarshalerFunc(f)
|
|
}
|
|
|
|
|
|
// MarshalLogObject satisfies the zapcore.ObjectMarshaler interface.
|
|
func (r request) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
|
enc.AddString("zone", r.zone)
|
|
if r.append {
|
|
enc.AddString("type", "append")
|
|
} else {
|
|
enc.AddString("type", "delete")
|
|
}
|
|
|
|
if len(r.records) > 0 {
|
|
array := func(arr zapcore.ArrayEncoder) error {
|
|
for _, r := range r.records {
|
|
object := func(obj zapcore.ObjectEncoder) error {
|
|
log_RR(obj, r)
|
|
return nil
|
|
}
|
|
arr.AppendObject(zapcore.ObjectMarshalerFunc(object))
|
|
}
|
|
return nil
|
|
}
|
|
enc.AddArray("records", zapcore.ArrayMarshalerFunc(array))
|
|
}
|
|
|
|
return nil
|
|
}
|