From 720dbc5ccbaa65ceeefa2eec0f84d5e03313c64b Mon Sep 17 00:00:00 2001 From: grumbulon Date: Thu, 15 Dec 2022 16:54:36 -0500 Subject: [PATCH 01/13] attempt to make json print like kdig (ref RFC-8427) --- pkg/query/print.go | 302 +++++--------------------------------------- pkg/query/struct.go | 81 ++++++------ pkg/query/util.go | 282 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 352 insertions(+), 313 deletions(-) create mode 100644 pkg/query/util.go diff --git a/pkg/query/print.go b/pkg/query/print.go index 33734d6..1737525 100644 --- a/pkg/query/print.go +++ b/pkg/query/print.go @@ -3,7 +3,6 @@ package query import ( - "encoding/hex" "encoding/json" "encoding/xml" "errors" @@ -253,297 +252,60 @@ func MakePrintable(res util.Response, opts *util.Options) (*Message, error) { msg = res.DNS ) // The things I do for compatibility - ret := Message{ - Header: Header{ - ID: msg.Id, - Response: msg.Response, - Opcode: dns.OpcodeToString[msg.Opcode], - Authoritative: msg.Authoritative, - Truncated: msg.Truncated, - RecursionDesired: msg.RecursionDesired, - RecursionAvailable: msg.RecursionAvailable, - Zero: msg.Zero, - AuthenticatedData: msg.AuthenticatedData, - CheckingDisabled: msg.CheckingDisabled, - Status: dns.RcodeToString[msg.Rcode], - }, + ret := &Message{ + RTT: res.RTT.String(), + Server: opts.Request.Server + serverExtra(opts), + When: time.Now().Format(time.RFC3339), + DateString: time.Now().Format(time.RFC3339), + DateSeconds: time.Now().Format(time.UnixDate), + MsgSize: res.DNS.Len(), + ID: msg.Id, + Opcode: dns.OpcodeToString[msg.Opcode], + Status: dns.RcodeToString[msg.Rcode], + Response: msg.Response, + + Authoritative: msg.Authoritative, + Truncated: msg.Truncated, + RecursionDesired: msg.RecursionDesired, + RecursionAvailable: msg.RecursionAvailable, + Zero: msg.Zero, + AuthenticatedData: msg.AuthenticatedData, + CheckingDisabled: msg.CheckingDisabled, } opt := msg.IsEdns0() if opt != nil && opts.Display.Opt { - ret.Opt, err = parseOpt(*opt) + ret.Opt, err = ret.ParseOpt(*opt) if err != nil { return nil, fmt.Errorf("edns print: %w", err) } } if opts.Display.Question { - for _, question := range msg.Question { - var name string - if opts.Display.UcodeTranslate { - name, err = idna.ToUnicode(question.Name) - if err != nil { - return nil, fmt.Errorf("punycode to unicode: %w", err) - } - } else { - name = question.Name - } - - ret.Question = append(ret.Question, Question{ - Name: name, - Type: dns.TypeToString[question.Qtype], - Class: dns.ClassToString[question.Qclass], - }) + err = ret.displayQuestion(msg, opts, opt) + if err != nil { + return nil, fmt.Errorf("unable to display questions: %w", err) } } if opts.Display.Answer { - for _, answer := range msg.Answer { - temp := strings.Split(answer.String(), "\t") - - var ( - ttl string - name string - ) - - if opts.Display.TTL { - if opts.Display.HumanTTL { - ttl = (time.Duration(answer.Header().Ttl) * time.Second).String() - } else { - ttl = strconv.Itoa(int(answer.Header().Ttl)) - } - } - - if opts.Display.UcodeTranslate { - name, err = idna.ToUnicode(answer.Header().Name) - if err != nil { - return nil, fmt.Errorf("punycode to unicode: %w", err) - } - } else { - name = answer.Header().Name - } - - ret.Answer = append(ret.Answer, Answer{ - RRHeader: RRHeader{ - Name: name, - Type: dns.TypeToString[answer.Header().Rrtype], - Class: dns.ClassToString[answer.Header().Class], - Rdlength: answer.Header().Rdlength, - TTL: ttl, - }, - Value: temp[len(temp)-1], - }) + err = ret.displayAnswers(msg, opts, opt) + if err != nil { + return nil, fmt.Errorf("unable to display answers: %w", err) } } if opts.Display.Authority { - for _, ns := range msg.Ns { - temp := strings.Split(ns.String(), "\t") - - var ( - ttl string - name string - ) - - if opts.Display.TTL { - if opts.Display.HumanTTL { - ttl = (time.Duration(ns.Header().Ttl) * time.Second).String() - } else { - ttl = strconv.Itoa(int(ns.Header().Ttl)) - } - } - - if opts.Display.UcodeTranslate { - name, err = idna.ToUnicode(ns.Header().Name) - if err != nil { - return nil, fmt.Errorf("punycode to unicode: %w", err) - } - } else { - name = ns.Header().Name - } - - ret.Authority = append(ret.Authority, Answer{ - RRHeader: RRHeader{ - Name: name, - Type: dns.TypeToString[ns.Header().Rrtype], - Class: dns.ClassToString[ns.Header().Class], - Rdlength: ns.Header().Rdlength, - TTL: ttl, - }, - Value: temp[len(temp)-1], - }) + err = ret.displayAuthority(msg, opts, opt) + if err != nil { + return nil, fmt.Errorf("unable to display authority: %w", err) } } if opts.Display.Additional { - for _, additional := range msg.Extra { - if additional.Header().Rrtype == dns.StringToType["OPT"] { - continue - } else { - temp := strings.Split(additional.String(), "\t") - - var ( - ttl string - name string - ) - - if opts.Display.TTL { - if opts.Display.HumanTTL { - ttl = (time.Duration(additional.Header().Ttl) * time.Second).String() - } else { - ttl = strconv.Itoa(int(additional.Header().Ttl)) - } - } - - if opts.Display.UcodeTranslate { - name, err = idna.ToUnicode(additional.Header().Name) - if err != nil { - return nil, fmt.Errorf("punycode to unicode: %w", err) - } - } else { - name = additional.Header().Name - } - - ret.Additional = append(ret.Additional, Answer{ - RRHeader: RRHeader{ - Name: name, - Type: dns.TypeToString[additional.Header().Rrtype], - Class: dns.ClassToString[additional.Header().Class], - Rdlength: additional.Header().Rdlength, - TTL: ttl, - }, - Value: temp[len(temp)-1], - }) - } - } - } - - if opts.Display.Statistics { - ret.Statistics = Statistics{ - RTT: res.RTT.String(), - Server: opts.Request.Server + serverExtra(opts), - When: time.Now().Format(time.RFC3339), - MsgSize: res.DNS.Len(), - } - } else { - ret.Statistics = Statistics{} - } - - return &ret, nil -} - -func parseOpt(rr dns.OPT) ([]Opts, error) { - ret := []Opts{} - // Most of this is taken from https://github.com/miekg/dns/blob/master/edns.go#L76 - - ret = append(ret, Opts{ - Name: "Version", - Value: strconv.Itoa(int(rr.Version())), - }) - - if rr.Do() { - ret = append(ret, Opts{ - Name: "Flags", - Value: "do", - }) - } else { - ret = append(ret, Opts{ - Name: "Flags", - Value: "", - }) - } - - if rr.Hdr.Ttl&0x7FFF != 0 { - ret = append(ret, Opts{ - Name: "MBZ", - Value: fmt.Sprintf("0x%04x", rr.Hdr.Ttl&0x7FFF), - }) - } - - ret = append(ret, Opts{ - Name: "UDP Buffer Size", - Value: strconv.Itoa(int(rr.UDPSize())), - }) - - for _, opt := range rr.Option { - switch opt.(type) { - case *dns.EDNS0_NSID: - str := opt.String() - - hex, err := hex.DecodeString(str) - if err != nil { - return nil, fmt.Errorf("%w", err) - } - - ret = append(ret, Opts{ - Name: "NSID", - Value: fmt.Sprintf("%s (%s)", str, string(hex)), - }) - case *dns.EDNS0_SUBNET: - ret = append(ret, Opts{ - Name: "Subnet", - Value: opt.String(), - }) - case *dns.EDNS0_COOKIE: - ret = append(ret, Opts{ - Name: "Cookie", - Value: opt.String(), - }) - case *dns.EDNS0_EXPIRE: - ret = append(ret, Opts{ - Name: "Expire", - Value: opt.String(), - }) - case *dns.EDNS0_TCP_KEEPALIVE: - ret = append(ret, Opts{ - Name: "TCP Keepalive", - Value: opt.String(), - }) - case *dns.EDNS0_UL: - ret = append(ret, Opts{ - Name: "Update Lease", - Value: opt.String(), - }) - case *dns.EDNS0_LLQ: - ret = append(ret, Opts{ - Name: "Long Lived Queries", - Value: opt.String(), - }) - case *dns.EDNS0_DAU: - ret = append(ret, Opts{ - Name: "DNSSEC Algorithm Understood", - Value: opt.String(), - }) - case *dns.EDNS0_DHU: - ret = append(ret, Opts{ - Name: "DS Hash Understood", - Value: opt.String(), - }) - case *dns.EDNS0_N3U: - ret = append(ret, Opts{ - Name: "NSEC3 Hash Understood", - Value: opt.String(), - }) - case *dns.EDNS0_LOCAL: - ret = append(ret, Opts{ - Name: "Local OPT", - Value: opt.String(), - }) - case *dns.EDNS0_PADDING: - ret = append(ret, Opts{ - Name: "Padding", - Value: opt.String(), - }) - case *dns.EDNS0_EDE: - ret = append(ret, Opts{ - Name: "EDE", - Value: opt.String(), - }) - case *dns.EDNS0_ESU: - ret = append(ret, Opts{ - Name: "ESU", - Value: opt.String(), - }) + ret.displayAdditional(msg, opts, opt) + if err != nil { + return nil, fmt.Errorf("unable to display additional: %w", err) } } diff --git a/pkg/query/struct.go b/pkg/query/struct.go index 3ad2159..d3a1119 100644 --- a/pkg/query/struct.go +++ b/pkg/query/struct.go @@ -10,51 +10,60 @@ import ( // //nolint:govet // Better looking output is worth a few bytes. type Message struct { - // Header section - Header `json:"header,omitempty" xml:"header,omitempty" yaml:"header,omitempty"` - // Opt Pseudosection - Opt []Opts `json:"opt,omitempty" xml:"opt,omitempty" yaml:"opt,omitempty"` - // Question Section - Question []Question `json:"question,omitempty" xml:"question,omitempty" yaml:"question,omitempty"` - // Answer Section - Answer []Answer `json:"answer,omitempty" xml:"answer,omitempty" yaml:"answer,omitempty"` - // Authority Section - Authority []Answer `json:"authority,omitempty" xml:"authority,omitempty" yaml:"authority,omitempty"` - // Additional Section - Additional []Answer `json:"additional,omitempty" xml:"additional,omitempty" yaml:"additional,omitempty"` - // Statistics :) - Statistics `json:"statistics,omitempty" xml:"statistics,omitempty" yaml:"statistics,omitempty"` -} + DateString string `json:"dateString,omitempty" xml:"dateString,omitempty" yaml:"dateString,omitempty"` + DateSeconds string `json:"dateSeconds,omitempty" xml:"dateSeconds,omitempty" yaml:"dateSeconds,omitempty"` + MsgSize int `json:"msgLength,omitempty" xml:"msgSize,omitempty" yaml:"msgSize,omitempty"` + ID uint16 `json:"id," xml:"id," yaml:"id" example:"12"` -// Header is the header. -type Header struct { Opcode string `json:"opcode," xml:"opcode," yaml:"opcode" example:"QUERY"` Status string `json:"status," xml:"status," yaml:"status" example:"NOERR"` - ID uint16 `json:"id," xml:"id," yaml:"id" example:"12"` Response bool `json:"response," xml:"response," yaml:"response" example:"true"` Authoritative bool `json:"authoritative," xml:"authoritative," yaml:"authoritative" example:"false"` Truncated bool `json:"truncated," xml:"truncated," yaml:"truncated" example:"false"` - RecursionDesired bool `json:"recursionDesired," xml:"recursionDesired," yaml:"recursionDesired" example:"true"` - RecursionAvailable bool `json:"recursionAvailable," xml:"recursionAvailable," yaml:"recursionAvailable" example:"true"` + RecursionDesired bool `json:"RD," xml:"recursionDesired," yaml:"recursionDesired" example:"true"` + RecursionAvailable bool `json:"RA," xml:"recursionAvailable," yaml:"recursionAvailable" example:"true"` Zero bool `json:"zero," xml:"zero," yaml:"zero" example:"false"` AuthenticatedData bool `json:"authenticatedData," xml:"authenticatedData," yaml:"authenticatedData" example:"false"` CheckingDisabled bool `json:"checkingDisabled," xml:"checkingDisabled," yaml:"checkingDisabled" example:"false"` + Name string `json:"QNAME,omitempty" xml:"QNAME,omitempty" yaml:"QNAME,omitempty" example:"localhost"` + Type uint16 `json:"QTYPE,omitempty" xml:"QTYPE,omitempty" yaml:"QTYPE,omitempty" example:"IN"` + TypeName string `json:"QTYPEname,omitempty" xml:"QTYPEname,omitempty" yaml:"QTYPEname,omitempty" example:"IN"` + Class string `json:"QCLASS,omitempty" xml:"QCLASS,omitempty" yaml:"QCLASS,omitempty" example:"A"` + ClassName string `json:"QCLASSname,omitempty" xml:"QCLASSname,omitempty" yaml:"QCLASSname,omitempty" example:"1"` + RTT string `json:"queryTime,omitempty" xml:"queryTime,omitempty" yaml:"queryTime,omitempty"` + Server string `json:"server,omitempty" xml:"server,omitempty" yaml:"server,omitempty"` + When string `json:"when,omitempty" xml:"when,omitempty" yaml:"when,omitempty"` + + Opt []Opts `json:"opt,omitempty" xml:"opt,omitempty" yaml:"opt,omitempty"` + // Question Section + Question []Question `json:"question,omitempty" xml:"question,omitempty" yaml:"question,omitempty"` + + // Answer Section + AnswerRRs []Answer `json:"answersRRs,omitempty" xml:"answersRRs,omitempty" yaml:"answersRRs,omitempty" example:"false"` + AuthoritativeRRs []Answer `json:"authorityRRs,omitempty" xml:"authorityRRs,omitempty" yaml:"authorityRRs,omitempty" example:"false"` + AdditionalRRs []Answer `json:"additionalRRs,omitempty" xml:"additionalRRs,omitempty" yaml:"additionalRRs,omitempty" example:"false"` } // Question is a DNS Query. type Question struct { - Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"localhost"` - Class string `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` - Type string `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` + Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"localhost"` + Type uint16 `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` + TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"IN"` + Class string `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` + ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"1"` } // RRHeader is for DNS Resource Headers. -type RRHeader struct { - Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"127.0.0.1"` - TTL string `json:"ttl,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty" example:"0ms"` - Class string `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` - Type string `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` - Rdlength uint16 `json:"-" xml:"-" yaml:"-"` +type Answer struct { + Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"127.0.0.1"` + Type uint16 `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` + TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"IN"` + Class uint16 `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` + ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"A"` + TTL string `json:"ttl,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty" example:"0ms"` + Value string `json:"response,omitempty" xml:"response,omitempty" yaml:"response,omitempty"` + Rdlength uint16 `json:"RDLENGTH,omitempty" xml:"RDLENGTH,omitempty" yaml:"RDLENGTH,omitempty"` + Rdhex string `json:"RDATAHEX,omitempty" xml:"RDATAHEX,omitempty" yaml:"RDATAHEX,omitempty"` } // Opts is for the OPT pseudosection, nearly exclusively for EDNS. @@ -63,18 +72,4 @@ type Opts struct { Value string `json:"value" xml:"value" yaml:"value"` } -// Answer is for a DNS Response. -type Answer struct { - Value string `json:"response,omitempty" xml:"response,omitempty" yaml:"response,omitempty"` - RRHeader `json:"header,omitempty" xml:"header,omitempty" yaml:"header,omitempty"` -} - -// Statistics is the little bit at the bottom :). -type Statistics struct { - RTT string `json:"queryTime,omitempty" xml:"queryTime,omitempty" yaml:"queryTime,omitempty"` - Server string `json:"server,omitempty" xml:"server,omitempty" yaml:"server,omitempty"` - When string `json:"when,omitempty" xml:"when,omitempty" yaml:"when,omitempty"` - MsgSize int `json:"msgSize,omitempty" xml:"msgSize,omitempty" yaml:"msgSize,omitempty"` -} - var errNoMessage = errors.New("no message") diff --git a/pkg/query/util.go b/pkg/query/util.go new file mode 100644 index 0000000..e543aba --- /dev/null +++ b/pkg/query/util.go @@ -0,0 +1,282 @@ +package query + +import ( + "encoding/hex" + "fmt" + "strconv" + "strings" + "time" + + "git.froth.zone/sam/awl/pkg/util" + "github.com/miekg/dns" + "golang.org/x/net/idna" +) + +func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { + var ( + name string + err error + ) + for _, question := range msg.Question { + if opts.Display.UcodeTranslate { + name, err = idna.ToUnicode(question.Name) + if err != nil { + return fmt.Errorf("punycode to unicode: %w", err) + } + } else { + name = question.Name + } + + message.Name = name + message.Type = opt.Header().Rrtype + message.TypeName = dns.TypeToString[question.Qtype] + message.Class = dns.ClassToString[question.Qclass] + message.ClassName = dns.TypeToString[question.Qtype] + } + return nil +} + +func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { + var ( + ttl string + name string + err error + ) + for _, answer := range msg.Answer { + temp := strings.Split(answer.String(), "\t") + + if opts.Display.TTL { + if opts.Display.HumanTTL { + ttl = (time.Duration(answer.Header().Ttl) * time.Second).String() + } else { + ttl = strconv.Itoa(int(answer.Header().Ttl)) + } + } + + if opts.Display.UcodeTranslate { + name, err = idna.ToUnicode(answer.Header().Name) + if err != nil { + return fmt.Errorf("punycode to unicode: %w", err) + } + } else { + name = answer.Header().Name + } + + message.AnswerRRs = append(message.AnswerRRs, Answer{ + + Name: name, + TypeName: dns.TypeToString[answer.Header().Rrtype], + Type: answer.Header().Rrtype, + Rdlength: answer.Header().Rdlength, + TTL: ttl, + + Value: temp[len(temp)-1], + }) + } + return err +} + +func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { + var ( + ttl string + name string + err error + ) + + for _, ns := range msg.Ns { + temp := strings.Split(ns.String(), "\t") + + if opts.Display.TTL { + if opts.Display.HumanTTL { + ttl = (time.Duration(ns.Header().Ttl) * time.Second).String() + } else { + ttl = strconv.Itoa(int(ns.Header().Ttl)) + } + } + + if opts.Display.UcodeTranslate { + name, err = idna.ToUnicode(ns.Header().Name) + if err != nil { + return fmt.Errorf("punycode to unicode: %w", err) + } + } else { + name = ns.Header().Name + } + + message.AuthoritativeRRs = append(message.AuthoritativeRRs, Answer{ + + Name: name, + TypeName: dns.TypeToString[ns.Header().Rrtype], + Type: ns.Header().Rrtype, + Class: ns.Header().Rrtype, + ClassName: dns.ClassToString[ns.Header().Class], + Rdlength: ns.Header().Rdlength, + TTL: ttl, + + Value: temp[len(temp)-1], + }) + } + return err +} + +func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { + var ( + ttl string + name string + err error + ) + for _, additional := range msg.Extra { + if additional.Header().Rrtype == dns.StringToType["OPT"] { + continue + } else { + temp := strings.Split(additional.String(), "\t") + + if opts.Display.TTL { + if opts.Display.HumanTTL { + ttl = (time.Duration(additional.Header().Ttl) * time.Second).String() + } else { + ttl = strconv.Itoa(int(additional.Header().Ttl)) + } + } + + if opts.Display.UcodeTranslate { + name, err = idna.ToUnicode(additional.Header().Name) + if err != nil { + return fmt.Errorf("punycode to unicode: %w", err) + } + } else { + name = additional.Header().Name + } + + message.AdditionalRRs = append(message.AdditionalRRs, Answer{ + Name: name, + TypeName: dns.TypeToString[additional.Header().Rrtype], + Type: additional.Header().Rrtype, + Class: additional.Header().Rrtype, + ClassName: dns.ClassToString[additional.Header().Class], + Rdlength: additional.Header().Rdlength, + TTL: ttl, + Value: temp[len(temp)-1], + }) + } + } + return err +} + +func (message *Message) ParseOpt(rr dns.OPT) ([]Opts, error) { + ret := []Opts{} + // Most of this is taken from https://github.com/miekg/dns/blob/master/edns.go#L76 + + ret = append(ret, Opts{ + Name: "Version", + Value: strconv.Itoa(int(rr.Version())), + }) + + if rr.Do() { + ret = append(ret, Opts{ + Name: "Flags", + Value: "do", + }) + } else { + ret = append(ret, Opts{ + Name: "Flags", + Value: "", + }) + } + + if rr.Hdr.Ttl&0x7FFF != 0 { + ret = append(ret, Opts{ + Name: "MBZ", + Value: fmt.Sprintf("0x%04x", rr.Hdr.Ttl&0x7FFF), + }) + } + + ret = append(ret, Opts{ + Name: "UDP Buffer Size", + Value: strconv.Itoa(int(rr.UDPSize())), + }) + + for _, opt := range rr.Option { + switch opt.(type) { + case *dns.EDNS0_NSID: + str := opt.String() + + hex, err := hex.DecodeString(str) + if err != nil { + return nil, fmt.Errorf("%w", err) + } + + ret = append(ret, Opts{ + Name: "NSID", + Value: fmt.Sprintf("%s (%s)", str, string(hex)), + }) + case *dns.EDNS0_SUBNET: + ret = append(ret, Opts{ + Name: "Subnet", + Value: opt.String(), + }) + case *dns.EDNS0_COOKIE: + ret = append(ret, Opts{ + Name: "Cookie", + Value: opt.String(), + }) + case *dns.EDNS0_EXPIRE: + ret = append(ret, Opts{ + Name: "Expire", + Value: opt.String(), + }) + case *dns.EDNS0_TCP_KEEPALIVE: + ret = append(ret, Opts{ + Name: "TCP Keepalive", + Value: opt.String(), + }) + case *dns.EDNS0_UL: + ret = append(ret, Opts{ + Name: "Update Lease", + Value: opt.String(), + }) + case *dns.EDNS0_LLQ: + ret = append(ret, Opts{ + Name: "Long Lived Queries", + Value: opt.String(), + }) + case *dns.EDNS0_DAU: + ret = append(ret, Opts{ + Name: "DNSSEC Algorithm Understood", + Value: opt.String(), + }) + case *dns.EDNS0_DHU: + ret = append(ret, Opts{ + Name: "DS Hash Understood", + Value: opt.String(), + }) + case *dns.EDNS0_N3U: + ret = append(ret, Opts{ + Name: "NSEC3 Hash Understood", + Value: opt.String(), + }) + case *dns.EDNS0_LOCAL: + ret = append(ret, Opts{ + Name: "Local OPT", + Value: opt.String(), + }) + case *dns.EDNS0_PADDING: + ret = append(ret, Opts{ + Name: "Padding", + Value: opt.String(), + }) + case *dns.EDNS0_EDE: + ret = append(ret, Opts{ + Name: "EDE", + Value: opt.String(), + }) + case *dns.EDNS0_ESU: + ret = append(ret, Opts{ + Name: "ESU", + Value: opt.String(), + }) + } + } + + return ret, nil +} -- 2.45.2 From 5e0ca30b2e73fb8d05b54e9069fe7a33b578830a Mon Sep 17 00:00:00 2001 From: grumbulon Date: Thu, 15 Dec 2022 17:11:38 -0500 Subject: [PATCH 02/13] lint --- pkg/query/print.go | 2 +- pkg/query/struct.go | 8 ++++++-- pkg/query/util.go | 16 +++++++++++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pkg/query/print.go b/pkg/query/print.go index 1737525..9842855 100644 --- a/pkg/query/print.go +++ b/pkg/query/print.go @@ -303,7 +303,7 @@ func MakePrintable(res util.Response, opts *util.Options) (*Message, error) { } if opts.Display.Additional { - ret.displayAdditional(msg, opts, opt) + err = ret.displayAdditional(msg, opts, opt) if err != nil { return nil, fmt.Errorf("unable to display additional: %w", err) } diff --git a/pkg/query/struct.go b/pkg/query/struct.go index d3a1119..877c05c 100644 --- a/pkg/query/struct.go +++ b/pkg/query/struct.go @@ -8,7 +8,7 @@ import ( // Message is for overall DNS responses. // -//nolint:govet // Better looking output is worth a few bytes. +//nolint:govet,tagliatelle // Better looking output is worth a few bytes. type Message struct { DateString string `json:"dateString,omitempty" xml:"dateString,omitempty" yaml:"dateString,omitempty"` DateSeconds string `json:"dateSeconds,omitempty" xml:"dateSeconds,omitempty" yaml:"dateSeconds,omitempty"` @@ -45,6 +45,8 @@ type Message struct { } // Question is a DNS Query. +// +//nolint:govet,tagliatelle type Question struct { Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"localhost"` Type uint16 `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` @@ -53,7 +55,9 @@ type Question struct { ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"1"` } -// RRHeader is for DNS Resource Headers. +// Answer is for DNS Resource Headers. +// +//nolint:govet,tagliatelle type Answer struct { Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"127.0.0.1"` Type uint16 `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` diff --git a/pkg/query/util.go b/pkg/query/util.go index e543aba..748d56f 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -17,6 +17,7 @@ func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *d name string err error ) + for _, question := range msg.Question { if opts.Display.UcodeTranslate { name, err = idna.ToUnicode(question.Name) @@ -33,6 +34,7 @@ func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *d message.Class = dns.ClassToString[question.Qclass] message.ClassName = dns.TypeToString[question.Qtype] } + return nil } @@ -42,6 +44,7 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn name string err error ) + for _, answer := range msg.Answer { temp := strings.Split(answer.String(), "\t") @@ -63,7 +66,6 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn } message.AnswerRRs = append(message.AnswerRRs, Answer{ - Name: name, TypeName: dns.TypeToString[answer.Header().Rrtype], Type: answer.Header().Rrtype, @@ -73,7 +75,8 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn Value: temp[len(temp)-1], }) } - return err + + return nil } func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { @@ -104,7 +107,6 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * } message.AuthoritativeRRs = append(message.AuthoritativeRRs, Answer{ - Name: name, TypeName: dns.TypeToString[ns.Header().Rrtype], Type: ns.Header().Rrtype, @@ -116,7 +118,8 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * Value: temp[len(temp)-1], }) } - return err + + return nil } func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { @@ -125,6 +128,7 @@ func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt name string err error ) + for _, additional := range msg.Extra { if additional.Header().Rrtype == dns.StringToType["OPT"] { continue @@ -160,9 +164,11 @@ func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt }) } } - return err + + return nil } +// ParseOpt parses opts. func (message *Message) ParseOpt(rr dns.OPT) ([]Opts, error) { ret := []Opts{} // Most of this is taken from https://github.com/miekg/dns/blob/master/edns.go#L76 -- 2.45.2 From 9226d0cdf06df7ceec2eaefbd834ce68e92e2b0c Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Thu, 15 Dec 2022 23:49:02 +0100 Subject: [PATCH 03/13] small things to make more correct Signed-off-by: Sam Therapy --- pkg/query/struct.go | 14 +++++++------- pkg/query/util.go | 22 ++++++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/pkg/query/struct.go b/pkg/query/struct.go index 877c05c..b95a1da 100644 --- a/pkg/query/struct.go +++ b/pkg/query/struct.go @@ -28,7 +28,7 @@ type Message struct { Name string `json:"QNAME,omitempty" xml:"QNAME,omitempty" yaml:"QNAME,omitempty" example:"localhost"` Type uint16 `json:"QTYPE,omitempty" xml:"QTYPE,omitempty" yaml:"QTYPE,omitempty" example:"IN"` TypeName string `json:"QTYPEname,omitempty" xml:"QTYPEname,omitempty" yaml:"QTYPEname,omitempty" example:"IN"` - Class string `json:"QCLASS,omitempty" xml:"QCLASS,omitempty" yaml:"QCLASS,omitempty" example:"A"` + Class uint16 `json:"QCLASS,omitempty" xml:"QCLASS,omitempty" yaml:"QCLASS,omitempty" example:"A"` ClassName string `json:"QCLASSname,omitempty" xml:"QCLASSname,omitempty" yaml:"QCLASSname,omitempty" example:"1"` RTT string `json:"queryTime,omitempty" xml:"queryTime,omitempty" yaml:"queryTime,omitempty"` Server string `json:"server,omitempty" xml:"server,omitempty" yaml:"server,omitempty"` @@ -49,9 +49,9 @@ type Message struct { //nolint:govet,tagliatelle type Question struct { Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"localhost"` - Type uint16 `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` + Type uint16 `json:"TYPE,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"IN"` - Class string `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` + Class uint16 `json:"CLASS,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"1"` } @@ -59,12 +59,12 @@ type Question struct { // //nolint:govet,tagliatelle type Answer struct { - Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"127.0.0.1"` - Type uint16 `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` + Name string `json:"NAME,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"127.0.0.1"` + Type uint16 `json:"TYPE,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"IN"` - Class uint16 `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` + Class uint16 `json:"CLASS,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"A"` - TTL string `json:"ttl,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty" example:"0ms"` + TTL string `json:"TTL,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty" example:"0ms"` Value string `json:"response,omitempty" xml:"response,omitempty" yaml:"response,omitempty"` Rdlength uint16 `json:"RDLENGTH,omitempty" xml:"RDLENGTH,omitempty" yaml:"RDLENGTH,omitempty"` Rdhex string `json:"RDATAHEX,omitempty" xml:"RDATAHEX,omitempty" yaml:"RDATAHEX,omitempty"` diff --git a/pkg/query/util.go b/pkg/query/util.go index 748d56f..0d8d7f5 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -29,10 +29,10 @@ func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *d } message.Name = name - message.Type = opt.Header().Rrtype + message.Type = question.Qtype message.TypeName = dns.TypeToString[question.Qtype] - message.Class = dns.ClassToString[question.Qclass] - message.ClassName = dns.TypeToString[question.Qtype] + message.Class = question.Qclass + message.ClassName = dns.ClassToString[question.Qclass] } return nil @@ -66,11 +66,13 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn } message.AnswerRRs = append(message.AnswerRRs, Answer{ - Name: name, - TypeName: dns.TypeToString[answer.Header().Rrtype], - Type: answer.Header().Rrtype, - Rdlength: answer.Header().Rdlength, - TTL: ttl, + Name: name, + ClassName: dns.ClassToString[answer.Header().Class], + Class: answer.Header().Class, + TypeName: dns.TypeToString[answer.Header().Rrtype], + Type: answer.Header().Rrtype, + Rdlength: answer.Header().Rdlength, + TTL: ttl, Value: temp[len(temp)-1], }) @@ -110,7 +112,7 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * Name: name, TypeName: dns.TypeToString[ns.Header().Rrtype], Type: ns.Header().Rrtype, - Class: ns.Header().Rrtype, + Class: ns.Header().Class, ClassName: dns.ClassToString[ns.Header().Class], Rdlength: ns.Header().Rdlength, TTL: ttl, @@ -156,7 +158,7 @@ func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt Name: name, TypeName: dns.TypeToString[additional.Header().Rrtype], Type: additional.Header().Rrtype, - Class: additional.Header().Rrtype, + Class: additional.Header().Class, ClassName: dns.ClassToString[additional.Header().Class], Rdlength: additional.Header().Rdlength, TTL: ttl, -- 2.45.2 From beaa18d6fbfb79aeba545cd0b0bbf638329f1bf7 Mon Sep 17 00:00:00 2001 From: grumbulon Date: Thu, 15 Dec 2022 18:00:01 -0500 Subject: [PATCH 04/13] lint and stuff --- pkg/query/struct.go | 17 +++---- pkg/query/util.go | 108 +++++++++++++++++++++++++++++++------------- 2 files changed, 86 insertions(+), 39 deletions(-) diff --git a/pkg/query/struct.go b/pkg/query/struct.go index 877c05c..1225374 100644 --- a/pkg/query/struct.go +++ b/pkg/query/struct.go @@ -28,7 +28,7 @@ type Message struct { Name string `json:"QNAME,omitempty" xml:"QNAME,omitempty" yaml:"QNAME,omitempty" example:"localhost"` Type uint16 `json:"QTYPE,omitempty" xml:"QTYPE,omitempty" yaml:"QTYPE,omitempty" example:"IN"` TypeName string `json:"QTYPEname,omitempty" xml:"QTYPEname,omitempty" yaml:"QTYPEname,omitempty" example:"IN"` - Class string `json:"QCLASS,omitempty" xml:"QCLASS,omitempty" yaml:"QCLASS,omitempty" example:"A"` + Class uint16 `json:"QCLASS,omitempty" xml:"QCLASS,omitempty" yaml:"QCLASS,omitempty" example:"A"` ClassName string `json:"QCLASSname,omitempty" xml:"QCLASSname,omitempty" yaml:"QCLASSname,omitempty" example:"1"` RTT string `json:"queryTime,omitempty" xml:"queryTime,omitempty" yaml:"queryTime,omitempty"` Server string `json:"server,omitempty" xml:"server,omitempty" yaml:"server,omitempty"` @@ -49,9 +49,9 @@ type Message struct { //nolint:govet,tagliatelle type Question struct { Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"localhost"` - Type uint16 `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` + Type uint16 `json:"TYPE,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"IN"` - Class string `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` + Class uint16 `json:"CLASS,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"1"` } @@ -59,13 +59,14 @@ type Question struct { // //nolint:govet,tagliatelle type Answer struct { - Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"127.0.0.1"` - Type uint16 `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` + Name string `json:"NAME,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"127.0.0.1"` + Type uint16 `json:"TYPE,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"IN"` - Class uint16 `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` + Class uint16 `json:"CLASS,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"A"` - TTL string `json:"ttl,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty" example:"0ms"` - Value string `json:"response,omitempty" xml:"response,omitempty" yaml:"response,omitempty"` + TTL string `json:"TTL,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty" example:"0ms"` + ValueA string `json:"rdataA,omitempty" xml:"rdataA,omitempty" yaml:"rdataA,omitempty"` + ValueAAAA string `json:"rdataAAAA,omitempty" xml:"rdataAAAA,omitempty" yaml:"rdataAAAA,omitempty"` Rdlength uint16 `json:"RDLENGTH,omitempty" xml:"RDLENGTH,omitempty" yaml:"RDLENGTH,omitempty"` Rdhex string `json:"RDATAHEX,omitempty" xml:"RDATAHEX,omitempty" yaml:"RDATAHEX,omitempty"` } diff --git a/pkg/query/util.go b/pkg/query/util.go index 748d56f..54611d3 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -12,6 +12,8 @@ import ( "golang.org/x/net/idna" ) +const aaaa = "AAAA" + func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { var ( name string @@ -29,10 +31,10 @@ func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *d } message.Name = name - message.Type = opt.Header().Rrtype + message.Type = question.Qtype message.TypeName = dns.TypeToString[question.Qtype] - message.Class = dns.ClassToString[question.Qclass] - message.ClassName = dns.TypeToString[question.Qtype] + message.Class = question.Qclass + message.ClassName = dns.ClassToString[question.Qclass] } return nil @@ -65,15 +67,31 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn name = answer.Header().Name } - message.AnswerRRs = append(message.AnswerRRs, Answer{ - Name: name, - TypeName: dns.TypeToString[answer.Header().Rrtype], - Type: answer.Header().Rrtype, - Rdlength: answer.Header().Rdlength, - TTL: ttl, + switch dns.TypeToString[answer.Header().Rrtype] { + case "A": + message.AdditionalRRs = append(message.AdditionalRRs, Answer{ + Name: name, + ClassName: dns.ClassToString[answer.Header().Class], + Class: answer.Header().Class, + TypeName: dns.TypeToString[answer.Header().Rrtype], + Type: answer.Header().Rrtype, + Rdlength: answer.Header().Rdlength, + TTL: ttl, + ValueA: temp[len(temp)-1], + }) - Value: temp[len(temp)-1], - }) + case aaaa: + message.AdditionalRRs = append(message.AdditionalRRs, Answer{ + Name: name, + ClassName: dns.ClassToString[answer.Header().Class], + Class: answer.Header().Class, + TypeName: dns.TypeToString[answer.Header().Rrtype], + Type: answer.Header().Rrtype, + Rdlength: answer.Header().Rdlength, + TTL: ttl, + ValueAAAA: temp[len(temp)-1], + }) + } } return nil @@ -106,17 +124,31 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * name = ns.Header().Name } - message.AuthoritativeRRs = append(message.AuthoritativeRRs, Answer{ - Name: name, - TypeName: dns.TypeToString[ns.Header().Rrtype], - Type: ns.Header().Rrtype, - Class: ns.Header().Rrtype, - ClassName: dns.ClassToString[ns.Header().Class], - Rdlength: ns.Header().Rdlength, - TTL: ttl, + switch dns.TypeToString[ns.Header().Rrtype] { + case "A": + message.AdditionalRRs = append(message.AdditionalRRs, Answer{ + Name: name, + TypeName: dns.TypeToString[ns.Header().Rrtype], + Type: ns.Header().Rrtype, + Class: ns.Header().Class, + ClassName: dns.ClassToString[ns.Header().Class], + Rdlength: ns.Header().Rdlength, + TTL: ttl, + ValueA: temp[len(temp)-1], + }) - Value: temp[len(temp)-1], - }) + case aaaa: + message.AdditionalRRs = append(message.AdditionalRRs, Answer{ + Name: name, + TypeName: dns.TypeToString[ns.Header().Rrtype], + Type: ns.Header().Rrtype, + Class: ns.Header().Class, + ClassName: dns.ClassToString[ns.Header().Class], + Rdlength: ns.Header().Rdlength, + TTL: ttl, + ValueAAAA: temp[len(temp)-1], + }) + } } return nil @@ -151,17 +183,31 @@ func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt } else { name = additional.Header().Name } + switch dns.TypeToString[additional.Header().Rrtype] { + case "A": + message.AdditionalRRs = append(message.AdditionalRRs, Answer{ + Name: name, + TypeName: dns.TypeToString[additional.Header().Rrtype], + Type: additional.Header().Rrtype, + Class: additional.Header().Rrtype, + ClassName: dns.ClassToString[additional.Header().Class], + Rdlength: additional.Header().Rdlength, + TTL: ttl, + ValueA: temp[len(temp)-1], + }) - message.AdditionalRRs = append(message.AdditionalRRs, Answer{ - Name: name, - TypeName: dns.TypeToString[additional.Header().Rrtype], - Type: additional.Header().Rrtype, - Class: additional.Header().Rrtype, - ClassName: dns.ClassToString[additional.Header().Class], - Rdlength: additional.Header().Rdlength, - TTL: ttl, - Value: temp[len(temp)-1], - }) + case aaaa: + message.AdditionalRRs = append(message.AdditionalRRs, Answer{ + Name: name, + TypeName: dns.TypeToString[additional.Header().Rrtype], + Type: additional.Header().Rrtype, + Class: additional.Header().Rrtype, + ClassName: dns.ClassToString[additional.Header().Class], + Rdlength: additional.Header().Rdlength, + TTL: ttl, + ValueAAAA: temp[len(temp)-1], + }) + } } } -- 2.45.2 From 431937d0fe2ee51e61f0f615d3d0506bf6adac84 Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Fri, 16 Dec 2022 00:07:27 +0100 Subject: [PATCH 05/13] make time more correct Signed-off-by: Sam Therapy --- pkg/query/print.go | 3 +-- pkg/query/struct.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/query/print.go b/pkg/query/print.go index 9842855..3179924 100644 --- a/pkg/query/print.go +++ b/pkg/query/print.go @@ -255,9 +255,8 @@ func MakePrintable(res util.Response, opts *util.Options) (*Message, error) { ret := &Message{ RTT: res.RTT.String(), Server: opts.Request.Server + serverExtra(opts), - When: time.Now().Format(time.RFC3339), DateString: time.Now().Format(time.RFC3339), - DateSeconds: time.Now().Format(time.UnixDate), + DateSeconds: time.Now().Unix(), MsgSize: res.DNS.Len(), ID: msg.Id, Opcode: dns.OpcodeToString[msg.Opcode], diff --git a/pkg/query/struct.go b/pkg/query/struct.go index 1225374..1dc5b58 100644 --- a/pkg/query/struct.go +++ b/pkg/query/struct.go @@ -11,7 +11,7 @@ import ( //nolint:govet,tagliatelle // Better looking output is worth a few bytes. type Message struct { DateString string `json:"dateString,omitempty" xml:"dateString,omitempty" yaml:"dateString,omitempty"` - DateSeconds string `json:"dateSeconds,omitempty" xml:"dateSeconds,omitempty" yaml:"dateSeconds,omitempty"` + DateSeconds int64 `json:"dateSeconds,omitempty" xml:"dateSeconds,omitempty" yaml:"dateSeconds,omitempty"` MsgSize int `json:"msgLength,omitempty" xml:"msgSize,omitempty" yaml:"msgSize,omitempty"` ID uint16 `json:"id," xml:"id," yaml:"id" example:"12"` -- 2.45.2 From 1d8856c45a4529fa12b2eb5ed5f66cfc82f157fc Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Fri, 16 Dec 2022 00:15:58 +0100 Subject: [PATCH 06/13] skirt around rdata Signed-off-by: Sam Therapy --- pkg/query/struct.go | 3 +- pkg/query/util.go | 105 +++++++++++++------------------------------- 2 files changed, 31 insertions(+), 77 deletions(-) diff --git a/pkg/query/struct.go b/pkg/query/struct.go index 1dc5b58..ff4a411 100644 --- a/pkg/query/struct.go +++ b/pkg/query/struct.go @@ -65,8 +65,7 @@ type Answer struct { Class uint16 `json:"CLASS,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"A"` TTL string `json:"TTL,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty" example:"0ms"` - ValueA string `json:"rdataA,omitempty" xml:"rdataA,omitempty" yaml:"rdataA,omitempty"` - ValueAAAA string `json:"rdataAAAA,omitempty" xml:"rdataAAAA,omitempty" yaml:"rdataAAAA,omitempty"` + Value string `json:"rdata,omitempty" xml:"rdata,omitempty" yaml:"rdata,omitempty"` Rdlength uint16 `json:"RDLENGTH,omitempty" xml:"RDLENGTH,omitempty" yaml:"RDLENGTH,omitempty"` Rdhex string `json:"RDATAHEX,omitempty" xml:"RDATAHEX,omitempty" yaml:"RDATAHEX,omitempty"` } diff --git a/pkg/query/util.go b/pkg/query/util.go index 54611d3..7f0e349 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -12,8 +12,6 @@ import ( "golang.org/x/net/idna" ) -const aaaa = "AAAA" - func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { var ( name string @@ -67,31 +65,17 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn name = answer.Header().Name } - switch dns.TypeToString[answer.Header().Rrtype] { - case "A": - message.AdditionalRRs = append(message.AdditionalRRs, Answer{ - Name: name, - ClassName: dns.ClassToString[answer.Header().Class], - Class: answer.Header().Class, - TypeName: dns.TypeToString[answer.Header().Rrtype], - Type: answer.Header().Rrtype, - Rdlength: answer.Header().Rdlength, - TTL: ttl, - ValueA: temp[len(temp)-1], - }) + message.AnswerRRs = append(message.AnswerRRs, Answer{ + Name: name, + ClassName: dns.ClassToString[answer.Header().Class], + Class: answer.Header().Class, + TypeName: dns.TypeToString[answer.Header().Rrtype], + Type: answer.Header().Rrtype, + Rdlength: answer.Header().Rdlength, + TTL: ttl, - case aaaa: - message.AdditionalRRs = append(message.AdditionalRRs, Answer{ - Name: name, - ClassName: dns.ClassToString[answer.Header().Class], - Class: answer.Header().Class, - TypeName: dns.TypeToString[answer.Header().Rrtype], - Type: answer.Header().Rrtype, - Rdlength: answer.Header().Rdlength, - TTL: ttl, - ValueAAAA: temp[len(temp)-1], - }) - } + Value: temp[len(temp)-1], + }) } return nil @@ -124,31 +108,17 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * name = ns.Header().Name } - switch dns.TypeToString[ns.Header().Rrtype] { - case "A": - message.AdditionalRRs = append(message.AdditionalRRs, Answer{ - Name: name, - TypeName: dns.TypeToString[ns.Header().Rrtype], - Type: ns.Header().Rrtype, - Class: ns.Header().Class, - ClassName: dns.ClassToString[ns.Header().Class], - Rdlength: ns.Header().Rdlength, - TTL: ttl, - ValueA: temp[len(temp)-1], - }) + message.AuthoritativeRRs = append(message.AuthoritativeRRs, Answer{ + Name: name, + TypeName: dns.TypeToString[ns.Header().Rrtype], + Type: ns.Header().Rrtype, + Class: ns.Header().Class, + ClassName: dns.ClassToString[ns.Header().Class], + Rdlength: ns.Header().Rdlength, + TTL: ttl, - case aaaa: - message.AdditionalRRs = append(message.AdditionalRRs, Answer{ - Name: name, - TypeName: dns.TypeToString[ns.Header().Rrtype], - Type: ns.Header().Rrtype, - Class: ns.Header().Class, - ClassName: dns.ClassToString[ns.Header().Class], - Rdlength: ns.Header().Rdlength, - TTL: ttl, - ValueAAAA: temp[len(temp)-1], - }) - } + Value: temp[len(temp)-1], + }) } return nil @@ -183,31 +153,16 @@ func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt } else { name = additional.Header().Name } - switch dns.TypeToString[additional.Header().Rrtype] { - case "A": - message.AdditionalRRs = append(message.AdditionalRRs, Answer{ - Name: name, - TypeName: dns.TypeToString[additional.Header().Rrtype], - Type: additional.Header().Rrtype, - Class: additional.Header().Rrtype, - ClassName: dns.ClassToString[additional.Header().Class], - Rdlength: additional.Header().Rdlength, - TTL: ttl, - ValueA: temp[len(temp)-1], - }) - - case aaaa: - message.AdditionalRRs = append(message.AdditionalRRs, Answer{ - Name: name, - TypeName: dns.TypeToString[additional.Header().Rrtype], - Type: additional.Header().Rrtype, - Class: additional.Header().Rrtype, - ClassName: dns.ClassToString[additional.Header().Class], - Rdlength: additional.Header().Rdlength, - TTL: ttl, - ValueAAAA: temp[len(temp)-1], - }) - } + message.AdditionalRRs = append(message.AdditionalRRs, Answer{ + Name: name, + TypeName: dns.TypeToString[additional.Header().Rrtype], + Type: additional.Header().Rrtype, + Class: additional.Header().Class, + ClassName: dns.ClassToString[additional.Header().Class], + Rdlength: additional.Header().Rdlength, + TTL: ttl, + Value: temp[len(temp)-1], + }) } } -- 2.45.2 From 55cd300f4c9a451d73e2cf6a6fc27d339f5b4599 Mon Sep 17 00:00:00 2001 From: grumbulon Date: Thu, 15 Dec 2022 19:23:22 -0500 Subject: [PATCH 07/13] lint --- pkg/query/util.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pkg/query/util.go b/pkg/query/util.go index c7dfe85..393fae6 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -19,11 +19,6 @@ var ( ) func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { - var ( - name string - err error - ) - for _, question := range msg.Question { if opts.Display.UcodeTranslate { name, err = idna.ToUnicode(question.Name) @@ -82,7 +77,6 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn } func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { - for _, ns := range msg.Ns { temp := strings.Split(ns.String(), "\t") @@ -120,7 +114,6 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * } func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { - for _, additional := range msg.Extra { if additional.Header().Rrtype == dns.StringToType["OPT"] { continue -- 2.45.2 From cfc4d09003d601d73af8a6880dd0946b91836398 Mon Sep 17 00:00:00 2001 From: grumbulon Date: Thu, 15 Dec 2022 19:28:36 -0500 Subject: [PATCH 08/13] oops, accidentally was racist --- pkg/query/util.go | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/pkg/query/util.go b/pkg/query/util.go index 393fae6..a8c07a2 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -12,13 +12,13 @@ import ( "golang.org/x/net/idna" ) -var ( - ttl any - name string - err error -) - func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { + + var ( + name string + err error + ) + for _, question := range msg.Question { if opts.Display.UcodeTranslate { name, err = idna.ToUnicode(question.Name) @@ -40,6 +40,13 @@ func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *d } func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { + + var ( + ttl any + name string + err error + ) + for _, answer := range msg.Answer { temp := strings.Split(answer.String(), "\t") @@ -77,6 +84,13 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn } func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { + + var ( + ttl any + name string + err error + ) + for _, ns := range msg.Ns { temp := strings.Split(ns.String(), "\t") @@ -114,6 +128,13 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * } func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { + + var ( + ttl any + name string + err error + ) + for _, additional := range msg.Extra { if additional.Header().Rrtype == dns.StringToType["OPT"] { continue -- 2.45.2 From 252e95ee2d3195bb27a1c202274b34a1fb49aea4 Mon Sep 17 00:00:00 2001 From: grumbulon Date: Thu, 15 Dec 2022 19:29:34 -0500 Subject: [PATCH 09/13] oops again --- pkg/query/util.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/query/util.go b/pkg/query/util.go index a8c07a2..0782f89 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -13,7 +13,6 @@ import ( ) func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { - var ( name string err error @@ -40,7 +39,6 @@ func (message *Message) displayQuestion(msg *dns.Msg, opts *util.Options, opt *d } func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { - var ( ttl any name string @@ -84,7 +82,6 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn } func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { - var ( ttl any name string @@ -128,7 +125,6 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * } func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt *dns.OPT) error { - var ( ttl any name string -- 2.45.2 From 8aad12c7ef323df247e0093c37cfceb295bc7c96 Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Sat, 17 Dec 2022 16:29:52 +0100 Subject: [PATCH 10/13] add edns Signed-off-by: Sam Therapy --- pkg/query/print.go | 14 +++-- pkg/query/struct.go | 123 ++++++++++++++++++++++++------------- pkg/query/util.go | 144 ++++++++++++++++++-------------------------- 3 files changed, 145 insertions(+), 136 deletions(-) diff --git a/pkg/query/print.go b/pkg/query/print.go index 3179924..5444bf6 100644 --- a/pkg/query/print.go +++ b/pkg/query/print.go @@ -253,28 +253,30 @@ func MakePrintable(res util.Response, opts *util.Options) (*Message, error) { ) // The things I do for compatibility ret := &Message{ - RTT: res.RTT.String(), - Server: opts.Request.Server + serverExtra(opts), DateString: time.Now().Format(time.RFC3339), DateSeconds: time.Now().Unix(), MsgSize: res.DNS.Len(), ID: msg.Id, - Opcode: dns.OpcodeToString[msg.Opcode], - Status: dns.RcodeToString[msg.Rcode], + Opcode: msg.Opcode, Response: msg.Response, Authoritative: msg.Authoritative, Truncated: msg.Truncated, RecursionDesired: msg.RecursionDesired, RecursionAvailable: msg.RecursionAvailable, - Zero: msg.Zero, AuthenticatedData: msg.AuthenticatedData, CheckingDisabled: msg.CheckingDisabled, + Zero: msg.Zero, + + QdCount: len(msg.Question), + AnCount: len(msg.Answer), + NsCount: len(msg.Ns), + ArCount: len(msg.Extra), } opt := msg.IsEdns0() if opt != nil && opts.Display.Opt { - ret.Opt, err = ret.ParseOpt(*opt) + ret.EDNS0, err = ret.ParseOpt(msg.Rcode, *opt) if err != nil { return nil, fmt.Errorf("edns print: %w", err) } diff --git a/pkg/query/struct.go b/pkg/query/struct.go index 76e9d71..f4cb5eb 100644 --- a/pkg/query/struct.go +++ b/pkg/query/struct.go @@ -13,30 +13,30 @@ type Message struct { DateString string `json:"dateString,omitempty" xml:"dateString,omitempty" yaml:"dateString,omitempty"` DateSeconds int64 `json:"dateSeconds,omitempty" xml:"dateSeconds,omitempty" yaml:"dateSeconds,omitempty"` MsgSize int `json:"msgLength,omitempty" xml:"msgSize,omitempty" yaml:"msgSize,omitempty"` - ID uint16 `json:"id," xml:"id," yaml:"id" example:"12"` + ID uint16 `json:"ID" xml:"ID" yaml:"ID" example:"12"` - Opcode string `json:"opcode," xml:"opcode," yaml:"opcode" example:"QUERY"` - Status string `json:"status," xml:"status," yaml:"status" example:"NOERR"` - Response bool `json:"response," xml:"response," yaml:"response" example:"true"` - Authoritative bool `json:"authoritative," xml:"authoritative," yaml:"authoritative" example:"false"` - Truncated bool `json:"truncated," xml:"truncated," yaml:"truncated" example:"false"` - RecursionDesired bool `json:"RD," xml:"recursionDesired," yaml:"recursionDesired" example:"true"` - RecursionAvailable bool `json:"RA," xml:"recursionAvailable," yaml:"recursionAvailable" example:"true"` - Zero bool `json:"zero," xml:"zero," yaml:"zero" example:"false"` - AuthenticatedData bool `json:"authenticatedData," xml:"authenticatedData," yaml:"authenticatedData" example:"false"` - CheckingDisabled bool `json:"checkingDisabled," xml:"checkingDisabled," yaml:"checkingDisabled" example:"false"` - Name string `json:"QNAME,omitempty" xml:"QNAME,omitempty" yaml:"QNAME,omitempty" example:"localhost"` - Type uint16 `json:"QTYPE,omitempty" xml:"QTYPE,omitempty" yaml:"QTYPE,omitempty" example:"IN"` - TypeName string `json:"QTYPEname,omitempty" xml:"QTYPEname,omitempty" yaml:"QTYPEname,omitempty" example:"IN"` - Class uint16 `json:"QCLASS,omitempty" xml:"QCLASS,omitempty" yaml:"QCLASS,omitempty" example:"A"` - ClassName string `json:"QCLASSname,omitempty" xml:"QCLASSname,omitempty" yaml:"QCLASSname,omitempty" example:"1"` - RTT string `json:"queryTime,omitempty" xml:"queryTime,omitempty" yaml:"queryTime,omitempty"` - Server string `json:"server,omitempty" xml:"server,omitempty" yaml:"server,omitempty"` - When string `json:"when,omitempty" xml:"when,omitempty" yaml:"when,omitempty"` + Opcode int `json:"opcode" xml:"opcode" yaml:"opcode" example:"QUERY"` + Response bool `json:"QR" xml:"QR" yaml:"QR" example:"true"` + Authoritative bool `json:"AA" xml:"AA" yaml:"AA" example:"false"` + Truncated bool `json:"TC" xml:"TC" yaml:"TC" example:"false"` + RecursionDesired bool `json:"RD" xml:"RD" yaml:"RD" example:"true"` + RecursionAvailable bool `json:"RA" xml:"RA" yaml:"RA" example:"true"` + AuthenticatedData bool `json:"AD" xml:"AD" yaml:"AD" example:"false"` + CheckingDisabled bool `json:"CD" xml:"CD" yaml:"CD" example:"false"` + Zero bool `json:"Z" xml:"Z" yaml:"Z" example:"false"` - Opt []Opts `json:"opt,omitempty" xml:"opt,omitempty" yaml:"opt,omitempty"` - // Question Section - Question []Question `json:"question,omitempty" xml:"question,omitempty" yaml:"question,omitempty"` + QdCount int `json:"QDCOUNT" xml:"QDCOUNT" yaml:"QDCOUNT" example:"0"` + AnCount int `json:"ANCOUNT" xml:"ANCOUNT" yaml:"ANCOUNT" example:"0"` + NsCount int `json:"NSCOUNT" xml:"NSCOUNT" yaml:"NSCOUNT" example:"0"` + ArCount int `json:"ARCOUNT" xml:"ARCOUNT" yaml:"ARCOUNT" example:"0"` + + Name string `json:"QNAME,omitempty" xml:"QNAME,omitempty" yaml:"QNAME,omitempty" example:"localhost"` + Type uint16 `json:"QTYPE,omitempty" xml:"QTYPE,omitempty" yaml:"QTYPE,omitempty" example:"IN"` + TypeName string `json:"QTYPEname,omitempty" xml:"QTYPEname,omitempty" yaml:"QTYPEname,omitempty" example:"IN"` + Class uint16 `json:"QCLASS,omitempty" xml:"QCLASS,omitempty" yaml:"QCLASS,omitempty" example:"A"` + ClassName string `json:"QCLASSname,omitempty" xml:"QCLASSname,omitempty" yaml:"QCLASSname,omitempty" example:"1"` + + EDNS0 EDNS0 `json:",omitempty" xml:",omitempty" yaml:",omitempty"` // Answer Section AnswerRRs []Answer `json:"answersRRs,omitempty" xml:"answersRRs,omitempty" yaml:"answersRRs,omitempty" example:"false"` @@ -44,36 +44,73 @@ type Message struct { AdditionalRRs []Answer `json:"additionalRRs,omitempty" xml:"additionalRRs,omitempty" yaml:"additionalRRs,omitempty" example:"false"` } -// Question is a DNS Query. -// -//nolint:govet,tagliatelle -type Question struct { - Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"localhost"` - Type uint16 `json:"TYPE,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` - TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"IN"` - Class uint16 `json:"CLASS,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` - ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"1"` -} - // Answer is for DNS Resource Headers. // //nolint:govet,tagliatelle type Answer struct { - Name string `json:"NAME,omitempty" xml:"name,omitempty" yaml:"name,omitempty" example:"127.0.0.1"` - Type uint16 `json:"TYPE,omitempty" xml:"type,omitempty" yaml:"type,omitempty" example:"IN"` - TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"IN"` - Class uint16 `json:"CLASS,omitempty" xml:"class,omitempty" yaml:"class,omitempty" example:"A"` - ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"A"` - TTL any `json:"TTL,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty" example:"0ms"` + Name string `json:"NAME,omitempty" xml:"NAME,omitempty" yaml:"NAME,omitempty" example:"127.0.0.1"` + Type uint16 `json:"TYPE,omitempty" xml:"TYPE,omitempty" yaml:"TYPE,omitempty" example:"1"` + TypeName string `json:"TYPEname,omitempty" xml:"TYPEname,omitempty" yaml:"TYPEname,omitempty" example:"A"` + Class uint16 `json:"CLASS,omitempty" xml:"CLASS,omitempty" yaml:"CLASS,omitempty" example:"1"` + ClassName string `json:"CLASSname,omitempty" xml:"CLASSname,omitempty" yaml:"CLASSname,omitempty" example:"IN"` + TTL any `json:"TTL,omitempty" xml:"TTL,omitempty" yaml:"TTL,omitempty" example:"0ms"` Value string `json:"rdata,omitempty" xml:"rdata,omitempty" yaml:"rdata,omitempty"` Rdlength uint16 `json:"RDLENGTH,omitempty" xml:"RDLENGTH,omitempty" yaml:"RDLENGTH,omitempty"` Rdhex string `json:"RDATAHEX,omitempty" xml:"RDATAHEX,omitempty" yaml:"RDATAHEX,omitempty"` } -// Opts is for the OPT pseudosection, nearly exclusively for EDNS. -type Opts struct { - Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"` - Value string `json:"value" xml:"value" yaml:"value"` +// EDNS0 is for all EDNS options. +// +// RFC: https://datatracker.ietf.org/doc/draft-peltan-edns-presentation-format/ +// +//nolint:govet,tagliatelle +type EDNS0 struct { + Flags []string `json:"FLAGS" xml:"FLAGS" yaml:"FLAGS"` + Rcode string `json:"RCODE" xml:"RCODE" yaml:"RCODE"` + PayloadSize uint16 `json:"UDPSIZE" xml:"UDPSIZE" yaml:"UDPSIZE"` + LLQ *EdnsLLQ `json:"LLQ,omitempty" xml:"LLQ,omitempty" yaml:"LLQ,omitempty"` + NsidHex string `json:"NSIDHEX,omitempty" xml:"NSIDHEX,omitempty" yaml:"NSIDHEX,omitempty"` + Nsid string `json:"NSID,omitempty" xml:"NSID,omitempty" yaml:"NSID,omitempty"` + Dau []uint8 `json:"DAU,omitempty" xml:"DAU,omitempty" yaml:"DAU,omitempty"` + Dhu []uint8 `json:"DHU,omitempty" xml:"DHU,omitempty" yaml:"DHU,omitempty"` + N3u []uint8 `json:"N3U,omitempty" xml:"N3U,omitempty" yaml:"N3U,omitempty"` + Subnet *EDNSSubnet `json:"ECS,omitempty" xml:"ECS,omitempty" yaml:"ECS,omitempty"` + Expire uint32 `json:"EXPIRE,omitempty" xml:"EXPIRE,omitempty" yaml:"EXPIRE,omitempty"` + Cookie []string `json:"COOKIE,omitempty" xml:"COOKIE,omitempty" yaml:"COOKIE,omitempty"` + KeepAlive uint16 `json:"KEEPALIVE,omitempty" xml:"KEEPALIVE,omitempty" yaml:"KEEPALIVE,omitempty"` + Padding string `json:"PADDING,omitempty" xml:"PADDING,omitempty" yaml:"PADDING,omitempty"` + Chain string `json:"CHAIN,omitempty" xml:"CHAIN,omitempty" yaml:"CHAIN,omitempty"` + EDE *EDNSErr `json:"EDE,omitempty" xml:"EDE,omitempty" yaml:"EDE,omitempty"` +} + +// EdnsLLQ is for Long-lived queries. +// +//nolint:tagliatelle +type EdnsLLQ struct { + Version uint16 `json:"LLQ-VERSION" xml:"LLQ-VERSION" yaml:"LLQ-VERSION"` + Opcode uint16 `json:"LLQ-OPCODE" xml:"LLQ-OPCODE" yaml:"LLQ-OPCODE"` + Error uint16 `json:"LLQ-ERROR" xml:"LLQ-ERROR" yaml:"LLQ-ERROR"` + ID uint64 `json:"LLQ-ID" xml:"LLQ-ID" yaml:"LLQ-ID"` + Lease uint32 `json:"LLQ-LEASE" xml:"LLQ-LEASE" yaml:"LLQ-LEASE"` +} + +// EDNSSubnet is for EDNS subnet options, +// +//nolint:govet,tagliatelle +type EDNSSubnet struct { + Family uint16 `json:"FAMILY" xml:"FAMILY" yaml:"FAMILY"` + IP string + Source uint8 `json:"SOURCE" xml:"SOURCE" yaml:"SOURCE"` + Scope uint8 `json:"SCOPE,omitempty" xml:"SCOPE,omitempty" yaml:"SCOPE,omitempty"` +} + +// EDNSErr is for EDE codes +// +//nolint:govet,tagliatelle +type EDNSErr struct { + Code uint16 `json:"INFO-CODE" xml:"INFO-CODE" yaml:"INFO-CODE"` + Purpose string + Text string `json:"EXTRA-TEXT,omitempty" xml:"EXTRA-TEXT,omitempty" yaml:"EXTRA-TEXT,omitempty"` } var errNoMessage = errors.New("no message") diff --git a/pkg/query/util.go b/pkg/query/util.go index 0782f89..97b52c6 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -170,118 +170,88 @@ func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt } // ParseOpt parses opts. -func (message *Message) ParseOpt(rr dns.OPT) ([]Opts, error) { - ret := []Opts{} +func (message *Message) ParseOpt(rcode int, rr dns.OPT) (ret EDNS0, err error) { + ret.Rcode = dns.RcodeToString[rcode] + // Most of this is taken from https://github.com/miekg/dns/blob/master/edns.go#L76 - - ret = append(ret, Opts{ - Name: "Version", - Value: strconv.Itoa(int(rr.Version())), - }) - if rr.Do() { - ret = append(ret, Opts{ - Name: "Flags", - Value: "do", - }) - } else { - ret = append(ret, Opts{ - Name: "Flags", - Value: "", - }) + ret.Flags = append(ret.Flags, "DO") } - if rr.Hdr.Ttl&0x7FFF != 0 { - ret = append(ret, Opts{ - Name: "MBZ", - Value: fmt.Sprintf("0x%04x", rr.Hdr.Ttl&0x7FFF), - }) + for i := uint32(1); i <= 0x7FFF; i <<= 1 { + if rr.Hdr.Ttl&i != 0 { + ret.Flags = append(ret.Flags, fmt.Sprintf("FLAG%d", i)) + } } - ret = append(ret, Opts{ - Name: "UDP Buffer Size", - Value: strconv.Itoa(int(rr.UDPSize())), - }) + ret.PayloadSize = rr.UDPSize() for _, opt := range rr.Option { - switch opt.(type) { + switch opt := opt.(type) { case *dns.EDNS0_NSID: str := opt.String() hex, err := hex.DecodeString(str) if err != nil { - return nil, fmt.Errorf("%w", err) + return ret, fmt.Errorf("%w", err) } - ret = append(ret, Opts{ - Name: "NSID", - Value: fmt.Sprintf("%s (%s)", str, string(hex)), - }) + ret.NsidHex = string(hex) + ret.Nsid = str + case *dns.EDNS0_SUBNET: - ret = append(ret, Opts{ - Name: "Subnet", - Value: opt.String(), - }) + ret.Subnet = &EDNSSubnet{ + Source: opt.SourceNetmask, + Family: opt.Family, + } + + // 1: IPv4 2: IPv6 + if ret.Subnet.Family <= 2 { + ret.Subnet.IP = opt.Address.String() + } else { + ret.Subnet.IP = hex.EncodeToString([]byte(opt.Address)) + } + + if opt.SourceScope != 0 { + ret.Subnet.Scope = opt.SourceScope + } + case *dns.EDNS0_COOKIE: - ret = append(ret, Opts{ - Name: "Cookie", - Value: opt.String(), - }) + ret.Cookie = append(ret.Cookie, opt.String()) + case *dns.EDNS0_EXPIRE: - ret = append(ret, Opts{ - Name: "Expire", - Value: opt.String(), - }) + ret.Expire = opt.Expire + case *dns.EDNS0_TCP_KEEPALIVE: - ret = append(ret, Opts{ - Name: "TCP Keepalive", - Value: opt.String(), - }) - case *dns.EDNS0_UL: - ret = append(ret, Opts{ - Name: "Update Lease", - Value: opt.String(), - }) + ret.KeepAlive = opt.Timeout + case *dns.EDNS0_LLQ: - ret = append(ret, Opts{ - Name: "Long Lived Queries", - Value: opt.String(), - }) + ret.LLQ = &EdnsLLQ{ + Version: opt.Version, + Opcode: opt.Opcode, + Error: opt.Error, + ID: opt.Id, + Lease: opt.LeaseLife, + } + case *dns.EDNS0_DAU: - ret = append(ret, Opts{ - Name: "DNSSEC Algorithm Understood", - Value: opt.String(), - }) + ret.Dau = opt.AlgCode + case *dns.EDNS0_DHU: - ret = append(ret, Opts{ - Name: "DS Hash Understood", - Value: opt.String(), - }) + ret.Dhu = opt.AlgCode + case *dns.EDNS0_N3U: - ret = append(ret, Opts{ - Name: "NSEC3 Hash Understood", - Value: opt.String(), - }) - case *dns.EDNS0_LOCAL: - ret = append(ret, Opts{ - Name: "Local OPT", - Value: opt.String(), - }) + ret.N3u = opt.AlgCode + case *dns.EDNS0_PADDING: - ret = append(ret, Opts{ - Name: "Padding", - Value: opt.String(), - }) + ret.Padding = string(opt.Padding) + case *dns.EDNS0_EDE: - ret = append(ret, Opts{ - Name: "EDE", - Value: opt.String(), - }) - case *dns.EDNS0_ESU: - ret = append(ret, Opts{ - Name: "ESU", - Value: opt.String(), - }) + ret.EDE = &EDNSErr{ + Code: opt.InfoCode, + Purpose: dns.ExtendedErrorCodeToString[opt.InfoCode], + Text: opt.ExtraText, + } } } -- 2.45.2 From 9f517424d0f6cb5b77dd28559e2418f965a3e18b Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Sat, 17 Dec 2022 16:32:01 +0100 Subject: [PATCH 11/13] make ttl an int if it is an int Signed-off-by: Sam Therapy --- pkg/query/util.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/query/util.go b/pkg/query/util.go index 97b52c6..4df5e97 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -3,7 +3,6 @@ package query import ( "encoding/hex" "fmt" - "strconv" "strings" "time" @@ -52,7 +51,7 @@ func (message *Message) displayAnswers(msg *dns.Msg, opts *util.Options, opt *dn if opts.Display.HumanTTL { ttl = (time.Duration(answer.Header().Ttl) * time.Second).String() } else { - ttl = strconv.Itoa(int(answer.Header().Ttl)) + ttl = answer.Header().Ttl } } @@ -95,7 +94,7 @@ func (message *Message) displayAuthority(msg *dns.Msg, opts *util.Options, opt * if opts.Display.HumanTTL { ttl = (time.Duration(ns.Header().Ttl) * time.Second).String() } else { - ttl = strconv.Itoa(int(ns.Header().Ttl)) + ttl = ns.Header().Ttl } } @@ -141,7 +140,7 @@ func (message *Message) displayAdditional(msg *dns.Msg, opts *util.Options, opt if opts.Display.HumanTTL { ttl = (time.Duration(additional.Header().Ttl) * time.Second).String() } else { - ttl = strconv.Itoa(int(additional.Header().Ttl)) + ttl = additional.Header().Ttl } } -- 2.45.2 From 53f89ab1074c20c1283e4dcffd9aff6f11defb6a Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Tue, 27 Dec 2022 18:07:20 +0100 Subject: [PATCH 12/13] nit: change flag to bit this is in the RFC Signed-off-by: Sam Therapy --- pkg/query/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/query/util.go b/pkg/query/util.go index 4df5e97..10e51fb 100644 --- a/pkg/query/util.go +++ b/pkg/query/util.go @@ -179,7 +179,7 @@ func (message *Message) ParseOpt(rcode int, rr dns.OPT) (ret EDNS0, err error) { for i := uint32(1); i <= 0x7FFF; i <<= 1 { if rr.Hdr.Ttl&i != 0 { - ret.Flags = append(ret.Flags, fmt.Sprintf("FLAG%d", i)) + ret.Flags = append(ret.Flags, fmt.Sprintf("BIT%d", i)) } } -- 2.45.2 From 461718d1f690224e270e439273bc0f132ec81d3e Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Tue, 27 Dec 2022 18:24:40 +0100 Subject: [PATCH 13/13] Force a build -- 2.45.2