Compare commits
1 commit
master
...
renovate/g
Author | SHA1 | Date | |
---|---|---|---|
b246249dea |
20 changed files with 647 additions and 911 deletions
|
@ -1,8 +0,0 @@
|
|||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
steps:
|
||||
- name: test
|
||||
image: golang
|
||||
commands:
|
||||
- go test ./...
|
11
LICENCE
11
LICENCE
|
@ -1,11 +0,0 @@
|
|||
Copyright 2022 Sam Therapy, Gregward Bulon
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -30,6 +30,5 @@ lifting.
|
|||
- Make the CLI less abysmal (migrate to [cobra](https://github.com/spf13/cobra)?
|
||||
or just use stdlib's flags)
|
||||
- Optimize everything
|
||||
- Make the code less spaghetti (partially completed)
|
||||
- Feature parity with drill
|
||||
- Making a drop-in replacement for drill?
|
||||
- Make the code less spaghetti
|
||||
- Documentation, documentation, documentation
|
2
awl.go
2
awl.go
|
@ -1,5 +1,3 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
|
385
cli.go
385
cli.go
|
@ -1,200 +1,185 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"git.froth.zone/sam/awl/util"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// Do all the magic CLI crap
|
||||
func prepareCLI() *cli.App {
|
||||
// Custom version string
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
fmt.Printf("%s version %s, built with %s\n", c.App.Name, c.App.Version, runtime.Version())
|
||||
}
|
||||
|
||||
cli.VersionFlag = &cli.BoolFlag{
|
||||
Name: "v",
|
||||
Usage: "show version and exit",
|
||||
}
|
||||
|
||||
cli.HelpFlag = &cli.BoolFlag{
|
||||
Name: "h",
|
||||
Usage: "show this help and exit",
|
||||
}
|
||||
|
||||
// Hack to get rid of the annoying default on the CLI
|
||||
oldFlagStringer := cli.FlagStringer
|
||||
cli.FlagStringer = func(f cli.Flag) string {
|
||||
return strings.TrimSuffix(oldFlagStringer(f), " (default: false)")
|
||||
}
|
||||
|
||||
cli.AppHelpTemplate = `{{.Name}} - {{.Usage}}
|
||||
|
||||
Usage: {{.HelpName}} name [@server] [record]
|
||||
<name> can be a name or an IP address
|
||||
<record> defaults to A
|
||||
|
||||
arguments can be in any order
|
||||
{{if .VisibleFlags}}
|
||||
Options:
|
||||
{{range .VisibleFlags}}{{.}}
|
||||
{{end}}{{end}}`
|
||||
app := &cli.App{
|
||||
Name: "awl",
|
||||
Usage: "drill, writ small",
|
||||
Version: "v0.2.1",
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "port",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "`<port>` to make DNS query",
|
||||
DefaultText: "53 over plain TCP/UDP, 853 over TLS or QUIC",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "4",
|
||||
Usage: "force IPv4",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "6",
|
||||
Usage: "force IPv6",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "dnssec",
|
||||
Aliases: []string{"D"},
|
||||
Usage: "enable DNSSEC",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "json",
|
||||
Aliases: []string{"j"},
|
||||
Usage: "return the result(s) as JSON",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "short",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "print just the results, equivalent to dig +short",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tcp",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "use TCP (default: use UDP)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tls",
|
||||
Aliases: []string{"T"},
|
||||
Usage: "use DNS-over-TLS",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "https",
|
||||
Aliases: []string{"H"},
|
||||
Usage: "use DNS-over-HTTPS",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "quic",
|
||||
Aliases: []string{"Q"},
|
||||
Usage: "use DNS-over-QUIC",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-truncate",
|
||||
Usage: "ignore truncation if a UDP request truncates (default: retry with TCP)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "aa",
|
||||
Usage: "set AA (Authoratative Answer) flag (default: not set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tc",
|
||||
Usage: "set tc (TrunCated) flag (default: not set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "z",
|
||||
Usage: "set Z (Zero) flag (default: not set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "cd",
|
||||
Usage: "set CD (Checking Disabled) flag (default: not set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-rd",
|
||||
Usage: "UNset RD (Recursion Desired) flag (default: set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-ra",
|
||||
Usage: "UNset RA (Recursion Available) flag (default: set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "reverse",
|
||||
Aliases: []string{"x"},
|
||||
Usage: "do a reverse lookup",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "debug",
|
||||
Usage: "enable debug logging",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
Action: doQuery,
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
// Parse the wildcard arguments, drill style
|
||||
func parseArgs(args []string) (util.Answers, error) {
|
||||
var (
|
||||
resp util.Response
|
||||
err error
|
||||
)
|
||||
for _, arg := range args {
|
||||
r, ok := dns.StringToType[strings.ToUpper(arg)]
|
||||
switch {
|
||||
// If it starts with @, it's a DNS server
|
||||
case strings.HasPrefix(arg, "@"):
|
||||
resp.Answers.Server = strings.Split(arg, "@")[1]
|
||||
case strings.Contains(arg, "."):
|
||||
resp.Answers.Name, err = idna.ToUnicode(arg)
|
||||
if err != nil {
|
||||
return util.Answers{}, err
|
||||
}
|
||||
case ok:
|
||||
// If it's a DNS request, it's a DNS request (obviously)
|
||||
resp.Answers.Request = r
|
||||
default:
|
||||
//else, assume it's a name
|
||||
resp.Answers.Name, err = idna.ToUnicode(arg)
|
||||
if err != nil {
|
||||
return util.Answers{}, err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing was set, set a default
|
||||
if resp.Answers.Name == "" {
|
||||
resp.Answers.Name = "."
|
||||
if resp.Answers.Request == 0 {
|
||||
resp.Answers.Request = dns.StringToType["NS"]
|
||||
}
|
||||
} else {
|
||||
if resp.Answers.Request == 0 {
|
||||
resp.Answers.Request = dns.StringToType["A"]
|
||||
}
|
||||
}
|
||||
if resp.Answers.Server == "" {
|
||||
resolv, err := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
if err != nil { // Query Google by default, needed for Windows since the DNS library doesn't support Windows
|
||||
// TODO: Actually find where windows stuffs its dns resolvers
|
||||
resp.Answers.Server = "8.8.4.4"
|
||||
} else {
|
||||
resp.Answers.Server = resolv.Servers[rand.Intn(len(resolv.Servers))]
|
||||
}
|
||||
}
|
||||
|
||||
return util.Answers{Server: resp.Answers.Server, Request: resp.Answers.Request, Name: resp.Answers.Name}, nil
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"git.froth.zone/sam/awl/util"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// Do all the magic CLI crap
|
||||
func prepareCLI() *cli.App {
|
||||
// Custom version string
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
fmt.Printf("%s version %s, built with %s\n", c.App.Name, c.App.Version, runtime.Version())
|
||||
}
|
||||
|
||||
cli.VersionFlag = &cli.BoolFlag{
|
||||
Name: "v",
|
||||
Usage: "show version and exit",
|
||||
}
|
||||
|
||||
cli.HelpFlag = &cli.BoolFlag{
|
||||
Name: "h",
|
||||
Usage: "show this help and exit",
|
||||
}
|
||||
|
||||
// Hack to get rid of the annoying default on the CLI
|
||||
oldFlagStringer := cli.FlagStringer
|
||||
cli.FlagStringer = func(f cli.Flag) string {
|
||||
return strings.TrimSuffix(oldFlagStringer(f), " (default: false)")
|
||||
}
|
||||
|
||||
cli.AppHelpTemplate = `{{.Name}} - {{.Usage}}
|
||||
|
||||
Usage: {{.HelpName}} name [@server] [type]
|
||||
<name> can be a name or an IP address
|
||||
<type> defaults to A
|
||||
|
||||
arguments can be in any order
|
||||
{{if .VisibleFlags}}
|
||||
Options:
|
||||
{{range .VisibleFlags}}{{.}}
|
||||
{{end}}{{end}}`
|
||||
app := &cli.App{
|
||||
Name: "awl",
|
||||
Usage: "drill, writ small",
|
||||
Version: "v0.2.0",
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "port",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "`port` to make DNS query",
|
||||
DefaultText: "53 over plain TCP/UDP, 853 over TLS or QUIC, and 443 over HTTPS",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "4",
|
||||
Usage: "force IPv4",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "6",
|
||||
Usage: "force IPv6",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "dnssec",
|
||||
Aliases: []string{"D"},
|
||||
Usage: "enable DNSSEC",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "json",
|
||||
Aliases: []string{"j"},
|
||||
Usage: "return the result(s) as JSON",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "short",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "print just the results, equivalent to dig +short",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tcp",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "use TCP (default: use UDP)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tls",
|
||||
Aliases: []string{"T"},
|
||||
Usage: "use DNS-over-TLS",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "https",
|
||||
Aliases: []string{"H"},
|
||||
Usage: "use DNS-over-HTTPS",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "quic",
|
||||
Aliases: []string{"Q"},
|
||||
Usage: "use DNS-over-QUIC",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-truncate",
|
||||
Usage: "ignore truncation if a UDP request truncates (default: retry with TCP)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "z",
|
||||
Usage: "set Z (zero) flag (default: not set) [THIS DOESN'T DO ANYTHING]",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "cd",
|
||||
Usage: "set CD (CheckingDisabled) flag (default: not set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-rd",
|
||||
Usage: "UNset RD (RecursionDesired) flag (default: set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-ra",
|
||||
Usage: "UNset RA (RecursionAvailable) flag (default: set)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "reverse",
|
||||
Aliases: []string{"x"},
|
||||
Usage: "do a reverse lookup",
|
||||
},
|
||||
},
|
||||
Action: doQuery,
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
// Parse the wildcard arguments, drill style
|
||||
func parseArgs(args []string) (util.Answers, error) {
|
||||
var (
|
||||
resp util.Response
|
||||
)
|
||||
for _, arg := range args {
|
||||
// If it starts with @, it's a DNS server
|
||||
if strings.HasPrefix(arg, "@") {
|
||||
resp.Answers.Server = strings.Split(arg, "@")[1]
|
||||
continue
|
||||
}
|
||||
// If there's a dot, it's a name
|
||||
if strings.Contains(arg, ".") {
|
||||
resp.Answers.Name, _ = idna.ToUnicode(arg)
|
||||
continue
|
||||
}
|
||||
// If it's a request, it's a request (duh)
|
||||
if r, ok := dns.StringToType[strings.ToUpper(arg)]; ok {
|
||||
resp.Answers.Request = r
|
||||
continue
|
||||
}
|
||||
|
||||
//else, assume it's a name
|
||||
var err error
|
||||
resp.Answers.Name, err = idna.ToUnicode(arg)
|
||||
if err != nil {
|
||||
return util.Answers{}, err
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing was set, set a default
|
||||
if resp.Answers.Name == "" {
|
||||
resp.Answers.Name = "."
|
||||
if resp.Answers.Request == 0 {
|
||||
resp.Answers.Request = dns.StringToType["NS"]
|
||||
}
|
||||
} else {
|
||||
if resp.Answers.Request == 0 {
|
||||
resp.Answers.Request = dns.StringToType["A"]
|
||||
}
|
||||
}
|
||||
if resp.Answers.Server == "" {
|
||||
resolv, err := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
if err != nil { // Query Google by default, needed for Windows since the DNS library doesn't support Windows
|
||||
// TODO: Actually find where windows stuffs its dns resolvers
|
||||
resp.Answers.Server = "8.8.4.4"
|
||||
} else {
|
||||
resp.Answers.Server = resolv.Servers[0]
|
||||
}
|
||||
}
|
||||
|
||||
return util.Answers{Server: resp.Answers.Server, Request: resp.Answers.Request, Name: resp.Answers.Name}, nil
|
||||
}
|
||||
|
|
42
cli_test.go
42
cli_test.go
|
@ -1,42 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.froth.zone/sam/awl/util"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestApp(t *testing.T) {
|
||||
app := prepareCLI()
|
||||
// What more can even be done lmao
|
||||
require.NotNil(t, app)
|
||||
}
|
||||
|
||||
func TestArgParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
in []string
|
||||
want util.Answers
|
||||
}{
|
||||
{
|
||||
[]string{"@::1", "localhost", "AAAA"},
|
||||
util.Answers{Server: "::1", Request: dns.TypeAAAA, Name: "localhost"},
|
||||
},
|
||||
{
|
||||
[]string{"@1.0.0.1", "google.com"},
|
||||
util.Answers{Server: "1.0.0.1", Request: dns.TypeA, Name: "google.com"},
|
||||
},
|
||||
{
|
||||
[]string{"@8.8.4.4"},
|
||||
util.Answers{Server: "8.8.4.4", Request: dns.TypeNS, Name: "."},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
act, err := parseArgs(test.in)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, test.want, act)
|
||||
}
|
||||
}
|
15
go.mod
15
go.mod
|
@ -5,8 +5,8 @@ go 1.18
|
|||
require (
|
||||
github.com/lucas-clemente/quic-go v0.27.2
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/urfave/cli/v2 v2.10.3
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
||||
github.com/urfave/cli/v2 v2.10.2
|
||||
golang.org/x/net v0.0.0-20220622184535-263ec571b305
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -16,21 +16,22 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/c-robinson/iplib v1.0.3
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/stretchr/testify v1.7.4
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.11 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
|
|
43
go.sum
43
go.sum
|
@ -8,10 +8,13 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1
|
|||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
|
||||
github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
|
@ -25,9 +28,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
|||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
|
@ -72,11 +74,9 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0
|
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lucas-clemente/quic-go v0.27.2 h1:zsMwwniyybb8B/UDNXRSYee7WpQJVOcjQEGgpw2ikXs=
|
||||
github.com/lucas-clemente/quic-go v0.27.2/go.mod h1:vXgO/11FBSKM+js1NxoaQ/bPtVFYfB7uxhfHXyMhl1A=
|
||||
|
@ -104,9 +104,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
|||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
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=
|
||||
|
@ -119,6 +118,7 @@ github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
|
@ -150,19 +150,21 @@ github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
|
||||
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/urfave/cli/v2 v2.10.3 h1:oi571Fxz5aHugfBAJd5nkwSk3fzATXtMlpxdLylSCMo=
|
||||
github.com/urfave/cli/v2 v2.10.3/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
|
||||
github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y=
|
||||
github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
|
@ -172,8 +174,8 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -196,11 +198,15 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220621193019-9d032be2e588 h1:9ubFuySsnAJYGyJrZ3koiEv8FyqofCBdz3G9Mbf2YFc=
|
||||
golang.org/x/net v0.0.0-20220621193019-9d032be2e588/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220622184535-263ec571b305 h1:dAgbJ2SP4jD6XYfMNLVj0BF21jo2PjChrtGaAvF5M3I=
|
||||
golang.org/x/net v0.0.0-20220622184535-263ec571b305/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -234,10 +240,12 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8=
|
||||
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -289,7 +297,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
LogAwl is a package for custom logging needs
|
||||
|
||||
LogAwl extends the standard log library with support for log levels
|
||||
This is _different_ from the syslog package in the standard library because you do not define a file
|
||||
because awl is a cli utility it writes directly to std err.
|
||||
*/
|
||||
// Use the New() function to init logawl
|
||||
//
|
||||
// logger := logawl.New()
|
||||
//
|
||||
// You can call specific logging levels from your new logger using
|
||||
//
|
||||
// logger.Debug("Message to log")
|
||||
// logger.Fatal("Message to log")
|
||||
// logger.Info("Message to log")
|
||||
// logger.Error("Message to log")
|
||||
//
|
||||
// You may also set the log level on the fly with
|
||||
//
|
||||
// Logger.SetLevel(3)
|
||||
// This allows you to change the default level (Info) and prevent log messages from being posted at higher verbosity levels
|
||||
//for example if
|
||||
// Logger.SetLevel(3)
|
||||
// is not called and you call
|
||||
// Logger.Debug()
|
||||
// this runs through
|
||||
// IsLevel(level)
|
||||
// to verify if the debug log should be sent to std.Err or not based on the current expected log level
|
||||
package logawl
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
LogAwl is a package for custom logging needs
|
||||
|
||||
LogAwl extends the standard log library with support for log levels
|
||||
This is _different_ from the syslog package in the standard library because you do not define a file
|
||||
because awl is a cli utility it writes directly to std err.
|
||||
*/
|
||||
// Use the New() function to init logawl
|
||||
//
|
||||
// logger := logawl.New()
|
||||
//
|
||||
// You can call specific logging levels from your new logger using
|
||||
//
|
||||
// logger.Debug("Message to log")
|
||||
// logger.Fatal("Message to log")
|
||||
// logger.Info("Message to log")
|
||||
// logger.Error("Message to log")
|
||||
//
|
||||
// You may also set the log level on the fly with
|
||||
//
|
||||
// Logger.SetLevel(3)
|
||||
// This allows you to change the default level (Info) and prevent log messages from being posted at higher verbosity levels
|
||||
//for example if
|
||||
// Logger.SetLevel(3)
|
||||
// is not called and you call
|
||||
// Logger.Debug()
|
||||
// this runs through
|
||||
// IsLevel(level)
|
||||
// to verify if the debug log should be sent to std.Err or not based on the current expected log level
|
||||
package logawl
|
|
@ -1,74 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package logawl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Level int32
|
||||
type Logger struct {
|
||||
Mu sync.Mutex
|
||||
Level Level
|
||||
Prefix string
|
||||
Out io.Writer
|
||||
buf []byte
|
||||
isDiscard int32
|
||||
}
|
||||
|
||||
// Stores whatever input value is in mem address of l.level
|
||||
func (l *Logger) SetLevel(level Level) {
|
||||
atomic.StoreInt32((*int32)(&l.Level), int32(level))
|
||||
}
|
||||
|
||||
// Mostly nothing
|
||||
func (l *Logger) GetLevel() Level {
|
||||
return l.level()
|
||||
}
|
||||
|
||||
// Retrieves whatever was stored in mem address of l.level
|
||||
func (l *Logger) level() Level {
|
||||
return Level(atomic.LoadInt32((*int32)(&l.Level)))
|
||||
}
|
||||
|
||||
// Unmarshalls the int value of level for writing the header
|
||||
func (l *Logger) UnMarshalLevel(lv Level) (string, error) {
|
||||
switch lv {
|
||||
case 0:
|
||||
return "FATAL ", nil
|
||||
case 1:
|
||||
return "ERROR ", nil
|
||||
case 2:
|
||||
return "INFO ", nil
|
||||
case 3:
|
||||
return "DEBUG ", nil
|
||||
}
|
||||
return "", fmt.Errorf("Invalid log level choice")
|
||||
}
|
||||
|
||||
func (l *Logger) IsLevel(level Level) bool {
|
||||
return l.level() >= level
|
||||
}
|
||||
|
||||
var AllLevels = []Level{
|
||||
FatalLevel,
|
||||
ErrorLevel,
|
||||
InfoLevel,
|
||||
DebugLevel,
|
||||
}
|
||||
|
||||
const (
|
||||
// Fatal logs (will call exit(1))
|
||||
FatalLevel Level = iota
|
||||
|
||||
// Error logs
|
||||
ErrorLevel
|
||||
|
||||
// What is going on level
|
||||
InfoLevel
|
||||
// Verbose log level.
|
||||
DebugLevel
|
||||
)
|
132
logawl/logger.go
132
logawl/logger.go
|
@ -1,132 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package logawl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Calling New instantiates Logger
|
||||
//
|
||||
// Level can be changed to one of the other log levels (FatalLevel, ErrorLevel, InfoLevel, DebugLevel)
|
||||
func New() *Logger {
|
||||
return &Logger{
|
||||
Out: os.Stderr,
|
||||
Level: InfoLevel, //Default value is InfoLevel
|
||||
}
|
||||
}
|
||||
|
||||
// Takes any and prints it out to Logger -> Out (io.Writer (default is std.Err))
|
||||
func (l *Logger) Println(level Level, v ...any) {
|
||||
if atomic.LoadInt32(&l.isDiscard) != 0 {
|
||||
return
|
||||
}
|
||||
//If verbose is not set --debug etc print _nothing_
|
||||
if l.IsLevel(level) {
|
||||
switch level { //Goes through log levels and does stuff based on them (Fatal os.Exit...etc)
|
||||
case 0:
|
||||
l.Printer(0, fmt.Sprintln(v...)) //Fatal level
|
||||
os.Exit(1)
|
||||
case 1:
|
||||
l.Printer(1, fmt.Sprintln(v...)) //Error level
|
||||
os.Exit(2)
|
||||
case 2:
|
||||
l.Printer(2, fmt.Sprintln(v...)) //Info level
|
||||
case 3:
|
||||
l.Printer(3, fmt.Sprintln(v...)) //Debug level
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Formats the log header as such <LogLevel> YYYY/MM/DD HH:MM:SS (local time) <the message to log>
|
||||
func (l *Logger) formatHeader(buf *[]byte, t time.Time, line int, level Level) {
|
||||
if lvl, err := l.UnMarshalLevel(level); err == nil {
|
||||
// This is ugly but functional
|
||||
// maybe there can be an append func or something in the future
|
||||
*buf = append(*buf, lvl...)
|
||||
year, month, day := t.Date()
|
||||
*buf = append(*buf, '[')
|
||||
formatter(buf, year, 4)
|
||||
*buf = append(*buf, '/')
|
||||
formatter(buf, int(month), 2)
|
||||
*buf = append(*buf, '/')
|
||||
formatter(buf, day, 2)
|
||||
*buf = append(*buf, ' ')
|
||||
hour, min, sec := t.Clock()
|
||||
formatter(buf, hour, 2)
|
||||
*buf = append(*buf, ':')
|
||||
formatter(buf, min, 2)
|
||||
*buf = append(*buf, ':')
|
||||
formatter(buf, sec, 2)
|
||||
*buf = append(*buf, ']')
|
||||
*buf = append(*buf, ':')
|
||||
*buf = append(*buf, ' ')
|
||||
} else {
|
||||
fmt.Printf("Unable to unmarshal log level: %v", err)
|
||||
os.Exit(2) //Fucking kill him
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Printer prints the formatted message directly to stdErr
|
||||
func (l *Logger) Printer(level Level, s string) error {
|
||||
now := time.Now()
|
||||
var line int
|
||||
l.Mu.Lock()
|
||||
defer l.Mu.Unlock()
|
||||
|
||||
l.buf = l.buf[:0]
|
||||
l.formatHeader(&l.buf, now, line, level)
|
||||
l.buf = append(l.buf, s...)
|
||||
if len(s) == 0 || s[len(s)-1] != '\n' {
|
||||
l.buf = append(l.buf, '\n')
|
||||
}
|
||||
_, err := l.Out.Write(l.buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// Some line formatting stuff from Golang log stdlib file
|
||||
//
|
||||
// Please view https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/log/log.go;drc=41e1d9075e428c2fc32d966b3752a3029b620e2c;l=96
|
||||
//
|
||||
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
|
||||
func formatter(buf *[]byte, i int, wid int) {
|
||||
// Assemble decimal in reverse order.
|
||||
var b [20]byte
|
||||
bp := len(b) - 1
|
||||
for i >= 10 || wid > 1 {
|
||||
wid--
|
||||
q := i / 10
|
||||
b[bp] = byte('0' + i - q*10)
|
||||
bp--
|
||||
i = q
|
||||
}
|
||||
// i < 10
|
||||
b[bp] = byte('0' + i)
|
||||
*buf = append(*buf, b[bp:]...)
|
||||
}
|
||||
|
||||
// Call print directly with Debug level
|
||||
func (l *Logger) Debug(v ...any) {
|
||||
l.Println(DebugLevel, v...)
|
||||
}
|
||||
|
||||
// Call print directly with Info level
|
||||
func (l *Logger) Info(v ...any) {
|
||||
l.Println(InfoLevel, v...)
|
||||
}
|
||||
|
||||
// Call print directly with Error level
|
||||
func (l *Logger) Error(v ...any) {
|
||||
l.Println(ErrorLevel, v...)
|
||||
}
|
||||
|
||||
// Call print directly with Fatal level
|
||||
func (l *Logger) Fatal(v ...any) {
|
||||
l.Println(FatalLevel, v...)
|
||||
}
|
358
query.go
358
query.go
|
@ -1,186 +1,172 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.froth.zone/sam/awl/logawl"
|
||||
"git.froth.zone/sam/awl/query"
|
||||
"git.froth.zone/sam/awl/util"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func doQuery(c *cli.Context) error {
|
||||
var (
|
||||
err error
|
||||
resp util.Response
|
||||
isHTTPS bool
|
||||
Logger = logawl.New() //init logger
|
||||
)
|
||||
|
||||
resp.Answers, err = parseArgs(c.Args().Slice())
|
||||
if err != nil {
|
||||
Logger.Error("Unable to parse args")
|
||||
return err
|
||||
}
|
||||
port := c.Int("port")
|
||||
if c.Bool("debug") {
|
||||
Logger.SetLevel(3)
|
||||
}
|
||||
|
||||
Logger.Debug("Starting awl")
|
||||
// If port is not set, set it
|
||||
if port == 0 {
|
||||
if c.Bool("tls") || c.Bool("quic") {
|
||||
port = 853
|
||||
} else {
|
||||
port = 53
|
||||
}
|
||||
}
|
||||
|
||||
if c.Bool("https") || strings.HasPrefix(resp.Answers.Server, "https://") {
|
||||
// add https:// if it doesn't already exist
|
||||
if !strings.HasPrefix(resp.Answers.Server, "https://") {
|
||||
resp.Answers.Server = "https://" + resp.Answers.Server
|
||||
}
|
||||
isHTTPS = true
|
||||
} else {
|
||||
resp.Answers.Server = net.JoinHostPort(resp.Answers.Server, strconv.Itoa(port))
|
||||
}
|
||||
|
||||
// Process the IP/Phone number so a PTR/NAPTR can be done
|
||||
if c.Bool("reverse") {
|
||||
if dns.TypeToString[resp.Answers.Request] == "A" {
|
||||
resp.Answers.Request = dns.StringToType["PTR"]
|
||||
}
|
||||
resp.Answers.Name, err = util.ReverseDNS(resp.Answers.Name, dns.TypeToString[resp.Answers.Request])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// if the domain is not canonical, make it canonical
|
||||
if !strings.HasSuffix(resp.Answers.Name, ".") {
|
||||
resp.Answers.Name = fmt.Sprintf("%s.", resp.Answers.Name)
|
||||
}
|
||||
|
||||
msg := new(dns.Msg)
|
||||
|
||||
msg.SetQuestion(resp.Answers.Name, resp.Answers.Request)
|
||||
|
||||
// Make this authoritative (does this do anything?)
|
||||
if c.Bool("aa") {
|
||||
msg.Authoritative = true
|
||||
}
|
||||
// Set truncated flag (why)
|
||||
if c.Bool("tc") {
|
||||
msg.Truncated = true
|
||||
}
|
||||
// Set the zero flag if requested (does nothing)
|
||||
if c.Bool("z") {
|
||||
Logger.Debug("Setting message to zero")
|
||||
msg.Zero = true
|
||||
}
|
||||
// Disable DNSSEC validation
|
||||
if c.Bool("cd") {
|
||||
msg.CheckingDisabled = true
|
||||
}
|
||||
// Disable wanting recursion
|
||||
if c.Bool("no-rd") {
|
||||
msg.RecursionDesired = false
|
||||
}
|
||||
// Disable recursion being available (I don't think this does anything)
|
||||
if c.Bool("no-ra") {
|
||||
msg.RecursionAvailable = false
|
||||
}
|
||||
// Set DNSSEC if requested
|
||||
if c.Bool("dnssec") {
|
||||
Logger.Debug("Using DNSSEC")
|
||||
msg.SetEdns0(1232, true)
|
||||
}
|
||||
|
||||
var in *dns.Msg
|
||||
|
||||
// Make the DNS request
|
||||
if isHTTPS {
|
||||
in, resp.Answers.RTT, err = query.ResolveHTTPS(msg, resp.Answers.Server)
|
||||
} else if c.Bool("quic") {
|
||||
in, resp.Answers.RTT, err = query.ResolveQUIC(msg, resp.Answers.Server)
|
||||
} else {
|
||||
|
||||
d := new(dns.Client)
|
||||
|
||||
// Set TCP/UDP, depending on flags
|
||||
if c.Bool("tcp") || c.Bool("tls") {
|
||||
d.Net = "tcp"
|
||||
} else {
|
||||
d.Net = "udp"
|
||||
}
|
||||
|
||||
// Set IPv4 or IPv6, depending on flags
|
||||
switch {
|
||||
case c.Bool("4"):
|
||||
d.Net += "4"
|
||||
case c.Bool("6"):
|
||||
d.Net += "6"
|
||||
}
|
||||
|
||||
// Add TLS, if requested
|
||||
if c.Bool("tls") {
|
||||
d.Net += "-tls"
|
||||
}
|
||||
|
||||
in, resp.Answers.RTT, err = d.Exchange(msg, resp.Answers.Server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If UDP truncates, use TCP instead (unless truncation is to be ignored)
|
||||
if in.MsgHdr.Truncated && !c.Bool("no-truncate") {
|
||||
fmt.Printf(";; Truncated, retrying with TCP\n\n")
|
||||
d.Net = "tcp"
|
||||
switch {
|
||||
case c.Bool("4"):
|
||||
d.Net += "4"
|
||||
case c.Bool("6"):
|
||||
d.Net += "6"
|
||||
}
|
||||
in, resp.Answers.RTT, err = d.Exchange(msg, resp.Answers.Server)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Bool("json") {
|
||||
json, err := json.MarshalIndent(in, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(json))
|
||||
} else {
|
||||
if !c.Bool("short") {
|
||||
// Print everything
|
||||
fmt.Println(in)
|
||||
fmt.Println(";; Query time:", resp.Answers.RTT)
|
||||
fmt.Println(";; SERVER:", resp.Answers.Server)
|
||||
fmt.Println(";; WHEN:", time.Now().Format(time.RFC1123Z))
|
||||
fmt.Println(";; MSG SIZE rcvd:", in.Len())
|
||||
} else {
|
||||
// Print just the responses, nothing else
|
||||
for _, res := range in.Answer {
|
||||
temp := strings.Split(res.String(), "\t")
|
||||
fmt.Println(temp[len(temp)-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.froth.zone/sam/awl/query"
|
||||
"git.froth.zone/sam/awl/util"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func doQuery(c *cli.Context) error {
|
||||
var err error
|
||||
var resp util.Response
|
||||
var isHTTPS bool
|
||||
resp.Answers, err = parseArgs(c.Args().Slice())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
port := c.Int("port")
|
||||
|
||||
// If port is not set, set it
|
||||
if port == 0 {
|
||||
if c.Bool("tls") || c.Bool("quic") {
|
||||
port = 853
|
||||
} else {
|
||||
port = 53
|
||||
}
|
||||
}
|
||||
|
||||
if c.Bool("https") || strings.HasPrefix(resp.Answers.Server, "https://") {
|
||||
// add https:// if it doesn't already exist
|
||||
if !strings.HasPrefix(resp.Answers.Server, "https://") {
|
||||
resp.Answers.Server = "https://" + resp.Answers.Server
|
||||
}
|
||||
isHTTPS = true
|
||||
} else {
|
||||
resp.Answers.Server = net.JoinHostPort(resp.Answers.Server, strconv.Itoa(port))
|
||||
}
|
||||
|
||||
// Process the IP/Phone number so a PTR/NAPTR can be done
|
||||
if c.Bool("reverse") {
|
||||
if dns.TypeToString[resp.Answers.Request] == "A" {
|
||||
resp.Answers.Request = dns.StringToType["PTR"]
|
||||
}
|
||||
resp.Answers.Name, err = util.ReverseDNS(resp.Answers.Name, dns.TypeToString[resp.Answers.Request])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// if the domain is not canonical, make it canonical
|
||||
if !strings.HasSuffix(resp.Answers.Name, ".") {
|
||||
resp.Answers.Name = fmt.Sprintf("%s.", resp.Answers.Name)
|
||||
}
|
||||
|
||||
msg := new(dns.Msg)
|
||||
|
||||
msg.SetQuestion(resp.Answers.Name, resp.Answers.Request)
|
||||
|
||||
// Set the zero flag if requested (does nothing)
|
||||
if c.Bool("z") {
|
||||
msg.Zero = true
|
||||
}
|
||||
// Disable DNSSEC validation if enabled
|
||||
if c.Bool("cd") {
|
||||
msg.CheckingDisabled = true
|
||||
}
|
||||
|
||||
if c.Bool("no-rd") {
|
||||
msg.RecursionDesired = false
|
||||
}
|
||||
|
||||
if c.Bool("no-ra") {
|
||||
msg.RecursionAvailable = false
|
||||
}
|
||||
|
||||
// Set DNSSEC if requested
|
||||
if c.Bool("dnssec") {
|
||||
msg.SetEdns0(1232, true)
|
||||
}
|
||||
|
||||
var in *dns.Msg
|
||||
|
||||
// Make the DNS request
|
||||
if isHTTPS {
|
||||
in, resp.Answers.RTT, err = query.ResolveHTTPS(msg, resp.Answers.Server)
|
||||
} else if c.Bool("quic") {
|
||||
in, resp.Answers.RTT, err = query.ResolveQUIC(msg, resp.Answers.Server)
|
||||
} else {
|
||||
|
||||
d := new(dns.Client)
|
||||
|
||||
// Set TCP/UDP, depending on flags
|
||||
if c.Bool("tcp") {
|
||||
d.Net = "tcp"
|
||||
if c.Bool("4") {
|
||||
d.Net = "tcp4"
|
||||
}
|
||||
if c.Bool("6") {
|
||||
d.Net = "tcp6"
|
||||
}
|
||||
} else {
|
||||
d.Net = "udp"
|
||||
if c.Bool("4") {
|
||||
d.Net = "udp4"
|
||||
}
|
||||
if c.Bool("6") {
|
||||
d.Net = "udp6"
|
||||
}
|
||||
}
|
||||
|
||||
// This is apparently all it takes to enable DoT
|
||||
// TODO: Is it really?
|
||||
if c.Bool("tls") {
|
||||
d.Net = "tcp-tls"
|
||||
}
|
||||
|
||||
in, resp.Answers.RTT, err = d.Exchange(msg, resp.Answers.Server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If UDP truncates, use TCP instead
|
||||
if !c.Bool("no-truncate") {
|
||||
if in.MsgHdr.Truncated {
|
||||
fmt.Printf(";; Truncated, retrying with TCP\n\n")
|
||||
d.Net = "tcp"
|
||||
if c.Bool("4") {
|
||||
d.Net = "tcp4"
|
||||
}
|
||||
if c.Bool("6") {
|
||||
d.Net = "tcp6"
|
||||
}
|
||||
in, resp.Answers.RTT, err = d.Exchange(msg, resp.Answers.Server)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Bool("json") {
|
||||
json, err := json.MarshalIndent(in, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(json))
|
||||
} else {
|
||||
if !c.Bool("short") {
|
||||
// Print everything
|
||||
fmt.Println(in)
|
||||
fmt.Println(";; Query time:", resp.Answers.RTT)
|
||||
fmt.Println(";; SERVER:", resp.Answers.Server)
|
||||
fmt.Println(";; WHEN:", time.Now().Format(time.RFC1123))
|
||||
fmt.Println(";; MSG SIZE rcvd:", in.Len())
|
||||
} else {
|
||||
// Print just the responses, nothing else
|
||||
for _, res := range in.Answer {
|
||||
temp := strings.Split(res.String(), "\t")
|
||||
fmt.Println(temp[len(temp)-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
110
query/HTTPS.go
110
query/HTTPS.go
|
@ -1,56 +1,54 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package query
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Resolve a DNS-over-HTTPS query
|
||||
//
|
||||
// Currently only supports POST requests
|
||||
func ResolveHTTPS(msg *dns.Msg, server string) (*dns.Msg, time.Duration, error) {
|
||||
httpR := &http.Client{}
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// query := server + "?dns=" + base64.RawURLEncoding.EncodeToString(buf)
|
||||
req, err := http.NewRequest("POST", server, bytes.NewBuffer(buf))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("DoH: %s", err.Error())
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/dns-message")
|
||||
req.Header.Set("Accept", "application/dns-message")
|
||||
|
||||
now := time.Now()
|
||||
res, err := httpR.Do(req)
|
||||
rtt := time.Since(now)
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("DoH HTTP request error: %s", err.Error())
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, 0, fmt.Errorf("DoH server responded with HTTP %d", res.StatusCode)
|
||||
}
|
||||
|
||||
fullRes, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("DoH body read error: %s", err.Error())
|
||||
}
|
||||
response := dns.Msg{}
|
||||
err = response.Unpack(fullRes)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("DoH dns message unpack error: %s", err.Error())
|
||||
}
|
||||
|
||||
return &response, rtt, nil
|
||||
}
|
||||
package query
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Resolve a DNS-over-HTTPS query
|
||||
//
|
||||
// Currently only supports POST requests
|
||||
func ResolveHTTPS(msg *dns.Msg, server string) (*dns.Msg, time.Duration, error) {
|
||||
httpR := &http.Client{}
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// query := server + "?dns=" + base64.RawURLEncoding.EncodeToString(buf)
|
||||
req, err := http.NewRequest("POST", server, bytes.NewBuffer(buf))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("DoH: %s", err.Error())
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/dns-message")
|
||||
req.Header.Set("Accept", "application/dns-message")
|
||||
|
||||
now := time.Now()
|
||||
res, err := httpR.Do(req)
|
||||
rtt := time.Since(now)
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("DoH HTTP request error: %s", err.Error())
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, 0, fmt.Errorf("DoH server responded with HTTP %d", res.StatusCode)
|
||||
}
|
||||
|
||||
fullRes, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("DoH body read error: %s", err.Error())
|
||||
}
|
||||
response := dns.Msg{}
|
||||
err = response.Unpack(fullRes)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("DoH dns message unpack error: %s", err.Error())
|
||||
}
|
||||
|
||||
return &response, rtt, nil
|
||||
}
|
||||
|
|
121
query/QUIC.go
121
query/QUIC.go
|
@ -1,63 +1,58 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package query
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Resolve DNS over QUIC, the hip new standard (for privacy I think, IDK)
|
||||
func ResolveQUIC(msg *dns.Msg, server string) (*dns.Msg, time.Duration, error) {
|
||||
tls := &tls.Config{
|
||||
NextProtos: []string{"doq"},
|
||||
}
|
||||
connection, err := quic.DialAddr(server, tls, nil)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Compress request to over-the-wire
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
t := time.Now()
|
||||
stream, err := connection.OpenStream()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
_, err = stream.Write(buf)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
fullRes, err := io.ReadAll(stream)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
rtt := time.Since(t)
|
||||
|
||||
// Close with error: no error
|
||||
err = connection.CloseWithError(0, "")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
err = stream.Close()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
response := dns.Msg{}
|
||||
err = response.Unpack(fullRes)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return &response, rtt, nil
|
||||
}
|
||||
package query
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Resolve DNS over QUIC, the hip new standard (for privacy I think, IDK)
|
||||
func ResolveQUIC(msg *dns.Msg, server string) (*dns.Msg, time.Duration, error) {
|
||||
tls := &tls.Config{
|
||||
NextProtos: []string{"doq"},
|
||||
}
|
||||
connection, err := quic.DialAddr(server, tls, nil)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Close with error: no error
|
||||
defer connection.CloseWithError(0, "")
|
||||
|
||||
// Compress request to over-the-wire
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
t := time.Now()
|
||||
stream, err := connection.OpenStream()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
_, err = stream.Write(buf)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
fullRes, err := io.ReadAll(stream)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
rtt := time.Since(t)
|
||||
|
||||
err = stream.Close()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
response := dns.Msg{}
|
||||
err = response.Unpack(fullRes)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return &response, rtt, nil
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// Package for the special query types
|
||||
package query
|
||||
// Package for the special query types
|
||||
package query
|
||||
|
|
89
util/dns.go
Normal file
89
util/dns.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/c-robinson/iplib"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
Answers Answers `json:"Response"` //
|
||||
}
|
||||
|
||||
// The Answers struct is the basic structure of a DNS request
|
||||
// to be returned to the user upon making a request
|
||||
type Answers struct {
|
||||
Server string `json:"Server"` // The server to make the DNS request from
|
||||
Request uint16 `json:"Request"` // The type of request
|
||||
Name string `json:"Name"` // The domain name to make a DNS request for
|
||||
RTT time.Duration `json:"RTT"` // When AWL was ran
|
||||
}
|
||||
|
||||
func ReverseDNS(dom string, q string) (string, error) {
|
||||
if q == "PTR" {
|
||||
if strings.Contains(dom, ".") {
|
||||
// It's an IPv4 address
|
||||
ip := net.ParseIP(dom)
|
||||
if ip != nil {
|
||||
return iplib.IP4ToARPA(ip), nil
|
||||
} else {
|
||||
return "", errors.New("error: Could not parse IPv4 address")
|
||||
}
|
||||
|
||||
} else if strings.Contains(dom, ":") {
|
||||
// It's an IPv6 address
|
||||
ip := net.ParseIP(dom)
|
||||
if ip != nil {
|
||||
return iplib.IP6ToARPA(ip), nil
|
||||
} else {
|
||||
return "", errors.New("error: Could not parse IPv6 address")
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", errors.New("error: -x flag given but no IP found")
|
||||
}
|
||||
|
||||
func ResolveHTTPS(msg *dns.Msg, server string) (*dns.Msg, error) {
|
||||
httpR := &http.Client{}
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := server + "?dns=" + base64.RawURLEncoding.EncodeToString(buf)
|
||||
req, err := http.NewRequest("GET", query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Accept", "application/dns-message")
|
||||
|
||||
res, err := httpR.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("bad HTTP Request: %d", res.StatusCode)
|
||||
}
|
||||
|
||||
fullRes, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := dns.Msg{}
|
||||
err = response.Unpack(fullRes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
// Helper functions
|
||||
package util
|
||||
// Helper functions
|
||||
package util
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,43 +1,50 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIPv4(t *testing.T) {
|
||||
act, err := ReverseDNS("8.8.4.4", "PTR")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, act, "4.4.8.8.in-addr.arpa.", "IPv4 reverse")
|
||||
}
|
||||
|
||||
func TestIPv6(t *testing.T) {
|
||||
act, err := ReverseDNS("2606:4700:4700::1111", "PTR")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, act, "1.1.1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.4.0.0.7.4.6.0.6.2.ip6.arpa.", "IPv6 reverse")
|
||||
}
|
||||
|
||||
func TestNAPTR(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{"1-800-555-1234", "4.3.2.1.5.5.5.0.0.8.1.e164.arpa."},
|
||||
{"+1 800555 1234", "4.3.2.1.5.5.5.0.0.8.1.e164.arpa."},
|
||||
{"+46766861004", "4.0.0.1.6.8.6.6.7.6.4.e164.arpa."},
|
||||
{"17705551212", "2.1.2.1.5.5.5.0.7.7.1.e164.arpa."},
|
||||
}
|
||||
for _, test := range tests {
|
||||
act, err := ReverseDNS(test.in, "NAPTR")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, test.want, act)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalid(t *testing.T) {
|
||||
_, err := ReverseDNS("AAAAA", "A")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIPv4(t *testing.T) {
|
||||
act, err := ReverseDNS("8.8.4.4", "PTR")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, act, "4.4.8.8.in-addr.arpa.", "IPv4 reverse")
|
||||
}
|
||||
|
||||
// WIP
|
||||
// func FuzzIPv4(f *testing.F) {
|
||||
// f.Add("1.1.1.1", "1.1.1.1.in-addr.arpa")
|
||||
// f.Fuzz(func(t *testing.T, a string, b string) {
|
||||
// _, err := ReverseDNS(a, b)
|
||||
// assert.Nil(t, err)
|
||||
// })
|
||||
// }
|
||||
|
||||
func TestIPv6(t *testing.T) {
|
||||
act, err := ReverseDNS("2606:4700:4700::1111", "PTR")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, act, "1.1.1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.4.0.0.7.4.6.0.6.2.ip6.arpa.", "IPv6 reverse")
|
||||
}
|
||||
|
||||
func TestNAPTR(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{"1-800-555-1234", "4.3.2.1.5.5.5.0.0.8.1.e164.arpa."},
|
||||
{"+1 800555 1234", "4.3.2.1.5.5.5.0.0.8.1.e164.arpa."},
|
||||
{"18005551234", "4.3.2.1.5.5.5.0.0.8.1.e164.arpa."},
|
||||
{"+1-770-555-1212", "2.1.2.1.5.5.5.0.7.7.1.e164.arpa."},
|
||||
}
|
||||
for _, test := range tests {
|
||||
act, err := ReverseDNS(test.in, "NAPTR")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, test.want, act)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalid(t *testing.T) {
|
||||
_, err := ReverseDNS("AAAAA", "A")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue