From 46d64b2ca846ce1332e9b9df53d4520c6d304884 Mon Sep 17 00:00:00 2001 From: xaos Date: Wed, 22 Mar 2023 15:45:14 +0100 Subject: [PATCH] feat: improve logging & move into separate file --- log.go | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ stub.go | 103 ---------------------------- 2 files changed, 208 insertions(+), 103 deletions(-) create mode 100644 log.go diff --git a/log.go b/log.go new file mode 100644 index 0000000..4c72135 --- /dev/null +++ b/log.go @@ -0,0 +1,208 @@ +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: + } +} diff --git a/stub.go b/stub.go index 56e01b8..566763c 100644 --- a/stub.go +++ b/stub.go @@ -10,8 +10,6 @@ import ( "github.com/mholt/acmez" "github.com/mholt/acmez/acme" "github.com/miekg/dns" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" ) // TTL of the challenge TXT record to serve @@ -25,9 +23,6 @@ type StubDNS struct { logger *zap.Logger // set in Provision() } -// Wrapper for logging (relevant parts of) dns.Msg -type LoggableDNSMsg struct{ *dns.Msg } - func init() { caddy.RegisterModule(StubDNS{}) } @@ -227,104 +222,6 @@ func (s *StubDNS) make_handler(fqdn string, txt string) dns.HandlerFunc { return handler } -// 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 { - // since we only serve TXT records - txt, ok := r.(*dns.TXT) - if ok { - object := func(obj zapcore.ObjectEncoder) error { - obj.AddString("name", txt.Hdr.Name) - obj.AddString("class", dns.ClassToString[txt.Hdr.Class]) - obj.AddString("type", dns.TypeToString[txt.Hdr.Rrtype]) - obj.AddUint32("TTL", txt.Hdr.Ttl) - rec := func(arr2 zapcore.ArrayEncoder) error { - for _, t := range txt.Txt { - arr2.AppendString(t) - } - return nil - } - obj.AddArray("content", zapcore.ArrayMarshalerFunc(rec)) - return nil - } - arr.AppendObject(zapcore.ObjectMarshalerFunc(object)) - } else { - // fallback for other record types, serialized dig-style - arr.AppendString(r.String()) - } - } - 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)) - } -} - // Interface guards var ( _ acmez.Solver = (*StubDNS)(nil)