From 33cb3e457263524ec113160211ad198065e08b21 Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Fri, 16 Sep 2022 14:13:10 +0200 Subject: [PATCH] fix: EDNS cookies work properly Signed-off-by: Sam Therapy --- .goreleaser.yaml | 13 +++++++++++++ GNUmakefile | 7 +++++++ Makefile | 6 ++++++ cli/cli.go | 4 +++- cli/dig.go | 2 ++ cli/dig_test.go | 1 + cli/misc.go | 8 +++++++- cli/misc_test.go | 6 ++++++ completions/zsh.zsh | 1 + doc/awl.1.scd | 3 +++ logawl/docs.go | 2 +- query/general.go | 20 +++++++++++++++++++- query/general_test.go | 2 +- query/query.go | 2 +- template.mk | 6 ------ util/options.go | 2 ++ 16 files changed, 73 insertions(+), 12 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index ff26ef9..da446bc 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -13,9 +13,22 @@ builds: - linux - windows - darwin + - freebsd goarch: - amd64 + - arm - arm64 + ignore: + # Windows on ARM, maybe someday + - goos: windows + goarch: arm64 + - goos: windows + goarch: arm + + - goos: darwin + goarch: arm + - goos: freebsd + goarch: arm universal_binaries: - replace: true diff --git a/GNUmakefile b/GNUmakefile index 5e7fab3..66aacd1 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -9,6 +9,13 @@ else EXE := $(PROG) endif +doc/$(PROG).1: doc/$(PROG).1.scd + $(SCDOC) <$< >$@ + +doc/wiki/$(PROG).1.md: doc/$(PROG).1 + pandoc --from man --to gfm -o $@ $< + + ## install: installs awl .PHONY: install ifeq ($(OS),Windows_NT) diff --git a/Makefile b/Makefile index d8d8c68..b5483dd 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,12 @@ include template.mk EXE := $(PROG) +doc/$(PROG).1: doc/$(PROG).1.scd + $(SCDOC) $@ + +doc/wiki/$(PROG).1.md: doc/$(PROG).1 + pandoc --from man --to gfm -o $@ doc/$(PROG).1 + ## install: installs awl .PHONY: install install: all diff --git a/cli/cli.go b/cli/cli.go index f002afe..e093ece 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -62,7 +62,8 @@ func ParseCLI(args []string, version string) (util.Options, error) { subnet = flag.String("subnet", "", "set EDNS client subnet") padding = flag.Bool("pad", false, "set EDNS padding") - truncate = flag.Bool("no-truncate", false, "ignore truncation if a UDP request truncates (default: retry with TCP)") + badCookie = flag.Bool("no-bad-cookie", false, "ignore BADCOOKIE EDNS responses (default: retry with correct cookie") + truncate = flag.Bool("no-truncate", false, "ignore truncation if a UDP request truncates (default: retry with TCP)") tcp = flag.Bool("tcp", false, "use TCP") dnscrypt = flag.Bool("dnscrypt", false, "use DNSCrypt") @@ -126,6 +127,7 @@ func ParseCLI(args []string, version string) (util.Options, error) { HTTPS: *https, QUIC: *quic, Truncate: *truncate, + BadCookie: *badCookie, Reverse: *reverse, JSON: *json, XML: *xml, diff --git a/cli/dig.go b/cli/dig.go index 00ee8a6..5ac8477 100644 --- a/cli/dig.go +++ b/cli/dig.go @@ -73,6 +73,8 @@ func ParseDig(arg string, opts *util.Options) error { opts.TCP = isNo case "ignore": opts.Truncate = isNo + case "badcookie": + opts.BadCookie = !isNo case "tls": opts.TLS = isNo case "dnscrypt": diff --git a/cli/dig_test.go b/cli/dig_test.go index 5293bb2..572872e 100644 --- a/cli/dig_test.go +++ b/cli/dig_test.go @@ -40,6 +40,7 @@ func FuzzDig(f *testing.F) { "tries=2", "tries=b", "tries", "tcp", "vc", "notcp", "novc", "ignore", "noignore", + "badcookie", "nobadcookie", "tls", "notls", "dnscrypt", "nodnscrypt", "https", "nohttps", diff --git a/cli/misc.go b/cli/misc.go index 85228fd..97fec36 100644 --- a/cli/misc.go +++ b/cli/misc.go @@ -43,6 +43,12 @@ func ParseMiscArgs(args []string, opts *util.Options) error { opts.DNSCrypt = true opts.Request.Server = arg opts.Logger.Info("DNSCrypt implicitly set") + case strings.HasPrefix(arg, "tcp://"): + opts.DNSCrypt = true + opts.Request.Server = arg + opts.Logger.Info("TCP implicitly set") + case strings.HasPrefix(arg, "udp://"): + opts.Request.Server = strings.TrimPrefix(opts.Request.Server, "udp://") default: opts.Request.Server = arg } @@ -117,7 +123,7 @@ func ParseMiscArgs(args []string, opts *util.Options) error { if err != nil { // :^) - opts.Logger.Warn("Could not query system for server. Using localhost") + opts.Logger.Warn("Could not query system for server. Using localhost\n", "Error:", err) opts.Request.Server = "127.0.0.1" } else { // Make sure that if IPv4 or IPv6 is asked for it actually uses it diff --git a/cli/misc_test.go b/cli/misc_test.go index 286e0e3..c3f60c3 100644 --- a/cli/misc_test.go +++ b/cli/misc_test.go @@ -127,6 +127,8 @@ func TestFlagSetting(t *testing.T) { {[]string{"@tls://dns.google"}}, {[]string{"@https://dns.cloudflare.com/dns-query"}}, {[]string{"@quic://dns.adguard.com"}}, + {[]string{"@tcp://dns.froth.zone"}}, + {[]string{"@udp://dns.example.com"}}, } for i, test := range tests { @@ -147,6 +149,10 @@ func TestFlagSetting(t *testing.T) { assert.Assert(t, opts.HTTPS) case 3: assert.Assert(t, opts.QUIC) + case 4: + assert.Assert(t, opts.TCP) + case 5: + assert.Assert(t, true) } }) } diff --git a/completions/zsh.zsh b/completions/zsh.zsh index 8463dbf..64afd0c 100644 --- a/completions/zsh.zsh +++ b/completions/zsh.zsh @@ -13,6 +13,7 @@ local -a alts args '*+'{no,}'aaonly[set aa flag in the query]' '*+'{no,}'additional[print additional section of a reply]' '*+'{no,}'adflag[set the AD (authentic data) bit in the query]' + '*+'{no,}'badcookie[retry BADCOOKIE responses]' '*+'{no,}'cdflag[set the CD (checking disabled) bit in the query]' '*+'{no,}'cookie[add a COOKIE option to the request]' '*+edns=[specify EDNS version for query]:version (0-255)' diff --git a/doc/awl.1.scd b/doc/awl.1.scd index bc0110a..de88719 100644 --- a/doc/awl.1.scd +++ b/doc/awl.1.scd @@ -80,6 +80,9 @@ Anything in [brackets] is optional. *--no-truncate*, *+ignore* Ignore UDP truncation (by default, awl *retries with TCP*). +*--no-bad-cookie*, *+[no]badcookie* + \[Do not\] ignore BADCOOKIE responses + *--tcp*, *+tcp*, *+vc* Use TCP for the query (see RFC 7766). diff --git a/logawl/docs.go b/logawl/docs.go index fa0d5f9..d9940e3 100644 --- a/logawl/docs.go +++ b/logawl/docs.go @@ -14,7 +14,7 @@ because awl is a cli utility it writes directly to std err. // You can call specific logging levels from your new logger using // // logger.Debug("Message to log") -// logger.Fatal("Message to log") +// logger.Warning("Message to log") // logger.Info("Message to log") // logger.Error("Message to log") // diff --git a/query/general.go b/query/general.go index 8e0973b..6f4c6fa 100644 --- a/query/general.go +++ b/query/general.go @@ -52,13 +52,31 @@ func (r *StandardResolver) LookUp(msg *dns.Msg) (util.Response, error) { } } - r.opts.Logger.Debug("Using", dnsClient.Net, "for making the request") + r.opts.Logger.Info("Using", dnsClient.Net, "for making the request") resp.DNS, resp.RTT, err = dnsClient.Exchange(msg, r.opts.Request.Server) if err != nil { return util.Response{}, fmt.Errorf("standard: DNS exchange: %w", err) } + switch dns.RcodeToString[resp.DNS.MsgHdr.Rcode] { + case "BADCOOKIE": + if !r.opts.BadCookie { + fmt.Printf(";; BADCOOKIE, retrying.\n\n") + + msg.Extra = resp.DNS.Extra + + resp.DNS, resp.RTT, err = dnsClient.Exchange(msg, r.opts.Request.Server) + + if err != nil { + return util.Response{}, fmt.Errorf("badcookie: DNS exchange: %w", err) + } + } + + case "NOERR": + break + } + r.opts.Logger.Info("Request successful") if resp.DNS.MsgHdr.Truncated && !r.opts.Truncate { diff --git a/query/general_test.go b/query/general_test.go index fe06c12..396e87b 100644 --- a/query/general_test.go +++ b/query/general_test.go @@ -19,7 +19,7 @@ func TestResolve(t *testing.T) { Logger: util.InitLogger(0), Request: util.Request{ Server: "8.8.4.1", - Port: 53, + Port: 1, Type: dns.TypeA, Name: "example.com.", Timeout: time.Second / 2, diff --git a/query/query.go b/query/query.go index 6bccb34..45d680e 100644 --- a/query/query.go +++ b/query/query.go @@ -44,7 +44,7 @@ func CreateQuery(opts util.Options) (util.Response, error) { if opts.EDNS.Cookie { e := new(dns.EDNS0_COOKIE) e.Code = dns.EDNS0COOKIE - e.Cookie = uniuri.NewLenChars(8, []byte("1234567890abcdef")) + e.Cookie = uniuri.NewLenChars(16, []byte("1234567890abcdef")) o.Option = append(o.Option, e) opts.Logger.Info("Setting EDNS cookie to", e.Cookie) diff --git a/template.mk b/template.mk index 0223929..41e441e 100644 --- a/template.mk +++ b/template.mk @@ -28,12 +28,6 @@ all: $(PROG) doc/$(PROG).1 $(PROG): $(SOURCES) $(GO) build -o $(EXE) $(GOFLAGS) . -doc/$(PROG).1: doc/$(PROG).1.scd - $(SCDOC) <$< >$@ - -doc/wiki/$(PROG).1.md: doc/$(PROG).1 - pandoc --from man --to gfm -o $@ $< - ## update_doc: update documentation (requires pandoc) update_doc: doc/wiki/$(PROG).1.md diff --git a/util/options.go b/util/options.go index c406801..1abd2f4 100644 --- a/util/options.go +++ b/util/options.go @@ -27,6 +27,8 @@ type Options struct { Display Display // Ignore Truncation Truncate bool `json:"ignoreTruncate" example:"false"` + // Ignore BADCOOKIE + BadCookie bool `json:"ignoreBadCookie" example:"false"` // Print only the answer Short bool `json:"short" example:"false"` // When Short is true, display where the query came from