fix: EDNS cookies work properly #98

Merged
sam merged 3 commits from fix-edns-cookies into master 2022-09-16 23:26:10 +00:00
17 changed files with 93 additions and 32 deletions

View file

@ -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

View file

@ -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)

View file

@ -5,6 +5,12 @@ include template.mk
EXE := $(PROG)
doc/$(PROG).1: doc/$(PROG).1.scd
$(SCDOC) <doc/$(PROG).1.scd >$@
doc/wiki/$(PROG).1.md: doc/$(PROG).1
pandoc --from man --to gfm -o $@ doc/$(PROG).1
## install: installs awl
.PHONY: install
install: all

View file

@ -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,

View file

@ -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":

View file

@ -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",

View file

@ -29,7 +29,7 @@ func ParseMiscArgs(args []string, opts *util.Options) error {
switch {
case strings.HasPrefix(arg, "tls://"):
opts.TLS = true
opts.Request.Server = strings.TrimPrefix(opts.Request.Server, "tls://")
opts.Request.Server = strings.TrimPrefix(arg, "tls://")
opts.Logger.Info("DNS-over-TLS implicitly set")
case strings.HasPrefix(arg, "https://"):
opts.HTTPS = true
@ -37,12 +37,18 @@ func ParseMiscArgs(args []string, opts *util.Options) error {
opts.Logger.Info("DNS-over-HTTPS implicitly set")
case strings.HasPrefix(arg, "quic://"):
opts.QUIC = true
opts.Request.Server = strings.TrimPrefix(opts.Request.Server, "quic://")
opts.Request.Server = strings.TrimPrefix(arg, "quic://")
opts.Logger.Info("DNS-over-QUIC implicitly set.")
case strings.HasPrefix(arg, "sdns://"):
opts.DNSCrypt = true
opts.Request.Server = arg
opts.Logger.Info("DNSCrypt implicitly set")
case strings.HasPrefix(arg, "tcp://"):
opts.TCP = true
opts.Request.Server = strings.TrimPrefix(arg, "udp://")
opts.Logger.Info("TCP implicitly set")
case strings.HasPrefix(arg, "udp://"):
opts.Request.Server = strings.TrimPrefix(arg, "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

View file

@ -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)
}
})
}

View file

@ -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)'

View file

@ -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).

@ -1 +1 @@
Subproject commit 6f3070f5933d0cc48bc8bb5290a1d0cc1825cd75
Subproject commit d41f6197e638d7f0c0b203bd8b7f1fa0fc4b7f97

View file

@ -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")
//

View file

@ -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 {

View file

@ -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,

View file

@ -35,64 +35,64 @@ func CreateQuery(opts util.Options) (util.Response, error) {
// EDNS time :)
if opts.EDNS.EnableEDNS {
o := new(dns.OPT)
o.Hdr.Name = "."
o.Hdr.Rrtype = dns.TypeOPT
edns := new(dns.OPT)
edns.Hdr.Name = "."
edns.Hdr.Rrtype = dns.TypeOPT
o.SetVersion(opts.EDNS.Version)
edns.SetVersion(opts.EDNS.Version)
if opts.EDNS.Cookie {
e := new(dns.EDNS0_COOKIE)
e.Code = dns.EDNS0COOKIE
e.Cookie = uniuri.NewLenChars(8, []byte("1234567890abcdef"))
o.Option = append(o.Option, e)
cookie := new(dns.EDNS0_COOKIE)
cookie.Code = dns.EDNS0COOKIE
cookie.Cookie = uniuri.NewLenChars(16, []byte("1234567890abcdef"))
edns.Option = append(edns.Option, cookie)
opts.Logger.Info("Setting EDNS cookie to", e.Cookie)
opts.Logger.Info("Setting EDNS cookie to", cookie.Cookie)
}
if opts.EDNS.Expire {
o.Option = append(o.Option, new(dns.EDNS0_EXPIRE))
edns.Option = append(edns.Option, new(dns.EDNS0_EXPIRE))
opts.Logger.Info("Setting EDNS Expire option")
}
if opts.EDNS.KeepOpen {
o.Option = append(o.Option, new(dns.EDNS0_TCP_KEEPALIVE))
edns.Option = append(edns.Option, new(dns.EDNS0_TCP_KEEPALIVE))
opts.Logger.Info("Setting EDNS TCP Keepalive option")
}
if opts.EDNS.Nsid {
o.Option = append(o.Option, new(dns.EDNS0_NSID))
edns.Option = append(edns.Option, new(dns.EDNS0_NSID))
opts.Logger.Info("Setting EDNS NSID option")
}
if opts.EDNS.Padding {
o.Option = append(o.Option, new(dns.EDNS0_PADDING))
edns.Option = append(edns.Option, new(dns.EDNS0_PADDING))
opts.Logger.Info("Setting EDNS padding")
}
o.SetUDPSize(opts.EDNS.BufSize)
edns.SetUDPSize(opts.EDNS.BufSize)
opts.Logger.Info("EDNS UDP buffer set to", opts.EDNS.BufSize)
o.SetZ(opts.EDNS.ZFlag)
edns.SetZ(opts.EDNS.ZFlag)
opts.Logger.Info("EDNS Z flag set to", opts.EDNS.ZFlag)
if opts.EDNS.DNSSEC {
o.SetDo()
edns.SetDo()
opts.Logger.Info("EDNS DNSSEC OK set")
}
if opts.EDNS.Subnet.Address != nil {
o.Option = append(o.Option, &opts.EDNS.Subnet)
edns.Option = append(edns.Option, &opts.EDNS.Subnet)
}
req.Extra = append(req.Extra, o)
req.Extra = append(req.Extra, edns)
} else if opts.EDNS.DNSSEC {
req.SetEdns0(1232, true)
opts.Logger.Warn("DNSSEC implies EDNS, EDNS enabled")

View file

@ -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

View file

@ -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