feat: Allow opt pseudosection to be printed (#91)
continuous-integration/drone/push Build is passing Details

...when not using the standard print
(JSON/XML/YAML)

This should make making an API for this even easier :)

Reviewed-on: #91
Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
This commit is contained in:
Sam Therapy 2022-09-10 18:41:25 +00:00
parent 4f743f861d
commit 6fa6b2d1f6
10 changed files with 175 additions and 16 deletions

View File

@ -13,6 +13,7 @@ import (
)
// GetDNSConfig gets DNS information from Plan 9, because it's different from UNIX and Windows.
//
// Plan 9 stores its network data in /net/ndb, which seems to be formatted a specific way
// Yoink it and use it.
//

18
conf/wasm.go Normal file
View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build js
package conf
import (
"errors"
"github.com/miekg/dns"
)
// GetDNSConfig doesn't do anything, because it is impossible (and bad security)
// if it could, as that is the definition of a DNS leak.
func GetDNSConfig() (*dns.ClientConfig, error) {
return nil, errNotImplemented
}
var errNotImplemented = errors.New("not implemented")

2
go.mod
View File

@ -22,7 +22,7 @@ require (
github.com/google/go-cmp v0.5.8 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 // indirect
)
require (

2
go.sum
View File

@ -81,6 +81,8 @@ golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=

View File

@ -1,4 +1,5 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build !js
package main

View File

@ -36,10 +36,7 @@ func TestResolve(t *testing.T) {
assert.ErrorContains(t, err, "timeout")
}
// FIXME: See when this is fixed and fix it.
func TestTruncate(t *testing.T) {
t.Skip("Sadly this is broken.")
t.Parallel()
opts := util.Options{

View File

@ -3,6 +3,7 @@
package query
import (
"encoding/hex"
"encoding/json"
"encoding/xml"
"errors"
@ -178,7 +179,7 @@ func MakePrintable(msg *dns.Msg, opts util.Options) (*Message, error) {
name = additional.Header().Name
}
ret.Extra = append(ret.Extra, Answer{
ret.Additional = append(ret.Additional, Answer{
RRHeader: RRHeader{
Name: name,
Type: dns.TypeToString[additional.Header().Rrtype],
@ -191,7 +192,133 @@ func MakePrintable(msg *dns.Msg, opts util.Options) (*Message, error) {
}
}
opt := msg.IsEdns0()
if opt != nil && opts.Display.Opt {
ret.Opt, err = parseOpt(*opt)
if err != nil {
return nil, fmt.Errorf("edns print: %w", err)
}
}
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(),
})
}
}
return ret, nil
}
var errInvalidFormat = errors.New("this should never happen")

View File

@ -37,12 +37,16 @@ func TestCreateQ(t *testing.T) {
Statistics: true,
},
EDNS: util.EDNS{
ZFlag: 1,
BufSize: 1500,
EnableEDNS: true,
DNSSEC: true,
Cookie: true,
DNSSEC: true,
Expire: true,
KeepOpen: true,
Nsid: true,
Padding: true,
Version: 0,
},
},
{

View File

@ -15,30 +15,39 @@ import (
)
// Message is for overall DNS responses.
//
//nolint:govet // Better output is worth 32 bytes.
type Message struct {
Question []Question `json:"question,omitempty" xml:"question,omitempty" yaml:",omitempty"`
Answer []Answer `json:"answer,omitempty" xml:"answer,omitempty" yaml:",omitempty"`
Ns []Answer `json:"ns,omitempty" xml:"ns,omitempty" yaml:",omitempty"`
Extra []Answer `json:"extra,omitempty" xml:"extra,omitempty" yaml:",omitempty"`
Header dns.MsgHdr `json:"header,omitempty" xml:"header,omitempty" yaml:",omitempty"`
Header dns.MsgHdr `json:"header,omitempty" xml:"header,omitempty" yaml:",omitempty"`
Opt []Opts `json:"opt,omitempty" xml:"opt,omitempty" yaml:"opt,omitempty"`
Question []Question `json:"question,omitempty" xml:"question,omitempty" yaml:",omitempty"`
Answer []Answer `json:"answer,omitempty" xml:"answer,omitempty" yaml:",omitempty"`
Ns []Answer `json:"ns,omitempty" xml:"ns,omitempty" yaml:",omitempty"`
Additional []Answer `json:"additional,omitempty" xml:"additional,omitempty" yaml:",omitempty"`
}
// Question is a DNS Query.
type Question struct {
Name string `json:"name,omitempty" xml:"name,omitempty" yaml:",omitempty"`
Type string `json:"type,omitempty" xml:"type,omitempty" yaml:",omitempty"`
Class string `json:"class,omitempty" xml:"class,omitempty" yaml:",omitempty"`
Type string `json:"type,omitempty" xml:"type,omitempty" yaml:",omitempty"`
}
// RRHeader is for DNS Resource Headers.
type RRHeader struct {
Name string `json:"name,omitempty" xml:"name,omitempty" yaml:",omitempty"`
Type string `json:"type,omitempty" xml:"type,omitempty" yaml:",omitempty"`
Class string `json:"class,omitempty" xml:"class,omitempty" yaml:",omitempty"`
TTL string `json:"ttl,omitempty" xml:"ttl,omitempty" yaml:",omitempty"`
Class string `json:"class,omitempty" xml:"class,omitempty" yaml:",omitempty"`
Type string `json:"type,omitempty" xml:"type,omitempty" yaml:",omitempty"`
Rdlength uint16 `json:"-" xml:"-" yaml:"-"`
}
// Opts is for the OPT pseudosection, nearly exclusively for EDNS.
type Opts struct {
Name string `json:"name,omitempty" xml:"name,omitempty" yaml:",omitempty"`
Value string `json:"value" xml:"value" yaml:""`
}
// Answer is for a DNS Response.
type Answer struct {
Value string `json:"response,omitempty" xml:"response,omitempty" yaml:"response,omitempty"`
@ -212,7 +221,7 @@ func stringParse(str string, isAns bool, opts util.Options) (string, error) {
}
}
if opts.HumanTTL {
if opts.ShowTTL && opts.HumanTTL {
ttl, _ := strconv.Atoi(split[1])
split[1] = (time.Duration(ttl) * time.Second).String()
}

View File

@ -10,7 +10,7 @@ import (
"github.com/miekg/dns"
)
// Options is the grand CLI options structure.
// Options is the grand structure for all query options.
type Options struct {
Logger *logawl.Logger
TLSHost string