This commit is contained in:
commit
faa8ac55f2
28 changed files with 570 additions and 481 deletions
150
.drone.jsonnet
150
.drone.jsonnet
|
@ -1,102 +1,144 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
local testing(version, arch) = {
|
||||
kind: "pipeline",
|
||||
type: "docker",
|
||||
name: version + "-" + arch ,
|
||||
kind: 'pipeline',
|
||||
type: 'docker',
|
||||
name: version + '-' + arch,
|
||||
platform: {
|
||||
arch: arch
|
||||
arch: arch,
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
name: "compile",
|
||||
image: "golang:" + version,
|
||||
name: 'lint',
|
||||
image: 'rancher/drone-golangci-lint:latest',
|
||||
},
|
||||
{
|
||||
name: 'cache',
|
||||
image: 'golang:' + version,
|
||||
commands: [
|
||||
"make awl"
|
||||
'go mod tidy'
|
||||
],
|
||||
depends_on: [
|
||||
'lint',
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'cache',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "lint",
|
||||
image: "rancher/drone-golangci-lint:latest",
|
||||
name: 'test',
|
||||
image: 'golang:' + version,
|
||||
commands: [
|
||||
'make test-ci',
|
||||
],
|
||||
depends_on: [
|
||||
"compile",
|
||||
'cache',
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'cache',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "test",
|
||||
image: "golang:" + version,
|
||||
name: 'fuzz',
|
||||
image: 'golang:' + version,
|
||||
commands: [
|
||||
"make test-ci"
|
||||
'make fuzz-ci',
|
||||
],
|
||||
depends_on: [
|
||||
"lint",
|
||||
'cache',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "fuzz",
|
||||
image: "golang:" + version,
|
||||
commands: [
|
||||
"make fuzz-ci",
|
||||
],
|
||||
depends_on: [
|
||||
"lint",
|
||||
volumes: [
|
||||
{
|
||||
name: 'cache',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
trigger: {
|
||||
event: {
|
||||
exclude: [
|
||||
"tag"
|
||||
'tag',
|
||||
],
|
||||
}
|
||||
},
|
||||
},
|
||||
volumes: [
|
||||
{
|
||||
name: 'cache',
|
||||
temp: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// "Inspired by" https://goreleaser.com/ci/drone/
|
||||
local release() = {
|
||||
kind: "pipeline",
|
||||
type: "docker",
|
||||
name: "release",
|
||||
kind: 'pipeline',
|
||||
type: 'docker',
|
||||
name: 'release',
|
||||
trigger: {
|
||||
event: [
|
||||
"tag"
|
||||
'tag',
|
||||
],
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
name: "fetch",
|
||||
image: "alpine/git",
|
||||
commands : [
|
||||
"git fetch --tags",
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "test",
|
||||
image: "golang",
|
||||
name: 'fetch',
|
||||
image: 'alpine/git',
|
||||
commands: [
|
||||
"make test"
|
||||
]
|
||||
'git fetch --tags',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "release",
|
||||
image: "goreleaser/goreleaser",
|
||||
name: 'test',
|
||||
image: 'golang',
|
||||
commands: [
|
||||
'make test-ci',
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'cache',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'release',
|
||||
image: 'goreleaser/goreleaser',
|
||||
environment: {
|
||||
"GITEA_TOKEN": {
|
||||
from_secret: "GITEA_TOKEN"
|
||||
}
|
||||
GITEA_TOKEN: {
|
||||
from_secret: 'GITEA_TOKEN',
|
||||
},
|
||||
},
|
||||
commands: [
|
||||
"goreleaser release"
|
||||
'goreleaser release',
|
||||
],
|
||||
}
|
||||
]
|
||||
volumes: [
|
||||
{
|
||||
name: 'cache',
|
||||
path: '/go',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: 'cache',
|
||||
temp: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
[
|
||||
testing("1.19", "amd64"),
|
||||
testing("1.19", "arm64"),
|
||||
testing("1.18", "amd64"),
|
||||
testing("1.18", "arm64"),
|
||||
testing('1.19', 'amd64'),
|
||||
testing('1.19', 'arm64'),
|
||||
testing('1.18', 'amd64'),
|
||||
testing('1.18', 'arm64'),
|
||||
|
||||
release()
|
||||
]
|
||||
release(),
|
||||
]
|
||||
|
|
|
@ -32,6 +32,7 @@ linters:
|
|||
- predeclared
|
||||
- revive
|
||||
- staticcheck
|
||||
- tagliatelle
|
||||
- whitespace
|
||||
- wrapcheck
|
||||
- wsl
|
||||
|
@ -70,6 +71,16 @@ linters-settings:
|
|||
- name: unexported-return
|
||||
- name: var-declaration
|
||||
- name: var-naming
|
||||
linters-settings:
|
||||
tagliatelle:
|
||||
case:
|
||||
use-field-name: false
|
||||
rules:
|
||||
# Any struct tag type can be used.
|
||||
# Support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`
|
||||
json: goCamel
|
||||
yaml: goCamel
|
||||
xml: goCamel
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
6
Makefile
6
Makefile
|
@ -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
|
||||
|
|
11
cli/cli.go
11
cli/cli.go
|
@ -5,7 +5,6 @@ package cli
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -18,8 +17,8 @@ import (
|
|||
|
||||
// ParseCLI parses arguments given from the CLI and passes them into an `Options`
|
||||
// struct.
|
||||
func ParseCLI(version string) (util.Options, error) {
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
|
||||
func ParseCLI(args []string, version string) (util.Options, error) {
|
||||
flag.CommandLine = flag.NewFlagSet(args[0], flag.ContinueOnError)
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Println(`awl - drill, writ small
|
||||
|
@ -63,7 +62,8 @@ func ParseCLI(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")
|
||||
|
@ -104,7 +104,7 @@ func ParseCLI(version string) (util.Options, error) {
|
|||
flag.CommandLine.SortFlags = false
|
||||
|
||||
// Parse the flags
|
||||
if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
|
||||
if err := flag.CommandLine.Parse(args[1:]); err != nil {
|
||||
return util.Options{Logger: util.InitLogger(*verbosity)}, fmt.Errorf("flag: %w", err)
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,7 @@ func ParseCLI(version string) (util.Options, error) {
|
|||
HTTPS: *https,
|
||||
QUIC: *quic,
|
||||
Truncate: *truncate,
|
||||
BadCookie: *badCookie,
|
||||
Reverse: *reverse,
|
||||
JSON: *json,
|
||||
XML: *xml,
|
||||
|
|
110
cli/cli_test.go
110
cli/cli_test.go
|
@ -12,23 +12,19 @@ import (
|
|||
)
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
args := os.Args
|
||||
os.Args = []string{"awl", "-4"}
|
||||
args := []string{"awl", "-4"}
|
||||
|
||||
opts, err := cli.ParseCLI("TEST")
|
||||
opts, err := cli.ParseCLI(args, "TEST")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, opts.Request.Port, 53)
|
||||
assert.Assert(t, opts.IPv4)
|
||||
|
||||
os.Args = args
|
||||
}
|
||||
|
||||
func TestTLSPort(t *testing.T) {
|
||||
args := os.Args
|
||||
os.Args = []string{"awl", "-T"}
|
||||
args := []string{"awl", "-T"}
|
||||
|
||||
opts, err := cli.ParseCLI("TEST")
|
||||
opts, err := cli.ParseCLI(args, "TEST")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, opts.Request.Port, 853)
|
||||
|
@ -37,131 +33,91 @@ func TestTLSPort(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSubnet(t *testing.T) {
|
||||
args := os.Args
|
||||
os.Args = []string{"awl", "--subnet", "127.0.0.1/32"}
|
||||
args := []string{"awl", "--subnet", "127.0.0.1/32"}
|
||||
|
||||
opts, err := cli.ParseCLI("TEST")
|
||||
opts, err := cli.ParseCLI(args, "TEST")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, opts.EDNS.Subnet.Family, uint16(1))
|
||||
|
||||
os.Args = args
|
||||
args = []string{"awl", "--subnet", "0"}
|
||||
|
||||
os.Args = []string{"awl", "--subnet", "0"}
|
||||
|
||||
opts, err = cli.ParseCLI("TEST")
|
||||
opts, err = cli.ParseCLI(args, "TEST")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, opts.EDNS.Subnet.Family, uint16(1))
|
||||
|
||||
os.Args = args
|
||||
args = []string{"awl", "--subnet", "::/0"}
|
||||
|
||||
os.Args = []string{"awl", "--subnet", "::/0"}
|
||||
|
||||
opts, err = cli.ParseCLI("TEST")
|
||||
opts, err = cli.ParseCLI(args, "TEST")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, opts.EDNS.Subnet.Family, uint16(2))
|
||||
|
||||
os.Args = args
|
||||
args = []string{"awl", "--subnet", "/"}
|
||||
|
||||
os.Args = []string{"awl", "--subnet", "/"}
|
||||
|
||||
opts, err = cli.ParseCLI("TEST")
|
||||
opts, err = cli.ParseCLI(args, "TEST")
|
||||
assert.ErrorContains(t, err, "EDNS subnet")
|
||||
|
||||
os.Args = args
|
||||
}
|
||||
|
||||
func TestMBZ(t *testing.T) { //nolint: paralleltest // Race conditions
|
||||
args := os.Args
|
||||
os.Args = []string{"awl", "--zflag", "G"}
|
||||
func TestMBZ(t *testing.T) {
|
||||
args := []string{"awl", "--zflag", "G"}
|
||||
|
||||
_, err := cli.ParseCLI("TEST")
|
||||
_, err := cli.ParseCLI(args, "TEST")
|
||||
|
||||
assert.ErrorContains(t, err, "EDNS MBZ")
|
||||
|
||||
os.Args = args
|
||||
}
|
||||
|
||||
func TestInvalidFlag(t *testing.T) { //nolint: paralleltest // Race conditions
|
||||
args := os.Args
|
||||
stdout := os.Stdout
|
||||
stderr := os.Stderr
|
||||
func TestInvalidFlag(t *testing.T) {
|
||||
args := []string{"awl", "--treebug"}
|
||||
|
||||
os.Stdout = os.NewFile(0, os.DevNull)
|
||||
os.Stderr = os.NewFile(0, os.DevNull)
|
||||
|
||||
os.Args = []string{"awl", "--treebug"}
|
||||
|
||||
_, err := cli.ParseCLI("TEST")
|
||||
_, err := cli.ParseCLI(args, "TEST")
|
||||
|
||||
assert.ErrorContains(t, err, "unknown flag")
|
||||
|
||||
os.Args = args
|
||||
os.Stdout = stdout
|
||||
os.Stderr = stderr
|
||||
}
|
||||
|
||||
func TestInvalidDig(t *testing.T) { //nolint: paralleltest // Race conditions
|
||||
args := os.Args
|
||||
os.Args = []string{"awl", "+a"}
|
||||
func TestInvalidDig(t *testing.T) {
|
||||
args := []string{"awl", "+a"}
|
||||
|
||||
_, err := cli.ParseCLI("TEST")
|
||||
_, err := cli.ParseCLI(args, "TEST")
|
||||
|
||||
assert.ErrorContains(t, err, "digflags: invalid argument")
|
||||
|
||||
os.Args = args
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) { //nolint: paralleltest // Race conditions
|
||||
args := os.Args
|
||||
stdout := os.Stdout
|
||||
stderr := os.Stderr
|
||||
func TestVersion(t *testing.T) {
|
||||
args := []string{"awl", "--version"}
|
||||
|
||||
os.Args = []string{"awl", "--version"}
|
||||
|
||||
_, err := cli.ParseCLI("test")
|
||||
_, err := cli.ParseCLI(args, "test")
|
||||
|
||||
assert.ErrorType(t, err, cli.ErrNotError)
|
||||
|
||||
os.Args = args
|
||||
os.Stdout = stdout
|
||||
os.Stderr = stderr
|
||||
}
|
||||
|
||||
func TestTimeout(t *testing.T) { //nolint: paralleltest // Race conditions
|
||||
func TestTimeout(t *testing.T) {
|
||||
args := [][]string{
|
||||
{"awl", "+timeout=0"},
|
||||
{"awl", "--timeout", "0"},
|
||||
}
|
||||
for _, test := range args {
|
||||
args := os.Args
|
||||
os.Args = test
|
||||
test := test
|
||||
|
||||
opt, err := cli.ParseCLI("TEST")
|
||||
opt, err := cli.ParseCLI(test, "TEST")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, opt.Request.Timeout, time.Second/2)
|
||||
|
||||
os.Args = args
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetries(t *testing.T) { //nolint: paralleltest // Race conditions
|
||||
func TestRetries(t *testing.T) {
|
||||
args := [][]string{
|
||||
{"awl", "+retry=-2"},
|
||||
{"awl", "+tries=-2"},
|
||||
{"awl", "--retries", "-2"},
|
||||
}
|
||||
for _, test := range args {
|
||||
args := os.Args
|
||||
os.Args = test
|
||||
test := test
|
||||
|
||||
opt, err := cli.ParseCLI("TEST")
|
||||
opt, err := cli.ParseCLI(test, "TEST")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, opt.Request.Retries, 0)
|
||||
|
||||
os.Args = args
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,10 +131,8 @@ func FuzzFlags(f *testing.F) {
|
|||
f.Fuzz(func(t *testing.T, orig string) {
|
||||
// Get rid of outputs
|
||||
|
||||
args := os.Args
|
||||
os.Args = []string{"awl", orig}
|
||||
args := []string{"awl", orig}
|
||||
//nolint:errcheck,gosec // Only make sure the program does not crash
|
||||
cli.ParseCLI("TEST")
|
||||
os.Args = args
|
||||
cli.ParseCLI(args, "TEST")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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",
|
||||
|
|
12
cli/misc.go
12
cli/misc.go
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)'
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
|
10
go.mod
10
go.mod
|
@ -9,7 +9,7 @@ require (
|
|||
github.com/miekg/dns v1.1.50
|
||||
github.com/stefansundin/go-zflag v1.1.1
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gotest.tools/v3 v3.3.0
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ require (
|
|||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
|
||||
github.com/ameshkov/dnsstamps v1.0.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
|
@ -27,9 +27,9 @@ require (
|
|||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
|
||||
golang.org/x/exp v0.0.0-20220914170420-dc92f8653013 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
|
|
20
go.sum
20
go.sum
|
@ -15,8 +15,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 h1:RAV05c0xOkJ3dZGS0JFybxFKZ2WMLabgx3uXnd7rpGs=
|
||||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
|
@ -56,8 +57,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
|||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
||||
|
@ -76,10 +77,10 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20220914170420-dc92f8653013 h1:ZjglnWxEUdPyXl4o/j4T89SRCI+4X6NW6185PNLEOF4=
|
||||
golang.org/x/exp v0.0.0-20220914170420-dc92f8653013/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=
|
||||
|
@ -113,8 +114,9 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
|
8
main.go
8
main.go
|
@ -17,7 +17,7 @@ import (
|
|||
var version = "DEV"
|
||||
|
||||
func main() {
|
||||
if opts, code, err := run(); err != nil {
|
||||
if opts, code, err := run(os.Args); err != nil {
|
||||
// TODO: Make not ew
|
||||
if errors.Is(err, cli.ErrNotError) || strings.Contains(err.Error(), "help requested") {
|
||||
os.Exit(0)
|
||||
|
@ -28,8 +28,8 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
func run() (opts util.Options, code int, err error) {
|
||||
opts, err = cli.ParseCLI(version)
|
||||
func run(args []string) (opts util.Options, code int, err error) {
|
||||
opts, err = cli.ParseCLI(args, version)
|
||||
if err != nil {
|
||||
return opts, 1, fmt.Errorf("parse: %w", err)
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ func run() (opts util.Options, code int, err error) {
|
|||
|
||||
var str string
|
||||
if opts.JSON || opts.XML || opts.YAML {
|
||||
str, err = query.PrintSpecial(resp.DNS, opts)
|
||||
str, err = query.PrintSpecial(resp, opts)
|
||||
if err != nil {
|
||||
return opts, 10, fmt.Errorf("format print: %w", err)
|
||||
}
|
||||
|
|
22
main_test.go
22
main_test.go
|
@ -14,33 +14,23 @@ func TestMain(t *testing.T) { //nolint: paralleltest // Race conditions
|
|||
os.Stdout = os.NewFile(0, os.DevNull)
|
||||
os.Stderr = os.NewFile(0, os.DevNull)
|
||||
|
||||
old := os.Args
|
||||
args := []string{"awl", "+yaml", "@1.1.1.1"}
|
||||
|
||||
os.Args = []string{"awl", "+yaml", "@1.1.1.1"}
|
||||
|
||||
_, code, err := run()
|
||||
_, code, err := run(args)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, code, 0)
|
||||
|
||||
os.Args = []string{"awl", "+short", "@1.1.1.1"}
|
||||
args = []string{"awl", "+short", "@1.1.1.1"}
|
||||
|
||||
_, code, err = run()
|
||||
_, code, err = run(args)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, code, 0)
|
||||
|
||||
os.Args = old
|
||||
}
|
||||
|
||||
func TestHelp(t *testing.T) {
|
||||
old := os.Args
|
||||
os.Stdout = os.NewFile(0, os.DevNull)
|
||||
os.Stderr = os.NewFile(0, os.DevNull)
|
||||
args := []string{"awl", "-h"}
|
||||
|
||||
os.Args = []string{"awl", "-h"}
|
||||
|
||||
_, code, err := run()
|
||||
_, code, err := run(args)
|
||||
assert.ErrorIs(t, err, zflag.ErrHelp)
|
||||
assert.Equal(t, code, 1)
|
||||
|
||||
os.Args = old
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c8686b1e149b6c42db019c77caf36475aafadd03
|
||||
Subproject commit d876d6de34a78298ed041f575662015fb7eccdb5
|
|
@ -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")
|
||||
//
|
||||
|
|
|
@ -18,10 +18,210 @@ import (
|
|||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// ToString turns the response into something that looks a lot like dig
|
||||
//
|
||||
// Much of this is taken from https://github.com/miekg/dns/blob/master/msg.go#L900
|
||||
func ToString(res util.Response, opts util.Options) (string, error) {
|
||||
if res.DNS == nil {
|
||||
return "<nil> MsgHdr", errNoMessage
|
||||
}
|
||||
|
||||
var (
|
||||
s string
|
||||
opt *dns.OPT
|
||||
)
|
||||
|
||||
if !opts.Short {
|
||||
if opts.Display.Comments {
|
||||
s += res.DNS.MsgHdr.String() + " "
|
||||
s += "QUERY: " + strconv.Itoa(len(res.DNS.Question)) + ", "
|
||||
s += "ANSWER: " + strconv.Itoa(len(res.DNS.Answer)) + ", "
|
||||
s += "AUTHORITY: " + strconv.Itoa(len(res.DNS.Ns)) + ", "
|
||||
s += "ADDITIONAL: " + strconv.Itoa(len(res.DNS.Extra)) + "\n"
|
||||
opt = res.DNS.IsEdns0()
|
||||
|
||||
if opt != nil && opts.Display.Opt {
|
||||
// OPT PSEUDOSECTION
|
||||
s += opt.String() + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Question {
|
||||
if len(res.DNS.Question) > 0 {
|
||||
if opts.Display.Comments {
|
||||
s += "\n;; QUESTION SECTION:\n"
|
||||
}
|
||||
|
||||
for _, r := range res.DNS.Question {
|
||||
str, err := stringParse(r.String(), false, opts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
s += str + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Answer {
|
||||
if len(res.DNS.Answer) > 0 {
|
||||
if opts.Display.Comments {
|
||||
s += "\n;; ANSWER SECTION:\n"
|
||||
}
|
||||
|
||||
for _, r := range res.DNS.Answer {
|
||||
if r != nil {
|
||||
str, err := stringParse(r.String(), true, opts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
s += str + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Authority {
|
||||
if len(res.DNS.Ns) > 0 {
|
||||
if opts.Display.Comments {
|
||||
s += "\n;; AUTHORITY SECTION:\n"
|
||||
}
|
||||
|
||||
for _, r := range res.DNS.Ns {
|
||||
if r != nil {
|
||||
str, err := stringParse(r.String(), true, opts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
s += str + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Additional {
|
||||
if len(res.DNS.Extra) > 0 && (opt == nil || len(res.DNS.Extra) > 1) {
|
||||
if opts.Display.Comments {
|
||||
s += "\n;; ADDITIONAL SECTION:\n"
|
||||
}
|
||||
|
||||
for _, r := range res.DNS.Extra {
|
||||
if r != nil && r.Header().Rrtype != dns.TypeOPT {
|
||||
str, err := stringParse(r.String(), true, opts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
s += str + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Statistics {
|
||||
s += "\n;; Query time: " + res.RTT.String()
|
||||
s += "\n;; SERVER: " + opts.Request.Server + serverExtra(opts)
|
||||
s += "\n;; WHEN: " + time.Now().Format(time.RFC1123Z)
|
||||
s += "\n;; MSG SIZE rcvd: " + strconv.Itoa(res.DNS.Len()) + "\n"
|
||||
}
|
||||
} else {
|
||||
// Print just the responses, nothing else
|
||||
for i, resp := range res.DNS.Answer {
|
||||
temp := strings.Split(resp.String(), "\t")
|
||||
s += temp[len(temp)-1]
|
||||
|
||||
if opts.Identify {
|
||||
s += " from server " + opts.Request.Server + " in " + res.RTT.String()
|
||||
}
|
||||
|
||||
// Don't print newline on last line
|
||||
if i != len(res.DNS.Answer)-1 {
|
||||
s += "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func serverExtra(opts util.Options) string {
|
||||
// Add extra information to server string
|
||||
var extra string
|
||||
|
||||
switch {
|
||||
case opts.TCP:
|
||||
extra = ":" + strconv.Itoa(opts.Request.Port) + " (TCP)"
|
||||
case opts.TLS:
|
||||
extra = ":" + strconv.Itoa(opts.Request.Port) + " (TLS)"
|
||||
case opts.HTTPS, opts.DNSCrypt:
|
||||
extra = ""
|
||||
case opts.QUIC:
|
||||
extra = ":" + strconv.Itoa(opts.Request.Port) + " (QUIC)"
|
||||
default:
|
||||
extra = ":" + strconv.Itoa(opts.Request.Port) + " (UDP)"
|
||||
}
|
||||
|
||||
return extra
|
||||
}
|
||||
|
||||
// stringParse edits the raw responses to user requests.
|
||||
func stringParse(str string, isAns bool, opts util.Options) (string, error) {
|
||||
split := strings.Split(str, "\t")
|
||||
|
||||
// Make edits if so requested
|
||||
|
||||
// TODO: make less ew?
|
||||
// This exists because the question section should be left alone EXCEPT for punycode.
|
||||
|
||||
if isAns {
|
||||
if !opts.Display.TTL {
|
||||
// Remove from existence
|
||||
split = append(split[:1], split[2:]...)
|
||||
}
|
||||
|
||||
if !opts.Display.ShowClass {
|
||||
// Position depends on if the TTL is there or not.
|
||||
if opts.Display.TTL {
|
||||
split = append(split[:2], split[3:]...)
|
||||
} else {
|
||||
split = append(split[:1], split[2:]...)
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.TTL && opts.Display.HumanTTL {
|
||||
ttl, _ := strconv.Atoi(split[1])
|
||||
split[1] = (time.Duration(ttl) * time.Second).String()
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.UcodeTranslate {
|
||||
var (
|
||||
err error
|
||||
semi string
|
||||
)
|
||||
|
||||
if strings.HasPrefix(split[0], ";") {
|
||||
split[0] = strings.TrimPrefix(split[0], ";")
|
||||
semi = ";"
|
||||
}
|
||||
|
||||
split[0], err = idna.ToUnicode(split[0])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("punycode: %w", err)
|
||||
}
|
||||
|
||||
split[0] = semi + split[0]
|
||||
}
|
||||
|
||||
return strings.Join(split, "\t"), nil
|
||||
}
|
||||
|
||||
// PrintSpecial is for printing as JSON, XML or YAML.
|
||||
// As of now JSON and XML use the stdlib version.
|
||||
func PrintSpecial(msg *dns.Msg, opts util.Options) (string, error) {
|
||||
formatted, err := MakePrintable(msg, opts)
|
||||
func PrintSpecial(res util.Response, opts util.Options) (string, error) {
|
||||
formatted, err := MakePrintable(res, opts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -52,9 +252,11 @@ func PrintSpecial(msg *dns.Msg, opts util.Options) (string, error) {
|
|||
|
||||
// MakePrintable takes a DNS message and makes it nicer to be printed as JSON,YAML,
|
||||
// and XML. Little is changed beyond naming.
|
||||
func MakePrintable(msg *dns.Msg, opts util.Options) (*Message, error) {
|
||||
var err error
|
||||
|
||||
func MakePrintable(res util.Response, opts util.Options) (*Message, error) {
|
||||
var (
|
||||
err error
|
||||
msg = res.DNS
|
||||
)
|
||||
// The things I do for compatibility
|
||||
ret := Message{
|
||||
Header: Header{
|
||||
|
@ -72,6 +274,14 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
for _, question := range msg.Question {
|
||||
var name string
|
||||
if opts.Display.UcodeTranslate {
|
||||
|
@ -205,12 +415,15 @@ 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)
|
||||
if opts.Display.Statistics {
|
||||
ret.Statistics = Statistics{
|
||||
RTT: res.RTT.String(),
|
||||
Server: opts.Request.Server + serverExtra(opts),
|
||||
When: time.Now().Format(time.RFC1123Z),
|
||||
MsgSize: res.DNS.Len(),
|
||||
}
|
||||
} else {
|
||||
ret.Statistics = Statistics{}
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
|
|
|
@ -193,7 +193,7 @@ func TestRealPrint(t *testing.T) {
|
|||
|
||||
if test.JSON || test.XML || test.YAML {
|
||||
str := ""
|
||||
str, err = query.PrintSpecial(resp.DNS, test)
|
||||
str, err = query.PrintSpecial(resp, test)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, str != "")
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ func TestRealPrint(t *testing.T) {
|
|||
func TestBadFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := query.PrintSpecial(new(dns.Msg), util.Options{})
|
||||
_, err := query.PrintSpecial(util.Response{DNS: new(dns.Msg)}, util.Options{})
|
||||
assert.ErrorContains(t, err, "never happen")
|
||||
}
|
||||
|
||||
|
|
|
@ -5,211 +5,17 @@ package query
|
|||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.froth.zone/sam/awl/pkg/resolvers"
|
||||
"git.froth.zone/sam/awl/pkg/util"
|
||||
"github.com/dchest/uniuri"
|
||||
"github.com/miekg/dns"
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// ToString turns the response into something that looks a lot like dig
|
||||
//
|
||||
// Much of this is taken from https://github.com/miekg/dns/blob/master/msg.go#L900
|
||||
func ToString(res util.Response, opts util.Options) (string, error) {
|
||||
if res.DNS == nil {
|
||||
return "<nil> MsgHdr", errNoMessage
|
||||
}
|
||||
|
||||
var (
|
||||
s string
|
||||
opt *dns.OPT
|
||||
)
|
||||
|
||||
if !opts.Short {
|
||||
if opts.Display.Comments {
|
||||
s += res.DNS.MsgHdr.String() + " "
|
||||
s += "QUERY: " + strconv.Itoa(len(res.DNS.Question)) + ", "
|
||||
s += "ANSWER: " + strconv.Itoa(len(res.DNS.Answer)) + ", "
|
||||
s += "AUTHORITY: " + strconv.Itoa(len(res.DNS.Ns)) + ", "
|
||||
s += "ADDITIONAL: " + strconv.Itoa(len(res.DNS.Extra)) + "\n"
|
||||
opt = res.DNS.IsEdns0()
|
||||
|
||||
if opt != nil && opts.Display.Opt {
|
||||
// OPT PSEUDOSECTION
|
||||
s += opt.String() + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Question {
|
||||
if len(res.DNS.Question) > 0 {
|
||||
if opts.Display.Comments {
|
||||
s += "\n;; QUESTION SECTION:\n"
|
||||
}
|
||||
|
||||
for _, r := range res.DNS.Question {
|
||||
str, err := stringParse(r.String(), false, opts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
s += str + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Answer {
|
||||
if len(res.DNS.Answer) > 0 {
|
||||
if opts.Display.Comments {
|
||||
s += "\n;; ANSWER SECTION:\n"
|
||||
}
|
||||
|
||||
for _, r := range res.DNS.Answer {
|
||||
if r != nil {
|
||||
str, err := stringParse(r.String(), true, opts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
s += str + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Authority {
|
||||
if len(res.DNS.Ns) > 0 {
|
||||
if opts.Display.Comments {
|
||||
s += "\n;; AUTHORITY SECTION:\n"
|
||||
}
|
||||
|
||||
for _, r := range res.DNS.Ns {
|
||||
if r != nil {
|
||||
str, err := stringParse(r.String(), true, opts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
s += str + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Additional {
|
||||
if len(res.DNS.Extra) > 0 && (opt == nil || len(res.DNS.Extra) > 1) {
|
||||
if opts.Display.Comments {
|
||||
s += "\n;; ADDITIONAL SECTION:\n"
|
||||
}
|
||||
|
||||
for _, r := range res.DNS.Extra {
|
||||
if r != nil && r.Header().Rrtype != dns.TypeOPT {
|
||||
str, err := stringParse(r.String(), true, opts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
s += str + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.Statistics {
|
||||
s += "\n;; Query time: " + res.RTT.String()
|
||||
// Add extra information to server string
|
||||
var extra string
|
||||
|
||||
switch {
|
||||
case opts.TCP:
|
||||
extra = ":" + strconv.Itoa(opts.Request.Port) + " (TCP)"
|
||||
case opts.TLS:
|
||||
extra = ":" + strconv.Itoa(opts.Request.Port) + " (TLS)"
|
||||
case opts.HTTPS, opts.DNSCrypt:
|
||||
extra = ""
|
||||
case opts.QUIC:
|
||||
extra = ":" + strconv.Itoa(opts.Request.Port) + " (QUIC)"
|
||||
default:
|
||||
extra = ":" + strconv.Itoa(opts.Request.Port) + " (UDP)"
|
||||
}
|
||||
|
||||
s += "\n;; SERVER: " + opts.Request.Server + extra
|
||||
s += "\n;; WHEN: " + time.Now().Format(time.RFC1123Z)
|
||||
s += "\n;; MSG SIZE rcvd: " + strconv.Itoa(res.DNS.Len()) + "\n"
|
||||
}
|
||||
} else {
|
||||
// Print just the responses, nothing else
|
||||
for i, resp := range res.DNS.Answer {
|
||||
temp := strings.Split(resp.String(), "\t")
|
||||
s += temp[len(temp)-1]
|
||||
|
||||
if opts.Identify {
|
||||
s += " from server " + opts.Request.Server + " in " + res.RTT.String()
|
||||
}
|
||||
|
||||
// Don't print newline on last line
|
||||
if i != len(res.DNS.Answer)-1 {
|
||||
s += "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// stringParse edits the raw responses to user requests.
|
||||
func stringParse(str string, isAns bool, opts util.Options) (string, error) {
|
||||
split := strings.Split(str, "\t")
|
||||
|
||||
// Make edits if so requested
|
||||
|
||||
// TODO: make less ew?
|
||||
// This exists because the question section should be left alone EXCEPT for punycode.
|
||||
|
||||
if isAns {
|
||||
if !opts.Display.TTL {
|
||||
// Remove from existence
|
||||
split = append(split[:1], split[2:]...)
|
||||
}
|
||||
|
||||
if !opts.Display.ShowClass {
|
||||
// Position depends on if the TTL is there or not.
|
||||
if opts.Display.TTL {
|
||||
split = append(split[:2], split[3:]...)
|
||||
} else {
|
||||
split = append(split[:1], split[2:]...)
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.TTL && opts.Display.HumanTTL {
|
||||
ttl, _ := strconv.Atoi(split[1])
|
||||
split[1] = (time.Duration(ttl) * time.Second).String()
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Display.UcodeTranslate {
|
||||
var (
|
||||
err error
|
||||
semi string
|
||||
)
|
||||
|
||||
if strings.HasPrefix(split[0], ";") {
|
||||
split[0] = strings.TrimPrefix(split[0], ";")
|
||||
semi = ";"
|
||||
}
|
||||
|
||||
split[0], err = idna.ToUnicode(split[0])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("punycode: %w", err)
|
||||
}
|
||||
|
||||
split[0] = semi + split[0]
|
||||
}
|
||||
|
||||
return strings.Join(split, "\t"), nil
|
||||
}
|
||||
const (
|
||||
tcp = "tcp"
|
||||
udp = "udp"
|
||||
)
|
||||
|
||||
// CreateQuery creates a DNS query from the options given.
|
||||
// It sets query flags and EDNS flags from the respective options.
|
||||
|
@ -230,64 +36,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")
|
||||
|
@ -306,7 +112,7 @@ func CreateQuery(opts util.Options) (util.Response, error) {
|
|||
)
|
||||
|
||||
if opts.JSON || opts.XML || opts.YAML {
|
||||
str, err = PrintSpecial(req, opts)
|
||||
str, err = PrintSpecial(util.Response{DNS: req}, opts)
|
||||
if err != nil {
|
||||
return util.Response{}, err
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ func TestCreateQ(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
assert.Assert(t, res != util.Response{})
|
||||
|
||||
str, err := query.PrintSpecial(res.DNS, opt)
|
||||
str, err := query.PrintSpecial(res, opt)
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, str != "")
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
//nolint:govet // Better looking output is worth a few bytes.
|
||||
type Message struct {
|
||||
// Header section
|
||||
Header Header `json:"header,omitempty" xml:"header,omitempty" yaml:"header,omitempty"`
|
||||
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
|
||||
|
@ -22,42 +22,44 @@ type Message struct {
|
|||
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"`
|
||||
}
|
||||
|
||||
// Header is the header.
|
||||
type Header struct {
|
||||
Opcode string `json:"opcode," xml:"opcode," yaml:"opcode"`
|
||||
Status string `json:"status," xml:"status," yaml:"status"`
|
||||
ID uint16 `json:"id," xml:"id," yaml:"id"`
|
||||
Response bool `json:"response," xml:"response," yaml:"response"`
|
||||
Authoritative bool `json:"authoritative," xml:"authoritative," yaml:"authoritative"`
|
||||
Truncated bool `json:"truncated," xml:"truncated," yaml:"truncated"`
|
||||
RecursionDesired bool `json:"recursionDesired," xml:"recursionDesired," yaml:"recursionDesired"`
|
||||
RecursionAvailable bool `json:"recursionAvailable," xml:"recursionAvailable," yaml:"recursionAvailable"`
|
||||
Zero bool `json:"zero," xml:"zero," yaml:"zero"`
|
||||
AuthenticatedData bool `json:"authenticatedData," xml:"authenticatedData," yaml:"authenticatedData"`
|
||||
CheckingDisabled bool `json:"checkingDisabled," xml:"checkingDisabled," yaml:"checkingDisabled"`
|
||||
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"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// Question is a DNS Query.
|
||||
type Question struct {
|
||||
Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"`
|
||||
Class string `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty"`
|
||||
Type string `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// RRHeader is for DNS Resource Headers.
|
||||
type RRHeader struct {
|
||||
Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"`
|
||||
TTL string `json:"ttl,omitempty" xml:"ttl,omitempty" yaml:"ttl,omitempty"`
|
||||
Class string `json:"class,omitempty" xml:"class,omitempty" yaml:"class,omitempty"`
|
||||
Type string `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty"`
|
||||
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:"-"`
|
||||
}
|
||||
|
||||
// Opts is for the OPT pseudosection, nearly exclusively for EDNS.
|
||||
type Opts struct {
|
||||
Name string `json:"name,omitempty" xml:"name,omitempty" yaml:",omitempty"`
|
||||
Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"`
|
||||
Value string `json:"value" xml:"value" yaml:"value"`
|
||||
}
|
||||
|
||||
|
@ -67,4 +69,12 @@ type Answer struct {
|
|||
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")
|
||||
|
|
|
@ -52,13 +52,31 @@ func (resolver *StandardResolver) LookUp(msg *dns.Msg) (util.Response, error) {
|
|||
}
|
||||
}
|
||||
|
||||
resolver.opts.Logger.Debug("Using", dnsClient.Net, "for making the request")
|
||||
resolver.opts.Logger.Info("Using", dnsClient.Net, "for making the request")
|
||||
|
||||
resp.DNS, resp.RTT, err = dnsClient.Exchange(msg, resolver.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 !resolver.opts.BadCookie {
|
||||
fmt.Printf(";; BADCOOKIE, retrying.\n\n")
|
||||
|
||||
msg.Extra = resp.DNS.Extra
|
||||
|
||||
resp.DNS, resp.RTT, err = dnsClient.Exchange(msg, resolver.opts.Request.Server)
|
||||
|
||||
if err != nil {
|
||||
return util.Response{}, fmt.Errorf("badcookie: DNS exchange: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
case "NOERR":
|
||||
break
|
||||
}
|
||||
|
||||
resolver.opts.Logger.Info("Request successful")
|
||||
|
||||
if resp.DNS.MsgHdr.Truncated && !resolver.opts.Truncate {
|
||||
|
|
|
@ -20,7 +20,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,
|
||||
|
|
|
@ -13,26 +13,28 @@ import (
|
|||
// Options is the grand structure for all query options.
|
||||
type Options struct {
|
||||
// The logger
|
||||
Logger *logawl.Logger
|
||||
Logger *logawl.Logger `json:"-"`
|
||||
// Host to verify TLS cert with
|
||||
TLSHost string `json:"tlsHost"`
|
||||
TLSHost string `json:"tlsHost" example:""`
|
||||
// EDNS Options
|
||||
EDNS
|
||||
// DNS request :)
|
||||
Request Request
|
||||
|
||||
// Verbosity levels, see [logawl.AllLevels]
|
||||
Verbosity int `json:"-"`
|
||||
Verbosity int `json:"-" example:"0"`
|
||||
// Display options
|
||||
Display Display
|
||||
// Ignore Truncation
|
||||
Truncate bool `json:"ignoreTruncate"`
|
||||
Truncate bool `json:"ignoreTruncate" example:"false"`
|
||||
// Ignore BADCOOKIE
|
||||
BadCookie bool `json:"ignoreBadCookie" example:"false"`
|
||||
// Print only the answer
|
||||
Short bool `json:"short"`
|
||||
Short bool `json:"short" example:"false"`
|
||||
// When Short is true, display where the query came from
|
||||
Identify bool `json:"identify"`
|
||||
Identify bool `json:"identify" example:"false"`
|
||||
// Perform a reverse DNS query when true
|
||||
Reverse bool `json:"reverse"`
|
||||
Reverse bool `json:"reverse" example:"false"`
|
||||
|
||||
HeaderFlags
|
||||
|
||||
|
@ -44,42 +46,43 @@ type Options struct {
|
|||
YAML bool `json:"-" xml:"-" yaml:"-"`
|
||||
|
||||
// Use TCP instead of UDP to make the query
|
||||
TCP bool `json:"tcp"`
|
||||
TCP bool `json:"tcp" example:"false"`
|
||||
// Use DNS-over-TLS to make the query
|
||||
TLS bool `json:"dns_over_tls"`
|
||||
TLS bool `json:"dnsOverTLS" example:"false"`
|
||||
// When using TLS, ignore certificates
|
||||
TLSNoVerify bool `json:"tlsNoVerify"`
|
||||
TLSNoVerify bool `json:"tlsNoVerify" example:"false"`
|
||||
// Use DNS-over-HTTPS to make the query
|
||||
HTTPS bool `json:"dns_over_https"`
|
||||
HTTPS bool `json:"dnsOverHTTPS" example:"false"`
|
||||
// Use DNS-over-QUIC to make the query
|
||||
QUIC bool `json:"dns_over_quic"`
|
||||
//nolint:tagliatelle // QUIC is an acronym
|
||||
QUIC bool `json:"dnsOverQUIC" example:"false"`
|
||||
// Use DNSCrypt to make the query
|
||||
DNSCrypt bool `json:"dnscrpyt"`
|
||||
DNSCrypt bool `json:"dnscrypt" example:"false"`
|
||||
|
||||
// Force IPv4 only
|
||||
IPv4 bool `json:"force_IPv4"`
|
||||
IPv4 bool `json:"forceIPv4" example:"false"`
|
||||
// Force IPv6 only
|
||||
IPv6 bool `json:"force_IPv6"`
|
||||
IPv6 bool `json:"forceIPv6" example:"false"`
|
||||
}
|
||||
|
||||
// HeaderFlags are the flags that are in DNS headers.
|
||||
type HeaderFlags struct {
|
||||
// Authoritative Answer DNS query flag
|
||||
AA bool `json:"authoritative,"`
|
||||
AA bool `json:"authoritative" example:"false"`
|
||||
// Authenticated Data DNS query flag
|
||||
AD bool `json:"authenticatedData,"`
|
||||
AD bool `json:"authenticatedData" example:"false"`
|
||||
// Checking Disabled DNS query flag
|
||||
CD bool `json:"checkingDisabled,"`
|
||||
CD bool `json:"checkingDisabled" example:"false"`
|
||||
// QueRy DNS query flag
|
||||
QR bool `json:"query"`
|
||||
QR bool `json:"query" example:"false"`
|
||||
// Recursion Desired DNS query flag
|
||||
RD bool `json:"recursionDesired"`
|
||||
RD bool `json:"recursionDesired" example:"true"`
|
||||
// Recursion Available DNS query flag
|
||||
RA bool `json:"recursionAvailable"`
|
||||
RA bool `json:"recursionAvailable" example:"false"`
|
||||
// TrunCated DNS query flag
|
||||
TC bool `json:"truncated"`
|
||||
TC bool `json:"truncated" example:"false"`
|
||||
// Zero DNS query flag
|
||||
Z bool `json:"zero"`
|
||||
Z bool `json:"zero" example:"false"`
|
||||
}
|
||||
|
||||
// Display contains toggles for what to (and not to) display.
|
||||
|
@ -87,32 +90,32 @@ type Display struct {
|
|||
/* Section displaying */
|
||||
|
||||
// Comments?
|
||||
Comments bool `json:"comments"`
|
||||
Comments bool `json:"comments" example:"true"`
|
||||
// QUESTION SECTION
|
||||
Question bool `json:"question"`
|
||||
Question bool `json:"question" example:"true"`
|
||||
// OPT PSEUDOSECTION
|
||||
Opt bool `json:"opt"`
|
||||
Opt bool `json:"opt" example:"true"`
|
||||
// ANSWER SECTION
|
||||
Answer bool `json:"answer"`
|
||||
Answer bool `json:"answer" example:"true"`
|
||||
// AUTHORITY SECTION
|
||||
Authority bool `json:"authority"`
|
||||
Authority bool `json:"authority" example:"true"`
|
||||
// ADDITIONAL SECTION
|
||||
Additional bool `json:"additional"`
|
||||
Additional bool `json:"additional" example:"true"`
|
||||
// Query time, message size, etc.
|
||||
Statistics bool `json:"statistics"`
|
||||
Statistics bool `json:"statistics" example:"true"`
|
||||
// Display TTL in response
|
||||
TTL bool `json:"ttl"`
|
||||
TTL bool `json:"ttl" example:"true"`
|
||||
|
||||
/* Answer formatting */
|
||||
|
||||
// Display Class in response
|
||||
ShowClass bool `json:"showClass"`
|
||||
ShowClass bool `json:"showClass" example:"true"`
|
||||
// Display query before it is sent
|
||||
ShowQuery bool `json:"showQuery"`
|
||||
ShowQuery bool `json:"showQuery" example:"false"`
|
||||
// Display TTL as human-readable
|
||||
HumanTTL bool `json:"HumanTTL"`
|
||||
HumanTTL bool `json:"humanTTL" example:"false"`
|
||||
// Translate Punycode back to Unicode
|
||||
UcodeTranslate bool `json:"unicode"`
|
||||
UcodeTranslate bool `json:"unicode" example:"true"`
|
||||
}
|
||||
|
||||
// EDNS contains toggles for various EDNS options.
|
||||
|
@ -120,25 +123,25 @@ type EDNS struct {
|
|||
// Subnet to originate query from.
|
||||
Subnet dns.EDNS0_SUBNET `json:"subnet"`
|
||||
// Must Be Zero flag
|
||||
ZFlag uint16 `json:"zflag"`
|
||||
ZFlag uint16 `json:"zflag" example:"0"`
|
||||
// UDP buffer size
|
||||
BufSize uint16 `json:"bufSize"`
|
||||
BufSize uint16 `json:"bufSize" example:"1232"`
|
||||
// Enable/Disable EDNS entirely
|
||||
EnableEDNS bool `json:"edns"`
|
||||
EnableEDNS bool `json:"edns" example:"false"`
|
||||
// Sending EDNS cookie
|
||||
Cookie bool `json:"cookie"`
|
||||
Cookie bool `json:"cookie" example:"true"`
|
||||
// Enabling DNSSEC
|
||||
DNSSEC bool `json:"dnssec"`
|
||||
DNSSEC bool `json:"dnssec" example:"false"`
|
||||
// Sending EDNS Expire
|
||||
Expire bool `json:"expire"`
|
||||
Expire bool `json:"expire" example:"false"`
|
||||
// Sending EDNS TCP keepopen
|
||||
KeepOpen bool `json:"keepOpen"`
|
||||
KeepOpen bool `json:"keepOpen" example:"false"`
|
||||
// Sending EDNS NSID
|
||||
Nsid bool `json:"nsid"`
|
||||
Nsid bool `json:"nsid" example:"false"`
|
||||
// Send EDNS Padding
|
||||
Padding bool `json:"padding"`
|
||||
Padding bool `json:"padding" example:"false"`
|
||||
// Set EDNS version (default: 0)
|
||||
Version uint8 `json:"version"`
|
||||
Version uint8 `json:"version" example:"0"`
|
||||
}
|
||||
|
||||
// ParseSubnet takes a subnet argument and makes it into one that the DNS library
|
||||
|
|
10
template.mk
10
template.mk
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Template for the BSD/GNU makefiles
|
||||
|
||||
HASH ?= `git describe --always --dirty --broken | sed 's/\([^-]*-g\)/r\1/;s/-/./g' || echo "UNKNOWN"`
|
||||
HASH ?= `git describe --always --dirty --broken | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g' || echo "UNKNOWN"`
|
||||
|
||||
SOURCES ?= $(shell find . -name "*.go" -type f ! -name '*_test*')
|
||||
TEST_SOURCES ?= $(shell find . -name "*_test.go" -type f)
|
||||
|
@ -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
|
||||
|
||||
|
@ -90,4 +84,4 @@ clean:
|
|||
.PHONY: help
|
||||
help:
|
||||
@echo "Usage: "
|
||||
@sed -n 's/^##//p' $(MAKEFILE_LIST) | column -t -s ':' | sed -e 's/^/ /'
|
||||
@sed -n 's/^##//p' $(MAKEFILE_LIST) | column -t -s ':' | sed -e 's/^/ /'
|
||||
|
|
Loading…
Reference in a new issue