Compare commits

...

27 commits

Author SHA1 Message Date
grumbulon a68821fc2a test2 2022-07-01 03:08:47 -04:00
grumbulon fb1c40d6d9 test 2022-07-01 03:07:46 -04:00
grumbulon d845808a3c I hate vscode 2022-06-29 21:07:57 -04:00
grumbulon a62f0b0759 upstream 2022-06-29 21:05:49 -04:00
Sam Therapy 5035898c13
Add a LICENSE
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-06-29 23:12:30 +02:00
grumbulon 98a14b1bf8 Merge logawl package into master (#10)
This PR is to bring in the new logging package for awl, I wanted to do some refinements before I opened this to upstream

logawl works in the following ways

1. It prints logs directly to std.err
1. The default log level is Info (this can be changed multiple ways)
1. It supports four log levels Error, Fatal, Info, Debug
1. It differs from the syslog package in the stdlib wherin it default to std.err you do not _need_ to define an out file (syslog for example)
1. I added a "debug" flag so now we can go through and define verbose logging through the app
5.5 I made it so we can call `Logger.debug("message")` anywhere in the query file but unless the debug flag is set to true it will not print a message (it is working as intended finally).

Co-authored-by: grumbulon <grumbulon@dismail.de>
Reviewed-on: sam/awl#10
Co-authored-by: grumbulon <grumbulon@grumbulon.xyz>
Co-committed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-06-29 22:57:03 +00:00
grumbulon 4353aa9559 Accidentally left something I was testing in..oops 2022-06-29 09:25:06 -04:00
grumbulon f7e5a7adee Added fatal logging, made doc for package better, and some minor changes 2022-06-29 09:22:28 -04:00
grumbulon be3b81029e Merge branch 'master' into master 2022-06-29 13:20:45 +00:00
Renovate Bot 5fab5a08a7 Update module github.com/stretchr/testify to v1.8.0 2022-06-29 06:00:21 -05:00
grumbulon dfea8060dd Merge branch 'master' into master 2022-06-28 18:20:24 +00:00
grumbulon 6d30a5ad9b Logging works bretty good now 2022-06-28 14:11:49 -04:00
grumbulon a36f1b8685 Added debuge flag, and added init for logawl 2022-06-28 12:12:52 -04:00
Renovate Bot d4b8d1469f Update module github.com/urfave/cli/v2 to v2.10.3 2022-06-28 11:48:23 -04:00
Renovate Bot f50b793931 Update module github.com/stretchr/testify to v1.7.5 2022-06-28 11:48:23 -04:00
Renovate Bot 4754097a40 Update module github.com/urfave/cli/v2 to v2.10.3 2022-06-27 21:00:34 -05:00
Renovate Bot 68c3345e9b Update module github.com/stretchr/testify to v1.7.5 2022-06-27 20:00:21 -05:00
grumbulon 68e6e54741 Accidentally reverted to old commit with dns.go 2022-06-26 14:16:38 -04:00
grumbulon 8b1a5f9147 Merge remote-tracking branch 'upstream/master'
Merging upstream into fork
2022-06-26 14:10:35 -04:00
grumbulon 6da6a55f6e Logging refinements 2022-06-26 14:01:13 -04:00
grumbulon 8c61f9f409 logging (#1)
Promoting branch to master

Co-authored-by: grumbulon <grumbulon@dismail.de>
Reviewed-on: #1
2022-06-26 04:07:58 +00:00
grumbulon 182ec20469 Revert "hehe off-by-one"
This reverts commit db78235ecd.

Reverting to old commit because I fucked up
2022-06-25 13:46:38 -04:00
Renovate Bot c0c5eb4a06 Update golang.org/x/net digest to 1bab6f3 2022-06-24 18:00:22 -05:00
Sam Therapy db78235ecd
hehe off-by-one
Signed-off-by: Sam Therapy <sam@samtherapy.net>
2022-06-23 23:18:54 +02:00
Sam Therapy bf06f7a3aa
I am still somehow getting paid to do this 2022-06-23 23:12:48 +02:00
Renovate Bot 027514b4cc Update golang.org/x/net digest to 263ec57 2022-06-23 07:29:27 +00:00
grumbulon 589b13320a Cannot defined things twice in same package (#5)
Co-authored-by: grumbulon <grumbulon@grumbulon.xyz>
Co-committed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-06-23 07:29:06 +00:00
20 changed files with 911 additions and 634 deletions

8
.drone.yml Normal file
View file

@ -0,0 +1,8 @@
kind: pipeline
type: docker
name: default
steps:
- name: test
image: golang
commands:
- go test ./...

11
LICENCE Normal file
View file

@ -0,0 +1,11 @@
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.

View file

@ -30,5 +30,6 @@ 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
- Documentation, documentation, documentation
- Make the code less spaghetti (partially completed)
- Feature parity with drill
- Making a drop-in replacement for drill?

2
awl.go
View file

@ -1,3 +1,5 @@
// SPDX-License-Identifier: BSD-3-Clause
package main
import (

385
cli.go
View file

@ -1,185 +1,200 @@
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
}
// 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
}

42
cli_test.go Normal file
View file

@ -0,0 +1,42 @@
// 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)
}
}

14
go.mod
View file

@ -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.2
golang.org/x/net v0.0.0-20220621193019-9d032be2e588
github.com/urfave/cli/v2 v2.10.3
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
)
require (
@ -18,19 +18,19 @@ require (
require (
github.com/cheekybits/genny v1.0.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // 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/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.4 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/testify v1.7.4
github.com/stretchr/testify v1.8.0
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // 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

31
go.sum
View file

@ -25,8 +25,9 @@ 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=
@ -71,9 +72,11 @@ 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=
@ -101,8 +104,9 @@ 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=
@ -146,14 +150,13 @@ 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.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
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/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
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/urfave/cli/v2 v2.10.3 h1:oi571Fxz5aHugfBAJd5nkwSk3fzATXtMlpxdLylSCMo=
github.com/urfave/cli/v2 v2.10.3/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=
@ -169,8 +172,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-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
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/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,8 +199,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
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-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-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/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=
@ -231,8 +234,9 @@ 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-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/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/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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -285,6 +289,7 @@ 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=

30
logawl/doc.go Normal file
View file

@ -0,0 +1,30 @@
/*
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

30
logawl/docs.go Normal file
View file

@ -0,0 +1,30 @@
/*
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

74
logawl/logawl.go Normal file
View file

@ -0,0 +1,74 @@
// 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 Normal file
View file

@ -0,0 +1,132 @@
// 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
View file

@ -1,172 +1,186 @@
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
}
// 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
}

View file

@ -1,54 +1,56 @@
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
}
// 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
}

View file

@ -1,58 +1,63 @@
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
}
// 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
}

View file

@ -1,2 +1,2 @@
// Package for the special query types
package query
// Package for the special query types
package query

View file

@ -1,89 +0,0 @@
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
}

View file

@ -1,2 +1,2 @@
// Helper functions
package util
// Helper functions
package util

View file

@ -1,3 +1,5 @@
// SPDX-License-Identifier: BSD-3-Clause
package util
import (

View file

@ -1,50 +1,43 @@
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)
}
// 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)
}